I was expecting to see 3, what's going on?
package main
import "fmt"
type Counter struct {
count int
}
func (self Counter) currentValue() int {
return self.count
}
func (self Counter) increment() {
self.count++
}
func main() {
counter := Counter{1}
counter.increment()
counter.increment()
fmt.Printf("current value %d", counter.currentValue())
}
http://play.golang.org/p/r3csfrD53A
Your method receiver is a struct value, which means the receiver gets a copy of the struct when invoked, therefore it's incrementing the copy and your original isn't updated.
To see the updates, put your method on a struct pointer instead.
func (self *Counter) increment() {
self.count++
}
Now self is a pointer to your counter variable, and so it'll update its value.
http://play.golang.org/p/h5dJ3e5YBC
I want to add to #user1106925 response.
If you need to use the custom type inside a map you need to use a map to pointer. because the for l,v :=range yourMapType will receive a copy of the struct.
Here a sample:
package main
import "fmt"
type Counter struct {
Count int
}
func (s *Counter) Increment() {
s.Count++
}
func main() {
// Using map to type
m := map[string]Counter{
"A": Counter{},
}
for _, v := range m {
v.Increment()
}
fmt.Printf("A: %v\n", m["A"].Count)
// Now using map to pointer
mp := map[string]*Counter{
"B": &Counter{},
}
for _, v := range mp {
v.Increment()
}
fmt.Printf("B: %v\n", mp["B"].Count)
}
The output is:
$ go build && ./gotest
A: 0
B: 1
Related
Now that type parameters are available on golang/go:master, I decided to give it a try. It seems that I'm running into a limitation I could not find in the Type Parameters Proposal. (Or I must have missed it).
I want to write a function which returns a slice of values of a generic type with the constraint of an interface type. If the passed type is an implementation with a pointer receiver, how can we instantiate it?
type SetGetter[V any] interface {
Set(V)
Get() V
}
// SetGetterSlice turns a slice of type V into a slice of type T,
// with T.Set() called for each entry in values.
func SetGetterSlice[V any, T SetGetter[V]](values []V) []T {
out := make([]T, len(values))
for i, v := range values {
out[i].Set(v) // panic if T has pointer receiver!
}
return out
}
When calling the above SetGetterSlice() function with the *Count type as T, this code will panic upon calling Set(v). (Go2go playground) To no surprise, as basically the code created a slice of nil pointers:
// Count implements SetGetter interface
type Count struct {
x int
}
func (c *Count) Set(x int) { c.x = x }
func (c *Count) Get() int { return c.x }
func main() {
ints := []int{1, 2, 3, 4, 5}
sgs := SetGetterSlice[int, *Count](ints)
for _, s := range sgs {
fmt.Println(s.Get())
}
}
Variations of the same problem
This ideas won't work, and I can't seem to find any simple way to instantiate the pointed value.
out[i] = new(T) will result in a compile failure, as it returns a *T where the type checker wants to see T.
Calling *new(T), compiles but will result in the same runtime panic because new(T) returns **Count in this case, where the pointer to Count is still nil.
Changing the return type to a slice of pointer to T will result in a compile failure:
func SetGetterSlice[V any, T SetGetter[V]](values []V) []*T {
out := make([]*T, len(values))
for i, v := range values {
out[i] = new(T)
out[i].Set(v) // panic if T has pointer receiver
}
return out
}
func main() {
ints := []int{1, 2, 3, 4, 5}
SetGetterSlice[int, Count](ints)
// Count does not satisfy SetGetter[V]: wrong method signature
}
Workaround
The only solution I found until now, is to require a constructor function to be passed to the generic function. But this just feels wrong and a bit tedious. Why would this be required if func F(T interface{})() []T is perfectly valid syntax?
func SetGetterSlice[V any, T SetGetter[V]](values []V, constructor func() T) []T {
out := make([]T, len(values))
for i, v := range values {
out[i] = constructor()
out[i].Set(v)
}
return out
}
// ...
func main() {
ints := []int{1, 2, 3, 4, 5}
SetGetterSlice[int, *Count](ints, func() *Count { return new(Count) })
}
Summary
My questions, in order of priority:
Am I overlooking something obvious?
Is this a limitation of generics in Go and this is as good as it gets?
Is this limitation known or should I raise an issue at the Go project?
Basically you have to add one more type parameter to the constraint to make T convertible to its pointer type. In its most basic form, this technique looks like the following (with an anonymous constraint):
func Foo[T any, PT interface { *T; M() }]() {
p := PT(new(T))
p.M() // calling method on non-nil pointer
}
Playground: https://go.dev/play/p/L00tePwrDfx
Step by step solution
Your constraint SetGetter already declares a type param V, so we slightly modify the example above:
// V is your original type param
// T is the additional helper param
type SetGetter[V any, T any] interface {
Set(V)
Get() V
*T
}
Then you define the SetGetterSlice function with the type parameter T any, whose purpose is just to instantiate the constraint SetGetter.
You will then be able to convert the expression &out[i] to the pointer type, and successfully call the method on the pointer receiver:
// T is the type with methods with pointer receiver
// PT is the SetGetter constraint with *T
func SetGetterSlice[V any, T any, PT SetGetter[V, T]](values []V) []T {
out := make([]T, len(values))
for i, v := range values {
// out[i] has type T
// &out[i] has type *T
// PT constraint includes *T
p := PT(&out[i]) // valid conversion!
p.Set(v) // calling with non-nil pointer receiver
}
return out
}
Full program:
package main
import (
"fmt"
)
type SetGetter[V any, T any] interface {
Set(V)
Get() V
*T
}
func SetGetterSlice[V any, T any, PT SetGetter[V, T]](values []V) []T {
out := make([]T, len(values))
for i, v := range values {
p := PT(&out[i])
p.Set(v)
}
return out
}
// Count implements SetGetter interface
type Count struct {
x int
}
func (c *Count) Set(x int) { c.x = x }
func (c *Count) Get() int { return c.x }
func main() {
ints := []int{1, 2, 3, 4, 5}
// instantiate with base type
sgs := SetGetterSlice[int, Count](ints)
for _, s := range sgs {
fmt.Println(s.Get()) // prints 1,2,3,4,5 each in a newline
}
}
This becomes more verbose because SetGetterSlice now requires three type parameters: the original V plus T (the type with pointer receivers) and PT (the new constraint). However when you call the function, you can omit the third one – with type inference, both type params V and T required to instantiate PT SetGetter[V,T] are already known:
SetGetterSlice[int, Count](ints)
Playground: https://go.dev/play/p/gcQZnw07Wp3
Spent a few hours to understand it.
So decided to add my example.
package main
import (
"fmt"
)
type User struct {
FullName string
Removed bool
}
type Account struct {
Name string
Removed bool
}
type Scanner[T User | Account] interface {
Scan()
*T
}
type Model interface {
User | Account
}
func (user *User) Scan() {
user.FullName = `changed in scan method`
user.Removed = true
}
func (account *Account) Scan() {
account.Name = `changed in scan method`
account.Removed = true
}
func setRemovedState[T Model, PT Scanner[T]](state bool) *T {
var obj T
pointer := PT(&obj)
pointer.Scan() // calling method on non-nil pointer
return &obj
}
func main() {
user := setRemovedState[User](true)
account := setRemovedState[Account](true)
fmt.Printf("User: %v\n", *user)
fmt.Printf("Account: %v\n", *account)
}
you can also try to attack the problem slighty differently, to keep it simple.
package main
import (
"fmt"
)
func mapp[T any, V any](s []T, h func(T) V) []V {
z := make([]V, len(s))
for i, v := range s {
z[i] = h(v)
}
return z
}
func mappp[T any, V any](s []T, h func(T) V) []V {
z := make([]V, 0, len(s))
for _, v := range s {
z = append(z, h(v))
}
return z
}
// Count implements SetGetter interface
type Count struct {
x int
}
func (c *Count) Set(x int) { c.x = x }
func (c *Count) Get() int { return c.x }
func FromInt(x int) *Count {
var out Count
out.x = x
return &out
}
func main() {
ints := []int{1, 2, 3, 4, 5}
sgs := mapp(ints, FromInt)
fmt.Printf("%T\n",sgs)
for _, s := range sgs {
fmt.Println(s.Get())
}
fmt.Println()
sgs = mappp(ints, FromInt)
fmt.Printf("%T\n",sgs)
for _, s := range sgs {
fmt.Println(s.Get())
}
}
https://go2goplay.golang.org/p/vzViKwiJJkZ
It is like your func SetGetterSlice[V any, T SetGetter[V]](values []V, constructor func() T) []T but without the complex verbosity. It also gave me zero pain to solve.
Edit: see blackgreen's answer, which I also found later on my own while scanning through the same documentation they linked. I was going to edit this answer to update based on that, but now I don't have to. :-)
There is probably a better way—this one seems a bit clumsy—but I was able to work around this with reflect:
if reflect.TypeOf(out[0]).Kind() == reflect.Ptr {
x := reflect.ValueOf(out).Index(i)
x.Set(reflect.New(reflect.TypeOf(out[0]).Elem()))
}
I just added the above four lines to your example. The temporary variable is left over from some debug and obviously can be removed. Playground link
Here is a simple go program that is not working :
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
fmt.Println(getProperty(&v, "X"))
}
func getProperty(v *Vertex, property string) (string) {
return v[property]
}
Error:
prog.go:18: invalid operation: v[property] (index of type *Vertex)
What I want is to access the Vertex X property using its name. If I do v.X it works, but v["X"] doesn't.
Can someone tell me how to make this work ?
Most code shouldn't need this sort of dynamic lookup. It's inefficient compared to direct access (the compiler knows the offset of the X field in a Vertex structure, it can compile v.X to a single machine instruction, whereas a dynamic lookup will need some sort of hash table implementation or similar). It's also inhibits static typing: the compiler has no way to check that you're not trying to access unknown fields dynamically, and it can't know what the resulting type should be.
But... the language provides a reflect module for the rare times you need this.
package main
import "fmt"
import "reflect"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
fmt.Println(getField(&v, "X"))
}
func getField(v *Vertex, field string) int {
r := reflect.ValueOf(v)
f := reflect.Indirect(r).FieldByName(field)
return int(f.Int())
}
There's no error checking here, so you'll get a panic if you ask for a field that doesn't exist, or the field isn't of type int. Check the documentation for reflect for more details.
You now have the project oleiade/reflections which allows you to get/set fields on struct value or pointers.
It makes using the reflect package less tricky.
s := MyStruct {
FirstField: "first value",
SecondField: 2,
ThirdField: "third value",
}
fieldsToExtract := []string{"FirstField", "ThirdField"}
for _, fieldName := range fieldsToExtract {
value, err := reflections.GetField(s, fieldName)
DoWhatEverWithThatValue(value)
}
// In order to be able to set the structure's values,
// a pointer to it has to be passed to it.
_ := reflections.SetField(&s, "FirstField", "new value")
// If you try to set a field's value using the wrong type,
// an error will be returned
err := reflection.SetField(&s, "FirstField", 123) // err != nil
With getAttr, you can get and set easy.
package main
import (
"fmt"
"reflect"
)
func getAttr(obj interface{}, fieldName string) reflect.Value {
pointToStruct := reflect.ValueOf(obj) // addressable
curStruct := pointToStruct.Elem()
if curStruct.Kind() != reflect.Struct {
panic("not struct")
}
curField := curStruct.FieldByName(fieldName) // type: reflect.Value
if !curField.IsValid() {
panic("not found:" + fieldName)
}
return curField
}
func main() {
type Point struct {
X int
y int // Set prefix to lowercase if you want to protect it.
Z string
}
p := Point{3, 5, "Z"}
pX := getAttr(&p, "X")
// Get test (int)
fmt.Println(pX.Int()) // 3
// Set test
pX.SetInt(30)
fmt.Println(p.X) // 30
// test string
getAttr(&p, "Z").SetString("Z123")
fmt.Println(p.Z) // Z123
py := getAttr(&p, "y")
if py.CanSet() { // The necessary condition for CanSet to return true is that the attribute of the struct must have an uppercase prefix
py.SetInt(50) // It will not execute here because CanSet return false.
}
fmt.Println(p.y) // 5
}
Run it on 👉
Reference
CanSet
A Good example of the reflex: https://stackoverflow.com/a/6396678
You can marshal the struct and unmarshal it back to map[string]interface{}. But, it would convert all the number values to float64 so you would have to convert it to int manually.
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
fmt.Println(getProperty(&v, "X"))
}
func getProperty(v *Vertex, property string) float64 {
m, _ := json.Marshal(v)
var x map[string]interface{}
_ = json.Unmarshal(m, &x)
return x[property].(float64)
}
I want to offer a different approach that is not using reflection:
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
fmt.Println(getProperty(&v, "X"))
}
type Getter func(v *Vertex) int
var VertexAccess = map[string]Getter{
"X": func(v *Vertex) int { return v.X },
"Y": func(v *Vertex) int { return v.Y },
}
func getProperty(v *Vertex, property string) int {
return VertexAccess[property](v)
}
https://go.dev/play/p/2E7LZBWx7yZ
This is an O(1) map lookup and a function call which should perform better than reflection. Obviously, you need some scaffolding code for every type you want to support. On the plus side, you can refactor your code easily; your function getProperty is a potential anti-pattern to https://martinfowler.com/bliki/TellDontAsk.html
Is there anyway to make a map of function pointers, but functions that take recievers? I know how to do it with regular functions:
package main
func someFunc(x int) int {
return x
}
func main() {
m := make(map[string]func(int)int, 0)
m["1"] = someFunc
print(m["1"](56))
}
But can you do that with functions that take recievers? Something like this (though I've tried this and it doesn't work):
package main
type someStruct struct {
x int
}
func (s someStruct) someFunc() int {
return s.x
}
func main() {
m := make(map[string](someStruct)func()int, 0)
s := someStruct{56}
m["1"] = someFunc
print(s.m["1"]())
}
An obvious work around is to just pass the struct as a parameter, but that's a little dirtier than I would have liked
You can do that using Method Expressions:
https://golang.org/ref/spec#Method_expressions
The call is a bit different, since the method expression takes the receiver as the first argument.
Here's your example modified:
package main
type someStruct struct {
x int
}
func (s someStruct) someFunc() int {
return s.x
}
func main() {
m := make(map[string]func(someStruct)int, 0)
s := someStruct{56}
m["1"] = (someStruct).someFunc
print(m["1"](s))
}
And here's a Go playground for you to test it:
https://play.golang.org/p/PLi5A9of-U
http://play.golang.org/p/wU44VOa_uP
Here's a simple example:
package main
import "fmt"
type Holder struct {
i int
}
func (h Holder) SetMember(i1 int) {
fmt.Println(i1)
h.i = i1
}
func (h Holder) GetMember() int {
fmt.Println(h.i)
return h.i
}
func main() {
c := Holder{i:3}
c.SetMember(5)
c.GetMember()
}
I'm probably missing a very basic truth about golang.
Why doesn't the value 5 stick after setting it?
This example works:
http://play.golang.org/p/j8hdKWPdsc
package main
import "fmt"
type Holder struct {
i int
}
func (h *Holder) SetMember(i1 int) {
fmt.Println(i1)
h.i = i1
}
func (h *Holder) GetMember() int {
fmt.Println(h.i)
return h.i
}
func main() {
c := &Holder{i:3}
c.SetMember(5)
c.GetMember()
}
In the second example you passing the struct object itself, you are a pointer receiver. You see the change because you have actually modified the original object. In the first example you are passing the copy of the object that contains the same values, you are using a value receiver. You don't see the change because your original object was not changed.
To convince yourself, you can print the addresses of the objects inside main and your SetMember method.
When using pointer receiver:
In main:
fmt.Printf("address in main: %p\n", c)
In SetMember (should be the same as in main):
fmt.Printf("address in SetMember: %p\n", h)
When using value receiver:
In main:
fmt.Printf("address in main: %p\n", &c)
In SetMember (should be different from what is in main) :
fmt.Printf("address in SetMember: %p\n", &h)
Here is a simple go program that is not working :
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
fmt.Println(getProperty(&v, "X"))
}
func getProperty(v *Vertex, property string) (string) {
return v[property]
}
Error:
prog.go:18: invalid operation: v[property] (index of type *Vertex)
What I want is to access the Vertex X property using its name. If I do v.X it works, but v["X"] doesn't.
Can someone tell me how to make this work ?
Most code shouldn't need this sort of dynamic lookup. It's inefficient compared to direct access (the compiler knows the offset of the X field in a Vertex structure, it can compile v.X to a single machine instruction, whereas a dynamic lookup will need some sort of hash table implementation or similar). It's also inhibits static typing: the compiler has no way to check that you're not trying to access unknown fields dynamically, and it can't know what the resulting type should be.
But... the language provides a reflect module for the rare times you need this.
package main
import "fmt"
import "reflect"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
fmt.Println(getField(&v, "X"))
}
func getField(v *Vertex, field string) int {
r := reflect.ValueOf(v)
f := reflect.Indirect(r).FieldByName(field)
return int(f.Int())
}
There's no error checking here, so you'll get a panic if you ask for a field that doesn't exist, or the field isn't of type int. Check the documentation for reflect for more details.
You now have the project oleiade/reflections which allows you to get/set fields on struct value or pointers.
It makes using the reflect package less tricky.
s := MyStruct {
FirstField: "first value",
SecondField: 2,
ThirdField: "third value",
}
fieldsToExtract := []string{"FirstField", "ThirdField"}
for _, fieldName := range fieldsToExtract {
value, err := reflections.GetField(s, fieldName)
DoWhatEverWithThatValue(value)
}
// In order to be able to set the structure's values,
// a pointer to it has to be passed to it.
_ := reflections.SetField(&s, "FirstField", "new value")
// If you try to set a field's value using the wrong type,
// an error will be returned
err := reflection.SetField(&s, "FirstField", 123) // err != nil
With getAttr, you can get and set easy.
package main
import (
"fmt"
"reflect"
)
func getAttr(obj interface{}, fieldName string) reflect.Value {
pointToStruct := reflect.ValueOf(obj) // addressable
curStruct := pointToStruct.Elem()
if curStruct.Kind() != reflect.Struct {
panic("not struct")
}
curField := curStruct.FieldByName(fieldName) // type: reflect.Value
if !curField.IsValid() {
panic("not found:" + fieldName)
}
return curField
}
func main() {
type Point struct {
X int
y int // Set prefix to lowercase if you want to protect it.
Z string
}
p := Point{3, 5, "Z"}
pX := getAttr(&p, "X")
// Get test (int)
fmt.Println(pX.Int()) // 3
// Set test
pX.SetInt(30)
fmt.Println(p.X) // 30
// test string
getAttr(&p, "Z").SetString("Z123")
fmt.Println(p.Z) // Z123
py := getAttr(&p, "y")
if py.CanSet() { // The necessary condition for CanSet to return true is that the attribute of the struct must have an uppercase prefix
py.SetInt(50) // It will not execute here because CanSet return false.
}
fmt.Println(p.y) // 5
}
Run it on 👉
Reference
CanSet
A Good example of the reflex: https://stackoverflow.com/a/6396678
You can marshal the struct and unmarshal it back to map[string]interface{}. But, it would convert all the number values to float64 so you would have to convert it to int manually.
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
fmt.Println(getProperty(&v, "X"))
}
func getProperty(v *Vertex, property string) float64 {
m, _ := json.Marshal(v)
var x map[string]interface{}
_ = json.Unmarshal(m, &x)
return x[property].(float64)
}
I want to offer a different approach that is not using reflection:
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
fmt.Println(getProperty(&v, "X"))
}
type Getter func(v *Vertex) int
var VertexAccess = map[string]Getter{
"X": func(v *Vertex) int { return v.X },
"Y": func(v *Vertex) int { return v.Y },
}
func getProperty(v *Vertex, property string) int {
return VertexAccess[property](v)
}
https://go.dev/play/p/2E7LZBWx7yZ
This is an O(1) map lookup and a function call which should perform better than reflection. Obviously, you need some scaffolding code for every type you want to support. On the plus side, you can refactor your code easily; your function getProperty is a potential anti-pattern to https://martinfowler.com/bliki/TellDontAsk.html