I'm playing around with Go for the first time. Consider this example.
type Foo struct {
Id int
}
func createFoo(id int) Foo {
return Foo{id}
}
This is perfectly fine for small objects, but how to create factory function for big objects?
In that case it's better to return pointer to avoid copying large chunks of data.
// now Foo has a lot of fields
func createFoo(id int /* other data here */) *Foo {
x := doSomeCalc()
return &Foo{
Id: id
//X: x and other data
}
}
or
func createFoo(id int /* other data here */) *Foo {
x := doSomeCalc()
f := new(Foo)
f.Id = id
//f.X = x and other data
return f
}
What's the difference between these two? What's the canonical way of doing it?
The convention is to write NewFoo functions to create and initialize objects. Examples:
xml.NewDecoder
http.NewRequest
You can always return pointers if you like since there is no syntactic difference when accessing methods or attributes. I would even go as far and say that it is often more convenient to return pointers so that you can use pointer receiver methods directly on the returned object. Imagine a base like this:
type Foo struct{}
func (f *Foo) M1() {}
When returning the object you cannot do this, since the returned value is not addressable (example on play):
NewFoo().M1()
When returning a pointer, you can do this. (example on play)
There is no difference. Sometimes one version is the "natural one", sometimes the other. Most gophers would prefere the first variant (unless the second has some advantages).
(Nitpick: Foo{id} is bad practice. Use Foo{Id: id} instead.)
Related
I have an interface Model, which is implemented by struct Person.
To get a model instance, I have the following helper functions:
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
The above approach allows me to return a properly typed Person instance (can easily add new models later with same approach).
When I attempted to do something similar for returning a slice of models, I get an error. Code:
func newModels(c string) []Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *[]Person {
var models []Person
return &models
}
Go complains with: cannot use newPersons() (type []Person) as type []Model in return argument
My goal is to return a slice of whatever model type is requested (whether []Person, []FutureModel, []Terminator2000, w/e). What am I missing, and how can I properly implement such a solution?
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A []Person and a []Model have different memory layouts. This is because the types they are slices of have different memory layouts. A Model is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. A Person is a struct whose size depends on the fields it contains. In order to convert from a []Person to a []Model, you will need to loop over the array and do a type conversion for each element.
Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
models := make([]Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.
*[]Person // pointer to slice
[]*Person // slice of pointers
Maybe this is an issue with your return type *[]Person, where it should actually be []*Person so to reference that each index of the slice is a reference to a Person, and where a slice [] is in itself a reference to an array.
Check out the following example:
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models []*Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
As Stephen already answered the question and you're a beginner I emphasize on giving advises.
A better way of working with go's interfaces is not to have a constructor returning
the interface as you might be used to from other languages, like java, but to have
a constructor for each object independently, as they implement the interface implicitly.
Instead of
newModel(type string) Model { ... }
you should do
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person and Politician both implementing the methods of Model.
You can still use Person or Politician everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model until you do a manual conversion to
another interface type.
Suppose I have a Person which implements the method Walk() and a Model implements ShowOff(), the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
As others have already answered, []T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) []interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make([]interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf([]int{1,2,3})
Types T and []T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
Even if Go's implementation allowed this, it's unfortunately unsound: You can't assign a []Person to a variable of type []Model because a []Model has different capabilities. For example, suppose we also have Animal which implements Model:
var people []Person = ...
var models []Model = people // not allowed in real Go
models[0] = Animal{..} // ???
var person Person = people[0] // !!!
If we allow line 2, then line 3 should also work because models can perfectly well store an Animal. And line 4 should still work because people stores Persons. But then we end up with a variable of type Person holding an Animal!
Java actually allows the equivalent of line 2, and it's widely considered a mistake. (The error is caught at run time; line 3 would throw an ArrayStoreException.)
Is it possible to define an immutable struct in Golang? Once initialized then only read operation on struct's field, no modification of field values. If so, how to do that.
It is possible to make a struct read-only outside of its package by making its members non-exported and providing readers. For example:
package mypackage
type myReadOnly struct {
value int
}
func (s myReadOnly) Value() int {
return s.value
}
func NewMyReadonly(value int) myReadOnly{
return myReadOnly{value: value}
}
And usage:
myReadonly := mypackage.NewMyReadonly(3)
fmt.Println(myReadonly.Value()) // Prints 3
There is no way to mark fields/variables as read only in a generic way. The only thing you could do is marking fields/variable as unexported (first letter small) and provide public getters to prevent other packages editing variables.
There is no way to define immutable structures in Go: struct fields are mutable and the const keyword doesn't apply to them. Go makes it easy however to copy an entire struct with a simple assignment, so we may think that passing arguments by value is all that is needed to have immutability at the cost of copying.
However, and unsurprisingly, this does not copy values referenced by pointers. And the since built-in collections (map, slice and array) are references and are mutable, copying a struct that contains one of these just copies the pointer to the same underlying memory.
Example :
type S struct {
A string
B []string
}
func main() {
x := S{"x-A", []string{"x-B"}}
y := x // copy the struct
y.A = "y-A"
y.B[0] = "y-B"
fmt.Println(x, y)
// Outputs "{x-A [y-B]} {y-A [y-B]}" -- x was modified!
}
Note : So you have to be extremely careful about this, and not assume immutability if you pass a parameter by value.
There are some deepcopy libraries that attempt to solve this using (slow) reflection, but they fall short since private fields can't be accessed with reflection. So defensive copying to avoid race conditions will be difficult, requiring lots of boilerplate code. Go doesn't even have a Clone interface that would standardize this.
Credit : https://bluxte.net/
if you write a functional struct by golang, it must be an immutable struct, eg
you can write maybe struct definite
type Maybe[T any] struct {
v T
valid bool
}
func (m Maybe[T]) Just() T {
return m.v
}
func (m Maybe[T]) Nothing() bool {
return m.valid == false
}
func Just[T any](v T) Maybe[T] {
return Maybe[T]{
v: v,
valid: true,
}
}
func Nothing[T any]() Maybe[T] {
return Maybe[T]{
valid: false,
}
}
the maybe struct is a immutable struct
Let's say I have a bunch of structs (around 10).
type A struct {
ID int64
... other A-specific fields
}
type B struct {
ID int64
... other B-specific fields
}
type C struct {
ID int64
... other C-specific fields
}
If I have an array of these structs at any given time (either []A, []B, or []C), how can I write a single function that pulls the IDs from the array of structs without writing 3 (or in my case, 10) separate functions like this:
type AList []A
type BList []B
type CList []C
func (list *AList) GetIDs() []int64 { ... }
func (list *BList) GetIDs() []int64 { ... }
func (list *CList) GetIDs() []int64 { ... }
With general method on the slice itself
You can make it a little simpler if you define a general interface to access the ID of the ith element of a slice:
type HasIDs interface {
GetID(i int) int64
}
And you provide implementation for these:
func (x AList) GetID(i int) int64 { return x[i].ID }
func (x BList) GetID(i int) int64 { return x[i].ID }
func (x CList) GetID(i int) int64 { return x[i].ID }
And then one GetID() function is enough:
func GetIDs(s HasIDs) (ids []int64) {
ids = make([]int64, reflect.ValueOf(s).Len())
for i := range ids {
ids[i] = s.GetID(i)
}
return
}
Note: the length of the slice may be a parameter to GetIDs(), or it may be part of the HasIDs interface. Both are more complex than the tiny reflection call to get the length of the slice, so bear with me on this.
Using it:
as := AList{A{1}, A{2}}
fmt.Println(GetIDs(as))
bs := BList{B{3}, B{4}}
fmt.Println(GetIDs(bs))
cs := []C{C{5}, C{6}}
fmt.Println(GetIDs(CList(cs)))
Output (try it on the Go Playground):
[1 2]
[3 4]
[5 6]
Note that we were able to use slices of type AList, BList etc, we did not need to use interface{} or []SomeIface. Also note that we could also use e.g. a []C, and when passing it to GetIDs(), we used a simple type conversion.
This is as simple as it can get. If you want to eliminate even the GetID() methods of the slices, then you really need to dig deeper into reflection (reflect package), and it will be slower. The presented solution above performs roughly the same as the "hard-coded" version.
With reflection completely
If you want it to be completely "generic", you may do it using reflection, and then you need absolutely no extra methods on anything.
Without checking for errors, here's the solution:
func GetIDs(s interface{}) (ids []int64) {
v := reflect.ValueOf(s)
ids = make([]int64, v.Len())
for i := range ids {
ids[i] = v.Index(i).FieldByName("ID").Int()
}
return
}
Testing and output is (almost) the same. Note that since here parameter type of GetIDs() is interface{}, you don't need to convert to CList to pass a value of type []C. Try it on the Go Playground.
With embedding and reflection
Getting a field by specifying its name as a string is quite fragile (think of rename / refactoring for example). We can improve maintainability, safety, and somewhat the reflection's performance if we "outsource" the ID field and an accessor method to a separate struct, which we'll embed, and we capture the accessor by an interface:
type IDWrapper struct {
ID int64
}
func (i IDWrapper) GetID() int64 { return i.ID }
type HasID interface {
GetID() int64
}
And the types all embed IDWrapper:
type A struct {
IDWrapper
}
type B struct {
IDWrapper
}
type C struct {
IDWrapper
}
By embedding, all the embedder types (A, B, C) will have the GetID() method promoted and thus they all automatically implement HasID. We can take advantage of this in the GetIDs() function:
func GetIDs(s interface{}) (ids []int64) {
v := reflect.ValueOf(s)
ids = make([]int64, v.Len())
for i := range ids {
ids[i] = v.Index(i).Interface().(HasID).GetID()
}
return
}
Testing it:
as := AList{A{IDWrapper{1}}, A{IDWrapper{2}}}
fmt.Println(GetIDs(as))
bs := BList{B{IDWrapper{3}}, B{IDWrapper{4}}}
fmt.Println(GetIDs(bs))
cs := []C{C{IDWrapper{5}}, C{IDWrapper{6}}}
fmt.Println(GetIDs(cs))
Output is the same. Try it on the Go Playground. Note that in this case the only method is IDWrapper.GetID(), no other methods needed to be defined.
As far as I know, there is no easy way.
You might be tempted to use embedding, but I'm not sure there's any way to make this particular task any easier. Embedding feels like subclassing but it doesn't give you the power of polymorphism.
Polymorphism in Go is limited to methods and interfaces, not fields, so you can't access a given field by name across multiple classes.
You could use reflection to find and access the field you are interested in by name (or tag), but there are performance penalties for that and it will make your code complex and hard to follow. Reflection is not really intended to be a substitute for Polymorphism or generics.
I think your best solution is to use the polymorphism that Go does give you, and create an interface:
type IDable interface {
GetId() int64
}
and make a GetId method for each of your classes. Full example.
Generic methods require the use of interfaces and reflection.
this code works fine but the temp var used to call the function feels clunky
package main
import "fmt"
type Foo struct {
name string
value int
}
// SetName receives a pointer to Foo so it can modify it.
func (f *Foo) SetName(name string) {
f.name = name
}
var users = map[string]Foo{}
func main() {
// Notice the Foo{}. The new(Foo) was just a syntactic sugar for &Foo{}
// and we don't need a pointer to the Foo, so I replaced it.
// Not relevant to the problem, though.
//p := Foo{}
users["a"] = Foo{value: 1}
x := users["a"]
x.SetName("Abc")
users["a"] = x
fmt.Println(users)
}
http://play.golang.org/p/vAXthNBfdP
Unfortunately no. In Go typically pointers are transparent, and values get auto-addressed when you call pointer methods on them. You managed to find one of the few cases where they aren't. That case is map storage -- values in maps are not considered addressable. That is, you can never do val := &map[key].
When you have a value val := Typ{} and methods defined on *Typ, when you try to call val.Method() Go will super secretly do (&val).Method(). Since you can't do &map[key], then this doesn't work so that temporary variable dance you do is the only way.
As for why that's the case, the internals of a map are considered a bit secret to the user, since it's a hashmap it reserves the right to reallocate itself, shuffle around data, etc, allowing you to take the address of any value undermines that. There have been proposals considered to allow this specific case to work (that is: calling a method with a pointer receiver on it), since the fix is so easy, but none have been accepted yet. It may be allowed someday, but not right now.
Following Jsor’s detailed explanation: if you really need to call methods of map values, it seems the only way for now is to use pointers for values.
var users = make(map[string]*Foo)
func main() {
users["a"] = &Foo{value: 1}
users["a"].SetName("Abc")
fmt.Println(users["a"])
}
But that loses you, precisely, the ability to meaningfully print them (values are just memory addresses now). You’d need to write a custom printing function for *Foo:
func (f *Foo) String() string {
return fmt.Sprintf("%v", *f)
}
http://play.golang.org/p/6-y2ewdnre
I have an interface Model, which is implemented by struct Person.
To get a model instance, I have the following helper functions:
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
The above approach allows me to return a properly typed Person instance (can easily add new models later with same approach).
When I attempted to do something similar for returning a slice of models, I get an error. Code:
func newModels(c string) []Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *[]Person {
var models []Person
return &models
}
Go complains with: cannot use newPersons() (type []Person) as type []Model in return argument
My goal is to return a slice of whatever model type is requested (whether []Person, []FutureModel, []Terminator2000, w/e). What am I missing, and how can I properly implement such a solution?
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A []Person and a []Model have different memory layouts. This is because the types they are slices of have different memory layouts. A Model is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. A Person is a struct whose size depends on the fields it contains. In order to convert from a []Person to a []Model, you will need to loop over the array and do a type conversion for each element.
Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
models := make([]Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.
*[]Person // pointer to slice
[]*Person // slice of pointers
Maybe this is an issue with your return type *[]Person, where it should actually be []*Person so to reference that each index of the slice is a reference to a Person, and where a slice [] is in itself a reference to an array.
Check out the following example:
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models []*Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
As Stephen already answered the question and you're a beginner I emphasize on giving advises.
A better way of working with go's interfaces is not to have a constructor returning
the interface as you might be used to from other languages, like java, but to have
a constructor for each object independently, as they implement the interface implicitly.
Instead of
newModel(type string) Model { ... }
you should do
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person and Politician both implementing the methods of Model.
You can still use Person or Politician everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model until you do a manual conversion to
another interface type.
Suppose I have a Person which implements the method Walk() and a Model implements ShowOff(), the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
As others have already answered, []T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) []interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make([]interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf([]int{1,2,3})
Types T and []T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
Even if Go's implementation allowed this, it's unfortunately unsound: You can't assign a []Person to a variable of type []Model because a []Model has different capabilities. For example, suppose we also have Animal which implements Model:
var people []Person = ...
var models []Model = people // not allowed in real Go
models[0] = Animal{..} // ???
var person Person = people[0] // !!!
If we allow line 2, then line 3 should also work because models can perfectly well store an Animal. And line 4 should still work because people stores Persons. But then we end up with a variable of type Person holding an Animal!
Java actually allows the equivalent of line 2, and it's widely considered a mistake. (The error is caught at run time; line 3 would throw an ArrayStoreException.)