Pass struct for function that accepts a interface - go

I have the following code:
package main
type MyInterface interface {
Test()
}
type MyType struct {
}
func (m MyType) Test(){}
func AcceptInterface(i *MyInterface){
}
func main() {
object := &MyType{}
AcceptInterface(object)
}
I was expecting this to work, because MyType implements MyInterface, but I get:
cannot use object (type *MyType) as type *MyInterface in argument to
AcceptInterface: *MyInterface is pointer to interface, not interface
I tried doing type assertion: object.(MyInterface), but that doesn't work either.
How can I accomplish this?

As the error says,
cannot use object (type *MyType) as type *MyInterface in argument to AcceptInterface: *MyInterface is pointer to interface, not interface
This means that it is expecting an interface value, not a pointer.
If you change the pointers to values in your code (by removing the & and *), the program will run with no errors:
package main
type MyInterface interface {
Test()
}
type MyType struct {
}
func (m MyType) Test(){}
func AcceptInterface(i MyInterface){
}
func main() {
object := MyType{}
AcceptInterface(object)
}
Play it
Edit 1
If you still want to use a pointer as an argument, there are two important parts of the Go language to note
From the Go Spec on what exacly is a variable that fits an instance:
A variable of interface type can store a value of any type with a method set that is any superset of the interface.
From the Go Spec on what pointers being automatically dereferenced:
As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).Mv [and] as with method calls, a reference to a non-interface method with a pointer receiver using an addressable value will automatically take the address of that value: t.Mp is equivalent to (&t).Mp.
Those two points are important, because when combined they explain that pointers to variables can still fit instances. This is because the pointer's method set is automatically dereferenced by the Go compiler (and since the variable it is referencing can fit an instance, the pointer can, too)!
In action, this means that in order to see if a pointer fits an instance, you have to declare the instance as a value and the pointer as a pointer.
If you run this code:
package main
type MyInterface interface {
Test()
}
type MyType struct {
}
func (m MyType) Test() {}
func AcceptInterface(i MyInterface) {
}
func main() {
object := &MyType{}
AcceptInterface(object)
}
Play it
you will see that there are no errors! Notice how there is an & in the object declaration, but no * in the i declaration?

type MyInterface interface {
Test()
}
type MyType struct {
}
func (m MyType) Test(){}
Note: it means that MyType implemts the interface MyInterface, not MyType*.
You can use:
func (m *MyType) Test(){} //Notice here
func AcceptInterface(i *MyInterface){
}
func main() {
object := &MyType{}
AcceptInterface(object)
}

Use explicit typing if you want to pass a pointer to interface:
func main() {
var object MyInterface = MyType{}
AcceptInterface(&object)
}
I would not recommend using pointer interfaces as you would need to write code like (*i).Test() to call the interface pointer methods. The compiler do auto dereferencing for struct pointers, not so for interface pointers.

Related

Go with Generics: type *T is pointer to type parameter, not type parameter

Probably a golang beginner's question :)
I'm facing following compiler error when trying to compile the code below.
I want to implement an object store for different types (here A and B) sharing a common ID field. Following the DRY idea, I want to implement the store using generics.
When adding an object, I want to set its ID field using the GS interface (the actual code is a bit more complex of course), but the compiler does not want me to do that.
./prog.go:29:7: item.SetId undefined (type *T is pointer to type parameter, not type parameter)
./prog.go:34:24: A does not implement GS (SetId method has pointer receiver)
Is there a recommended way to solve this? Thanks in advance!!
package main
import "fmt"
type A struct {
ID string
AMember string
}
type B struct {
ID string
BMember string
}
type GS interface {
Id() string
SetId(string)
}
func (s A) Id() string { return s.ID }
func (s *A) SetId(i string) { s.ID = i }
func (s B) Id() string { return s.ID }
func (s *B) SetId(i string) { s.ID = i }
type MyStore[T GS] struct {
values map[string]*T
}
func (s *MyStore[T]) add(item *T) {
item.SetId("aa")
s.values["aa"] = item
}
func main() {
var storeA = &MyStore[A]{}
storeA.values = make(map[string]*A)
a := &A{}
storeA.add(a)
fmt.Println(a.Id())
}
About using *T
In short, a type parameter is not its constraint. The constraint only determines what operations are available on T, it doesn't imply anything about *T, which is now just an unnamed pointer type. This is the meaning of:
type *T is pointer to type parameter, not type parameter
As a consequence, as in your case, the method set of *T does not automatically include pointer receiver methods declared on the T's concrete type A, and it does not implement interfaces that would be implemented by *A.
You'd have to make that explicit to the compiler by setting additional constraints. In a simplified form it would be something like:
func Foo[T any, PT interface { SetId(string); *T}](v T) {}
You can find more extensive examples and variations on this use case here:
Go 1.18 Generics how to define a new-able type parameter with interface
How can I instantiate a new pointer of type argument with generic Go?
What is the generic type for a pointer that implements an interface?
About implementing constraints
The reason this instantiation &MyStore[A]{} fails is clearly reported by the error message:
A does not implement GS (SetId method has pointer receiver)
In other words SetId() is declared on *A, and not A. Therefore you should instantiate MyStore with *A:
var storeA = &MyStore[*A]{}
Then change the occurrences of *T in the struct/method definition to T:
type MyStore[T GS] struct {
values map[string]T // just T instead of *T
}
func (s *MyStore[T]) add(item T) {
}
Upon instantiation with *A the type of the field would become equivalent to map[string]*A thus making the assignment storeA.values = make(map[string]*A) valid, and the method signature to add(item *A) thus allowing storeA.add(&A{}).
Fixed playground: https://gotipplay.golang.org/p/dcUVJ5YQK_b

Create new object of typed value via Go (go 1.18) generics

I am playing with generics in beta release of go 1.18. Create function in example below should create new instance of *T (therefore *Apple). I tried to use reflect package for that, but without luck.
Can you please show me how I can change function Create from the example below so that it creates instance of T instead of returning nil and crashing my example?
type FruitFactory[T any] struct{}
func (f FruitFactory[T]) Create() *T {
//how to create non-nil fruit here?
return nil
}
type Apple struct {
color string
}
func example() {
appleFactory := FruitFactory[Apple]{}
apple := appleFactory.Create()
//panics because nil pointer access
apple.color = "red"
}
Since you are instantiating FruitFactory with a non-pointer type (Apple), you can just declare a typed variable and return its address:
func (f FruitFactory[T]) Create() *T {
var a T
return &a
}
Or:
func (f FruitFactory[T]) Create() *T {
return new(T)
}
Playground: https://gotipplay.golang.org/p/IJErmO1mrJh
If you want to instantiate FruitFactory with a pointer type and still avoid segmentation faults, things get more complicated. Basically you have to take advantage of type inference to declare a variable of the non-pointer type in the method body and convert that to the pointer type.
// constraining a type to its pointer type
type Ptr[T any] interface {
*T
}
// the first type param will match pointer types and infer U
type FruitFactory[T Ptr[U], U any] struct{}
func (f FruitFactory[T,U]) Create() T {
// declare var of non-pointer type. this is not nil!
var a U
// address it and convert to pointer type (still not nil)
return T(&a)
}
type Apple struct {
color string
}
func main() {
// instantiating with ptr type
appleFactory := FruitFactory[*Apple, Apple]{}
apple := appleFactory.Create()
// all good
apple.color = "red"
fmt.Println(apple) // &{red}
}
Playground: https://gotipplay.golang.org/p/07nUGI-xP0O
EDIT, March 2022: type inference for defined types has been disabled, so the second playground doesn't compile anymore. Leaving the original one for reference. You must supply all type parameters: FruitFactory[*Apple, Apple]{}, which does make it quite verbose. Type inference works normally for functions.

embedded interface in a struct behaves in a very weird manner

I find hard to understand how Go works internally. There are some cases where it exhibits weird behavior.
type TestInterface interface {
Walk()
}
type A struct {
}
func (a *A) Walk() {
fmt.Println("hello world")
}
type B struct {
TestInterface
}
func main() {
var a *A
b := B{}
a.Walk() // This will not panic even though a is nil
b.Walk() // This will panic.
}
Since b embeds TestInterface, b.Walk() will internally call Walk method on struct A in a similar way as a.Walk() is called.
Why is it then that one works and the other panics?
As Go doc mentioned about Method_declarations, Methods are bound to the base type of the receiver.
The receiver is specified via an extra parameter section preceding the
method name. That parameter section must declare a single non-variadic
parameter, the receiver. Its type must be a defined type T or a
pointer to a defined type T. T is called the receiver base type. A
receiver base type cannot be a pointer or interface type and it must
be defined in the same package as the method. The method is said to be
bound to its receiver base type and the method name is visible only
within selectors for type T or *T.
So your Methods are bound to *main.A type and type of var a also *main.A. So it is allowed to call Walk() method. But if you use a as a value inside the method, it will also panic.
Inside your b of B type, TestInterface's default type is nil and that's why It is panicing. You have to inject interface implemented type into B to avoid panicing.
func main() {
var a *A
b := B{TestInterface:a}
fmt.Println(reflect.TypeOf(a), b)
a.Walk() // This will not panic even though a is nil
b.Walk() // This will not panic anymore.
}
run in playground
Thanks to #mkopriva comment above, I modified the program in the following way and it makes sense now. It also means that nil in Go has a type associated with it.
type TestInterface interface {
Walk()
}
type A struct {
}
func (a *A) Walk() {
fmt.Println("hello world")
}
type B struct {
TestInterface
}
func main() {
var a *A
b := B{TestInterface: a}
// both will not panic
a.Walk()
// TestInterface is still nil as a is nil.
b.Walk()
}```

what is the actual difference between &Struct{field: "blabla"} and Struct{field: "blabla"} (without memory address symbol)?

i.e.
package main
import "fmt"
type rabbit struct {
food string
}
func (r *rabbit) test() {
fmt.Println(r.food)
}
func main() {
roger := &rabbit{"carrot"} //rabbit{"carrot"} would have done the same thing
roger.food = "salad"
roger.test()
}
whether you define roger as &rabbit{"carrot"} or rabbit{"carrot"}, you can in any case change its attributes and call pointer receivers. But if you had to implement an interface like in this example
package main
import "fmt"
type interfaccia interface {
test()
}
type rabbit struct {
food string
}
func (r *rabbit) test() {
fmt.Println(r.food)
}
func someFunc(elemento interfaccia) {
elemento.test()
}
func main() {
roger := &rabbit{"carrot"} //without pointer receiver you would bump into an error
someFunc(roger)
}
then you are forced to set roger as pointer receiver due to the interface. and if I had a recursive struct like this:
type rabbit struct {
food string
girlfriend *rabbit
}
then I'm always forced to use the pointer.
My concern is: since &rabbit{"carrot"} includes all things of rabbit{"carrot"}, why should I use the last one?
A method of a type can either have a pointer receiver or a value receiver. There is a caveat while pointer vs value receiver for methods of a type when that type implements an interface
If a type implements all methods of an interface using value receiver, then both value and pointer of that type can be used while assigning to that interface variable or while passing to a function which accept an argument as that interface.
If a type implements all methods of an interface using pointer receiver, then the only pointer of that type can be used while assigning to that interface variable or while passing to a function that accepts an argument as that interface.
see the example in go tour here

Golang method with pointer receiver [duplicate]

This question already has answers here:
X does not implement Y (... method has a pointer receiver)
(4 answers)
Closed 3 years ago.
I have this example code
package main
import (
"fmt"
)
type IFace interface {
SetSomeField(newValue string)
GetSomeField() string
}
type Implementation struct {
someField string
}
func (i Implementation) GetSomeField() string {
return i.someField
}
func (i Implementation) SetSomeField(newValue string) {
i.someField = newValue
}
func Create() IFace {
obj := Implementation{someField: "Hello"}
return obj // <= Offending line
}
func main() {
a := Create()
a.SetSomeField("World")
fmt.Println(a.GetSomeField())
}
SetSomeField does not work as expected because its receiver is not of pointer type.
If I change the method to a pointer receiver, what I would expect to work, it looks like this:
func (i *Implementation) SetSomeField(newValue string) { ...
Compiling this leads to the following error:
prog.go:26: cannot use obj (type Implementation) as type IFace in return argument:
Implementation does not implement IFace (GetSomeField method has pointer receiver)
How can I have the struct implement the interface and the method SetSomeField change the value of the actual instance without creating a copy?
Here's a hackable snippet:
https://play.golang.org/p/ghW0mk0IuU
I've already seen this question In go (golang), how can you cast an interface pointer into a struct pointer?, but I cannot see how it is related to this example.
Your pointer to the struct should implement the Interface. In that way you can modify its fields.
Look at how I modified your code, to make it working as you expect:
package main
import (
"fmt"
)
type IFace interface {
SetSomeField(newValue string)
GetSomeField() string
}
type Implementation struct {
someField string
}
func (i *Implementation) GetSomeField() string {
return i.someField
}
func (i *Implementation) SetSomeField(newValue string) {
i.someField = newValue
}
func Create() *Implementation {
return &Implementation{someField: "Hello"}
}
func main() {
var a IFace
a = Create()
a.SetSomeField("World")
fmt.Println(a.GetSomeField())
}
The simple answer is that you won't be able to have the struct implement your interface while having SetSomeField work the way you want.
However, a pointer to the struct will implement the interface, so changing your Create method to do return &obj should get things working.
The underlying problem is that your modified SetSomeField method is no longer in the method set of Implementation. While the type *Implementation will inherit the non-pointer receiver methods, the reverse is not true.
The reason for this is related to the way interface variables are specified: the only way to access the dynamic value stored in an interface variable is to copy it. As an example, imagine the following:
var impl Implementation
var iface IFace = &impl
In this case, a call to iface.SetSomeField works because it can copy the pointer to use as the receiver in the method call. If we directly stored a struct in the interface variable, we'd need to create a pointer to that struct to complete the method call. Once such a pointer is made, it is possible to access (and potentially modify) the interface variable's dynamic value without copying it.

Resources