unexported struct best practice? (golint complains) - go

I have the following package :
package mypkg
type (
// mystruct ...
mystruct struct {
S string
}
)
// New ..
func New() *mystruct {
return &mystruct{S: "test"}
}
I use it this way:
package main
import (
"fmt"
"test/mypkg"
)
func main() {
x := mypkg.New()
fmt.Println(x.S)
// this fails intended
y := mypkg.mystruct{S: "andre"}
fmt.Println(y.S)
}
Why is golint complaining about my unexported struct? My intension is to prevent calling the struct creation outside the constructor call.
Is there another way to prevent instantiating without the New call?

You x := mypkg.New() in main.main() even can't have any type. It should not even compile. It's unusable. Seems to me more meaningful would be something like
package mypkg
type (
// mystruct ...
mystruct struct {
S string
}
)
type HaveS interface{ //which you can use but can't instantiate
GetS() string
}
func (strct *mystruct ) GetS() string {return strct.S}
// New ..
func New() HaveS {
return &mystruct{S: "test"}
}
then in main
var x mypkg.HaveS
x = mypkg.New()
fmt.Println(x.GetS())

Related

Property name of a structure to string

I would like to know if it is possible to get the name of a property from a structure and convert it to string.
For example in the following code:
package main
import "fmt"
type StructA struct {
ValueAA string
ValueAB string
}
type StructB struct {
ValueBA string
ValueBB string
RefStructA StructA
}
func main() {
//pass any attribute of any structure
fmt.Println(castProperty(StructB.RefStructA.ValueAA))
//print the name passed but in string. Do not print the value
//expected output: "StructB.RefStructA.ValueAA"
}
func castProperty(value interface{}) string {
//some code
}
Is it possible to write a function that allows obtaining the name of the property of a structure and converted to a string? property value is not required.
That's called Reflection. I let you read the page, it lets you do what you want.
First, read the The first law of reflection: https://go.dev/blog/laws-of-reflection
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
fmt.Println("type:", reflect.TypeOf(x))
}
https://play.golang.org/p/OuGgD1TlSMO
I am not sure exactly how do you want to give input to your function but here is an example that may help you
package main
import (
"log"
"reflect"
)
func main() {
getPropertyName(B{})
}
type A struct {
field1 string
}
type B struct {
field A
}
func getPropertyName(b interface{}) {
parentType := reflect.TypeOf(b)
val := reflect.ValueOf(b)
for i := 0; i< val.Type().NumField(); i++ {
t := val.Type().Field(i)
ty := val.Type().Field(i).Type.Name()
log.Println(parentType.Name()+"."+ t.Name+"."+ty)
}
}
you could do something like this :
package main
import (
"fmt"
)
type StructA struct {
ValueAA string
ValueAB string
}
type StructB struct {
ValueBA string
ValueBB string
RefStructA StructA
}
func main() {
x := &StructB{RefStructA: StructA{ValueAA: "something"}}
fmt.Printf("%+v", x)
}
out :
&{ValueBA: ValueBB: RefStructA:{ValueAA:something ValueAB:}}

After Type a type, can not be mixed any more

config.Config has a method func String(string) string
and I want to mix those methods to my Type Config
1. it is ok when
// type Config struct
type Config struct {
// a struct has many methods
config.Config
Path string
}
// new and call string method
var a Config = &Config{}
a.String("test")
it not ok when
// type Config struct
type (
Configure config.Config
Config struct {
Configure
Path string
}
)
// new and call string method
var a Config = &Config{}
// error, can not call `String()`
a.String("test")
It's well put by https://go101.org/article/type-system-overview.html:
a new defined type and its respective source type in type definitions are two distinct types.
This works:
package main
import(
"fmt"
)
type MyType struct {
Id int
}
func (mt *MyType)Method() {
fmt.Printf("Method called %d\n", mt.Id)
}
type MyOtherType MyType
func main(){
mt := &MyType{Id:3}
mt.Method()
//mt2 := &MyOtherType{Id:5}
//mt2.Method()
}
But if you uncomment mt2.Method(), you get an error:
mt2.Method undefined (type *MyOtherType has no field or method Method)
Composition works differently. A struct does get the methods of the structs of which it's composed:
package main
import (
"fmt"
)
type MyType struct {
Id int
}
func (mt *MyType) Method() {
fmt.Printf("Method called %d\n", mt.Id)
}
type MyOtherType struct {
MyType
}
func main() {
mt := &MyType{Id: 3}
mt.Method()
mt2 := &MyOtherType{MyType{Id: 5}}
mt2.Method()
}
That's the magic of type composition.
$ go run t.go
Method called 3
Method called 5

How to pass interface pointer through a function in Golang?

I was testing golang functionalities and came across this concept where I can use a pointer of an interface as an interface itself. In the below code, how do I ensure that the value of one changes to random.
package main
import (
"fmt"
)
func some(check interface{}) {
check = "random"
}
func main() {
var one *interface{}
some(one)
fmt.Println(one)
}
Specifically, I need ways in which I can pass an interface pointer to a function which accepts an interface as an argument.
Thanks!
Accept a pointer to interface{} as the first parameter to some
Pass the address of one to some
package main
import (
"fmt"
)
func some(check *interface{}) {
*check = "random"
}
func main() {
var one interface{}
some(&one)
fmt.Println(one)
}
https://play.golang.org/p/ksz6d4p2f0
If you want to keep the same signature of some, you will have to use the reflect package to set the interface{} pointer value:
package main
import (
"fmt"
"reflect"
)
func some(check interface{}) {
val := reflect.ValueOf(check)
if val.Kind() != reflect.Ptr {
panic("some: check must be a pointer")
}
val.Elem().Set(reflect.ValueOf("random"))
}
func main() {
var one interface{}
some(&one)
fmt.Println(one)
}
https://play.golang.org/p/ocqkeLdFLu
Note: val.Elem().Set() will panic if the value passed is not assignable to check's pointed-to type.

Private fields and methods for a struct

In the following test code I would like to have both mytype and the doPrivate method private, so that only members of mytype can access it, but not other types\functions in the scope of the mypackage package.
Can I do this in golang?
package mypackage
type mytype struct {
size string
hash uint32
}
func (r *mytype) doPrivate() string {
return r.size
}
func (r *mytype) Do() string {
return doPrivate("dsdsd")
}
Fields size and hash as well as the doPrivate method should be encapsulated and no other type should have access to them.
In Go, an identifier that starts with a capital letter is exported from the package, and can be accessed by anyone outside the package that declares it.
If an identifier starts with a lower case letter, it can only be accessed from within the package.
If you need members in a type to only be accessed by members of that type, you then need to place that type and its member functions in a separate package, as the only type in that package.
That's not how "privacy" works in Go: the granularity of privacy is the package.
If you really want only the members of mytype to access some fields, then you must isolate the struct and the functions in their own package.
But that's not the usual practice. Whether Go is OOP or not is debatable but clearly the practice isn't to encapsulate the code by a struct like you seem to want to do. Usually a package is small enough to be coherent: if you don't want to access fields from within the package, don't access them.
You can create an interface with the method you wish to expose and only access the object when wrapped into that interface.
package main
type mytype struct {
size string
hash uint32
}
// interface for exposed methods
type myinterface interface {
do() string
}
// constructor (optional)
func newMytype(size string, hash uint32) myinterface {
return &mytype{size, hash}
}
func (r *mytype) doPrivate() string {
return r.size
}
func (r *mytype) do() string {
return r.doPrivate()
}
func main() {
// with constructor
t := newMytype("100", 100)
t.do()
// t.doPrivate() // t.doPrivate undefined (type myinterface has no field or method doPrivate)
// without constructor
t2:= myinterface(&mytype{"100", 100})
t2.do()
// t.doPrivate() // t.doPrivate undefined (type myinterface has no field or method doPrivate)doPrivate)
}
https://play.golang.org/p/awjIIj8Kwms
You cannot do this in Go. Visibility is on a per package level only. But you may split your package into two.
In one module there can be any number of packages.
Public/Private works only across one package.
All public fields, methods and functions starts with uppercase char.
All private fields, methods and functions starts with lowercase char.
To add package to your module or program just create a lowercase folder and add package name to all files inside. Here is the example.
./main.go
./foo/foo.go
./foo/MyStruct.go
file ./foo/foo.go:
package foo
import "fmt"
func SomePublicFuncInFoo() {
somePrivateFuncInFoo()
}
func somePrivateFuncInFoo() {
fmt.Println("somePrivateFuncInFoo call")
}
file ./foo/MyStruct.go:
package foo
import "fmt"
type MyStruct struct {
MyPublicField string // starts with uppercase char
myPrivateField string // starts with lowercase char
}
func NewMyStruct(publicField string, privateField string) *MyStruct {
return &MyStruct{
MyPublicField: publicField,
myPrivateField: privateField,
}
}
func (self *MyStruct) SomePublicMethod() {
self.privateMethod()
}
func (self *MyStruct) privateMethod() {
fmt.Println("MyStruct", self.MyPublicField, self.myPrivateField)
}
file ./main.go:
package main
import (
"fmt"
"{your-module-name}/foo" // this line should be added by your IDE
)
func main() {
foo.SomePublicFuncInFoo()
myStruct := foo.NewMyStruct("string1", "string2")
fmt.Println("myStruct.MyPublicField=", myStruct.MyPublicField)
myStruct.SomePublicMethod()
}
You can have private variables and functions in Go, but the trick is that you simply don't define them in the struct. Bind them to the call stack of a closure, and simply don't return them.
package main
import (
"fmt"
)
type mytype struct {
Do func() string
}
func MyType(size string, hash uint32) mytype {
doPrivate := func() string {
return size
}
return mytype{
Do: func() string {
return doPrivate()
},
}
}
func main() {
instance := MyType("100", 100)
fmt.Println(instance.Do())
}

Object Factory in golang

I am a new to golang. I need to design a function to create object of differing types based on input. But I failed to figure out how to design the interface. Here comes my code:
package main
import (
"fmt"
)
type AA struct{
name string
}
func (this *AA) say(){
fmt.Println("==========>AA")
}
type BB struct{
*AA
age int
}
func (this *BB) say(){
fmt.Println("==========>BB")
}
func ObjectFactory(type int) *AA {
if type ==1 {
return new(AA)
}else{
return new(BB)
}
}
func main() {
obj1 := ObjectFactory(0)
obj1.say()
obj2 := ObjectFactory(0)
obj2.say()
}
The compiler tells me error no matter I ask ObjectFactory return *AA or interface{}. How can I make it work?
First off, using type as a variable name is disallowed in go (see the spec). That is your first problem.
The return type of object factory is *AA. This means that it can only return variables of type *AA, which causes the return of type of BB to fail. As defined in the spec, go doesn't have type inheritance, just struct embedding.
If you create an interface called sayer, you can use that instead of *AA in your ObjectFactory function.
type sayer interface {
say()
}
You probably want to use this interface when trying to get multiple dispatch (as demonstrated in the code below (see on play.golang.org as well).
Try this code:
package main
import (
"fmt"
)
type sayer interface {
say()
}
type AA struct{
name string
}
func (this *AA) say(){
fmt.Println("==========>AA")
}
type BB struct{
*AA
age int
}
func (this *BB) say(){
fmt.Println("==========>BB")
}
func ObjectFactory(typeNum int) sayer {
if typeNum ==1 {
return new(AA)
}else{
return new(BB)
}
}
func main() {
obj1 := ObjectFactory(1)
obj1.say()
obj2 := ObjectFactory(0)
obj2.say()
}

Resources