Are there any implications (GC churn, performance, or otherwise) to defining a struct inside a function vs. having it defined outside? For example:
type Outside struct {
Foo string `json:"foo"`
}
func SomeFunc(b []byte) error {
outside := Outside{}
if err := json.NewDecoder(b).Decode(&outside); err != nil {
return err
}
...
}
vs.
func SomeFunc(b []byte) error {
type inside struct {
Foo string `json:"foo"`
}
if err := json.NewDecoder(b).Decode(&inside); err != nil {
return err
}
...
}
Would there be any situation where one is preferred over the other?
To me the main drawback for a type defined in a function is that you cannot define methods on that type.
See this example https://play.golang.org/p/cgH01cRwDv6:
package main
import (
"fmt"
)
func main() {
type MyType struct {
Name string
}
// You cannot define a method on your type
// defined in a function, can you?
func (m MyType) String() string {
return m.Name
}
m := MyType{Name: "Hello, World!"}
fmt.Println(m)
}
The above example will fail with the error prog.go:15:27: expected ';', found 'IDENT' string (and 1 more errors).
There is no performance difference – it's only a difference of scope (i.e., where the type definition can be seen). If you only need the type within a single function, it's fine to define it there.
As others have noted, if you define a type at the package level (i.e., outside of a function) with a name beginning with a capital letter, it will be exported (i.e., visible outside the package). If the name doesn't begin with a capital letter, it will only be visible within the package.
My understanding is the difference is just in accessibility.
A struct defined starting with an upper case letter will be exportable, meaning it can be accessed from other packages.
A struct defined starting with a lower case letter can be accessed from anything within the same package but not externally.
A struct defined in a function inline can only be accessed/initialized by that function.
For me I once defined a struct inside a function for marshalling JSON byte array ([]byte) into the struct instance, and extract a message from the instance.
Obviously it is not required to define the struct. I could have extracted the message by marshalling the JSON byte array into interface{} and then cast recursively to get the required message.
By defining the struct, extraction of the message becomes very easy :)
var errDetail struct {
Message string `json:"message"`
Success bool `json:"success"`
}
json.Unmarshal(*bytes, &errDetail)
if errDetail.Message == "" {
fmt.Println("error message is not present")
return nil
}
return errDetail.Message
As others have mentioned its all about limit the variables scope. If you are going to use a struct inside a function, you could also use an anonymous struct.
package main
import (
"fmt"
)
func main() {
m := struct {
greeting string
name string
}{
greeting: "hello",
name: "world",
}
fmt.Printf("%v %v\n", m.greeting, m.name)
}
If you're only planing to use the struct inside the function you can define the fields of the struct and assign values to them right away.
The scope is different, you can check in Golang spec here:
Most related parts are:
Go is lexically scoped using blocks:
The scope of an identifier denoting a constant, type, variable, or function (but not method) declared at top level (outside any function) is the package block.
The scope of a type identifier declared inside a function begins at the identifier in the TypeSpec and ends at the end of the innermost containing block.
And if you use go tool compile -S -N hello.go to check the generated assembly code, you can spot the names of type defined in package level and names of type defined inside function are different.
Package level
package main
import (
"fmt"
)
type Point struct {
X, Y int
}
func main() {
fmt.Printf("%v\n", Point{X: 1, Y: 2})
}
Then try to compile and find this line: type."".Point SRODATA size=144.
Inside function
package main
import (
"fmt"
)
func main() {
type Point struct {
X, Y int
}
fmt.Printf("%v\n", Point{X: 1, Y: 2})
}
Then try to find this line: type.*"".Point·1 SRODATA size=56
Than means, they just got different names after compiled.
For Konrad Kleine's problem, you can still do it with some workaround like this
https://play.golang.org/p/50yv66LUNRt
package main
import (
"fmt"
)
func main() {
type MyType struct {
Name string
String func() string
}
InitMyType := func(m *MyType) {
m.String = func() string {
return m.Name
}
return
}
m := MyType{Name: "Hello, World!"}
initMyType(&m)
fmt.Println(m.String())
}
I agree the difference is just accessibility.
But this is still very useful, especially what you want is only a temp struct, or when you do unit test, there are many similar struct like args, test case in a package, you won't need bother to name them one by one.
Related
I'm stuck on something that seems/should be easy in Go.
I wrote a small go playground to explain my problem more easily => https://play.golang.org/p/Sm0SzrvEZS_o
package main
import (
"github.com/sirupsen/logrus"
)
type toto struct {
name string
}
func transform (data ...interface{}) {
logrus.Info("data before ", data)
data[0] = "tutu"
logrus.Info("data after ", data)
}
func main() {
var titi toto
logrus.Info("titi before ", titi) // -> empty
transform(&titi)
logrus.Info("titi after ", titi) // -> should have a name but don't
}
The goal is to pass a struct to a function, modifying in it and continue to use it in the caller function. Sadly, the argument is modified inside the child function but don't move into the caller.
I'm a beginner in this language, maybe I just missed something somewhere... Many thanks in advance for your help
This seems to do it:
package main
type toto struct { name string }
func transform (data ...interface{}) {
t := data[0].(*toto)
t.name = "tutu"
}
func main() {
var titi toto
transform(&titi)
println(titi.name == "tutu")
}
Sounds like you want a pointer.
In your example you use an array of interface{}, is there a particular reason for this? In general you should be explicit with your types in Go, especially since you're dealing with a simple struct.
package main
import (
"log"
)
type toto struct {
Name string
}
// to help with printing
func (t *toto) String() string {
return t.Name
}
// transform takes an array of pointers to the toto struct
func transform(totos ...*toto) {
log.Printf("totos before: %v", totos)
// unsafe array access!
totos[0].Name = "tutu"
log.Printf("totos after: %v", totos)
}
func main() {
// variables in Go are usually defined like this
titi := toto{}
transform(&titi)
}
In Go, the variable that's passed as a parameter in a function is actually a copy of the variable, not the actual variable itself. If you want to modify the variable that's passed, you need to pass it in as a pointer.
Personally, whenever I create a function that accepts a struct, I set the function to accept a pointer to an instance of that struct. This has the benefits of being more memory efficient (since my program doesn't have to create copies of the variable every time the function is called) and it allows me to modify the instance of the struct that I pass.
This is how I would do it:
package main
import (
"github.com/sirupsen/logrus"
)
type toto struct {
name string
}
func transform (t *toto) {
logrus.Info("t before: ", t)
// since t is a pointer to a toto struct,
// I can directly assign "tutu" to the "name" field
// using the "dot" operator
t.name = "tutu"
logrus.Info("t after: ", t)
}
func main() {
// init a pointer to a toto instance
titi := &toto{}
logrus.Info("titi before: ", titi) // -> empty
// this works because transform() accepts a pointer
// to a toto struct and and titi is a pointer to a toto instance
transform(titi)
logrus.Info("titi after (as a pointer): ", titi) // -> not empty
logrus.Info("titi after (as a value): ", *titi) // -> also not empty
}
I'm trying to convert an interface dynamically back to it's original struct but I am having issues accessing attributes of the struct after the conversion.
Take this code for example.
package main
import (
"fmt"
"log"
)
type struct1 struct {
A string
B string
}
type struct2 struct {
A string
C string
}
type struct3 struct {
A string
D string
}
func main() {
s1 := struct1{}
s1.A = "A"
structTest(s1)
s2 := struct2{}
s2.A = "A"
structTest(s2)
s3 := struct3{}
s3.A = "A"
structTest(s3)
}
func structTest(val interface{}) {
var typedVal interface{}
switch v := val.(type) {
case struct1:
fmt.Println("val is struct1")
case struct2:
fmt.Println("val is struct2")
case struct3:
fmt.Println("val is struct3")
default:
log.Panic("not sure what val is.")
}
fmt.Println(typedVal.A)
}
I would like to be able to pass in one of 3 known struct types into my function. Then figure out which struct type was passed in to type assert it. Finally I want to be able to access like attributes.
Basically I want to have some basic inheritance in my structs, but so far it seems that it is not possible to do this in go. I saw some posts mentioning inheritance using an interface, but my structs have no methods so I'm not sure how I would use an interface.
Is something like this possible in go?
I would like to be able to pass in one of 3 known struct types into my function. Then figure out which struct type was passed in to type assert it. Finally I want to be able to access like attributes.
You can use type assertions to do exactly that. Basic idea is, in any case of the type switch just use type assertion to get a concrete instance of the corresponding type and then you can call whatever properties that you wish.
Take a look at the following example
package main
import (
"fmt"
)
type test1 struct {
A, B string
}
type test2 struct {
A, C string
}
func testType(val interface{}) {
switch val.(type) {
case test1:
t := val.(test1)
fmt.Println(t.B)
break
case test2:
t := val.(test2)
fmt.Println(t.C)
break
}
}
func main() {
t1, t2 := test1{B: "hello"}, test2{C: "world"}
testType(t1)
testType(t2)
}
Playground
Function structTest(val interface{}) in your code seems to be loosely typed. You pass it an untyped argument and expect it will satisfy some condition (will have field A), it looks strange in any typed language.
Using an interface this kind of polymorphism, in Go, to my mind, can be expressed something like
package main
import (
"fmt"
"log"
)
type A string
type HasA interface {
PrintA()
}
func (a A) PrintA() { fmt.Println(a) }
type struct1 struct {
A
B string
}
type struct2 struct {
A
C string
}
type struct3 struct {
A
D string
}
func main() {
s1 := struct1{}
s1.A = "A"
structTest(s1)
s2 := struct2{}
s2.A = "A"
structTest(s2)
s3 := struct3{}
s3.A = "A"
structTest(s3)
}
func structTest(val HasA) {
switch val.(type) {
case struct1:
fmt.Println("val is struct1")
case struct2:
fmt.Println("val is struct2")
case struct3:
fmt.Println("val is struct3")
default:
log.Panic("not sure what val is.")
}
val.PrintA()
}
Playground
I wonder how to replace *Type by ? What address has the structure inside?
//mycode.go
package main
import "fmt"
func out(k *Type) {
fmt.Println(k)
}
func main() {
type DataIP struct{ Title, Desc string }
Data := DataIP{
"Hello!",
"Hello GO!",
}
out(&Data)
}
You need to define the type DataIP outside of main() that the type is in the scope of the package and not just inside of the main function:
package main
import "fmt"
type DataIP struct{ Title, Desc string }
func out(k *DataIP) {
fmt.Println(k)
}
func main() {
Data := DataIP{
"Hello!",
"Hello GO!",
}
out(&Data)
}
https://play.golang.org/p/cUS6ttcUy-
I am not sure to understand your question.
If you want out to work only with structs of type DataIP:
simply define DataIP outside of main and use the signature func out(k *DataIP).
if what you want is to be able to pass any type of structure to out:
In golang, this sort of generic methods can be implemented using the interface type. As this answer explains, an interface is a container with two words of data:
one word is used to point to a method table for the value’s underlying type,
and the other word is used to point to the actual data being held by that value.
An interface can hold anything and is often used as a function parameter to be able to process many sort of inputs.
In your case, you can do:
func out(k interface{}) {
fmt.Println(k)
}
This will print &{Hello! Hello GO!}. In case you want the & to disappear (i.e. you always pass it pointers), you can use the reflect package to "dereference" k:
func out(k interface{}) {
fmt.Println(reflect.ValueOf(k).Elem())
}
which yields {Hello! Hello GO!}
Here is a playground example.
if what you want is to print the address of Data:
you can use the %p pattern with fmt.Printf:
fmt.Printf("%p", &Data) // 0x1040a130
Using the out function, you get:
func out(k interface{}) {
fmt.Printf("%p\n", k)
}
See this playground example
I saw somewhere, but I do not remember where, that a slice struct is passing through function like the following code snippet.
package main
import "fmt"
func passSlice(arg interface{}) {
fmt.Println(arg)
}
func main() {
res := []struct {
Name string
}{}
passSlice(res)
}
I have no idea, how to use here a slice struct in the function. Have someone a idea, how can I use it in the function?
In order to use the slice struct (or any other value stored in an interface), you must first do a type assertion or type switch:
Type assertion:
func passSlice(arg interface{}) {
// Put args value in v if it is of type []struct{ Name string }
v, ok := arg.([]struct{ Name string })
if !ok {
// did not contain a value of type []struct{Name string}
return
}
for _, s := range v {
fmt.Println(s.Name)
}
}
Playground: http://play.golang.org/p/KiFeVC3VQ_
Type switches are similar, but can have cases for multiple types.
There is also an option of using the reflect package, allowing you to more dynamically handle interface values without knowing before hand what types you can expect, but using reflection is also more complex. To know more about using reflection in Golang, you can look here:
Laws of reflection
reflect package
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())
}