//Creating a structure
type Vertex struct {
X, Y int
}
//Using Add() to add an element to the slice of structure, v
func (v []Vertex) Add() {
v = append(v, Vertex{2,3})
}
func main() {
v:= make([]Vertex, 2, 2) //Creating a slice of Vertex struct type
v.Add()
fmt.Println(v)
}
The go tour site returns the following errors:
invalid receiver type []Vertex ([]Vertex is not a defined type)
v.Add undefined (type []Vertex has no field or method Add)
Could someone help me with where exactly is it that I am going wrong
When you define a method, the receiver must be a named type, or a pointer to a named type.
So func (v []Vertex) Add() { ... } isn't valid because []Vertex isn't a named type or a pointer to a named type.
If you wish to use a method on a slice a vertices, you need a new type. For example:
type Vertices []Vertex
func (v *Vertices) Add() {
*v = append(*v, Vertex{2, 3})
}
The whole program will be like this:
package main
import "fmt"
type Vertex struct {
X, Y int
}
type Vertices []Vertex
func (v *Vertices) Add() {
*v = append(*v, Vertex{2, 3})
}
func main() {
v := make([]Vertex, 2, 2) //Creating a slice of Vertex struct type
(*Vertices)(&v).Add()
fmt.Println(v)
}
//Creating a structure
type Vertex struct {
X, Y int
}
type Verices struct{
Vertices []Vertex
}
func (v *Verices) Add() {
v.Vertices = append(v.Vertices, Vertex{2,3})
}
func main() {
v:= Verices{}
v.Add()
fmt.Println(v)
}
You can't call Add on the slice and you can't define a method on that as well, but you can wrap slice in a struct and define methods on top of that.
See in Action:
https://play.golang.org/p/NHPYAdGrGtp
https://play.golang.org/p/nvEQVOQeg7-
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
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
If I use pointer receiver, the following code has exception at a=v since it is defined on pointer v, it makes sense.
package main
import (
"fmt"
"math"
)
type Abser interface {
Abs(x int) float64 //all types needs to implement this interface
}
type Vertex struct {
X float64
}
func (v *Vertex) Abs(x int) float64 {
return math.Abs(float64(x))
}
func main() {
/*define the interface and assign to it*/
var a Abser
v := Vertex{-3}
a = &v
fmt.Println(a.Abs(-3))
a = v
fmt.Println(a.Abs(-3))
}
But if I change the function of Abs to
func (v Vertex) Abs(x int) float64 {
return math.Abs(float64(x))
}
both a=v and a=&v works, what is the reason behind that?
Understand it like this as I do not have right resources to quote in answer; Go is happy to pass a copy of pointer struct as value when interface is implemented on value, you can check this by printing the address of variable; This is due to the fact that this operation is considered safe and cannot mutate the original value;
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
Given the setup in the 54th slide of the golang tour:
type Abser interface {
Abs() float64
}
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
Why can't a method also be defined for the struct as well as the pointer to the struct? That is:
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
Defining this gives the following error:
prog.go:41: method redeclared: Vertex.Abs
method(*Vertex) func() float64
method(Vertex) func() float64
It can. Just define it on the struct and not the pointer. It will resolve both ways
Method Sets
The method set of the corresponding pointer type *T is the set of all
methods with receiver *T or T (that is, it also contains the method
set of T)
Try live: http://play.golang.org/p/PsNUerVyqp
package main
import (
"fmt"
"math"
)
type Abser interface {
Abs() float64
}
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{5, 10}
v_ptr := &v
fmt.Println(v.Abs())
fmt.Println(v_ptr.Abs())
}
Update: As per comments I have created an extra example that actually makes use of the Abser interface to illustrate that both the value and the pointer satisfy the interface.
https://play.golang.org/p/Mls0d7_l4_t
While considering for example:
type T U
func (t *T) M() int { return 1 }
var t T
...we can now invoke M() on t by writing t.M() as the language permits to call a method with a pointer receiver even on its underlying (non pointer) typed instances, i.e. it becomes equivalent to (&t).M().
If it will be permitted to now additionaly define:
func (t T) M() int { return 2 }
...then there's no way to tell what is now t.M() supposed to return.