Adding a pointer to a struct to a slice - go

I'm trying to add a pointer to a struct to a slice, but I can't get rid of this error:
cannot use NewDog() (type *Dog) as type *Animal in append:
*Animal is pointer to interface, not interface
How can I avoid this error? (while still using pointers)
package main
import "fmt"
type Animal interface {
Speak()
}
type Dog struct {
}
func (d *Dog) Speak() {
fmt.Println("Ruff!")
}
func NewDog() *Dog {
return &Dog{}
}
func main() {
pets := make([]*Animal, 2)
pets[0] = NewDog()
(*pets[0]).Speak()
}

package main
import "fmt"
type Animal interface {
Speak()
}
type Dog struct {
}
func (d *Dog) Speak() {
fmt.Println("Ruff!")
}
func NewDog() *Dog {
return &Dog{}
}
func main() {
pets := make([]Animal, 2)
pets[0] = NewDog()
pets[0].Speak()
}
You don't need a Slice of pointers to Animal interfaces.
http://golang.org/doc/effective_go.html#pointers_vs_values

just change your code to:
func main() {
pets := make([]Animal, 2)
pets[0] = NewDog()
pets[0].Speak()
}
a interface value is already an implicit pointer.

Related

Struct with an pointer to an Interface mock error

package main
import (
"github.com/golang/mock/gomock"
"testing"
)
type Talker interface {
talk() string
}
type Person struct {
moth *Talker
}
func (p *Person) speak() string {
return (*p.moth).talk()
}
func TestPerson(t *testing.T) {
ctrl := gomock.NewController(t)
mockTalker := NewMockTalker(ctl)
person := Person{moth: mockTalker}
}
Assuming that I have already created a mock for Talker interface using mockgen.
I am getting error when I am creating Person{moth: mockTalker}. I am not able to pass mockTalker.
Don't user pointer interface. Essentially interface is pointer
type Person struct {
moth Talker
}
Normally, if function want return interface, it's will return new struct by pointer.
import "fmt"
type I interface {
M()
}
type S struct {
}
func (s *S) M() {
fmt.Println("M")
}
func NewI() I {
return &S{}
}
func main() {
i := NewI()
i.M()
}
In your Person struct the moth field is *Talker type. It is a pointer type of Talker interface. NewMockTalker(ctl) returns Talker type mock implementation.
You can do two things to fix this.
Change the Person's moth field's type to Talker.
type Person struct {
moth Talker
}
or
pass pointer reference of mockTalker to the person initialization`
person := Person{moth: &mockTalker}

Golang inheritance - Cannot use (type func(d Dog)) as the type func(animal Animal)

I was tring to write a method callGetName which can take both getCatName and getDogName method as its parameter while my IDE tells me:
Cannot use 'getDogName' (type func(d Dog)) as the type func(animal Animal)
package main
type Animal struct {
Name string
}
type Cat struct {
Animal
}
type Dog struct {
Animal
}
func getCatById(c Cat) {}
func validateDogNames(d Dog) {}
func invokeFunc(f func(animal Animal)) {}
func main() {
invokeFunc(getCatById)
invokeFunc(validateDogNames)
}
I tried to analyze the reason, maybe it's because golang supports multiple inheritance?
Please let me know if I was doing something stupid or is there any better way to achieve this?
========
A little more about why I'm trying this: in go-kit framework, I have to write makeEndpoint functions for every single service method defined. And I used reflect to adopt a generic makeEndpoints like below:
func NewProductEndpoints() ProductEndpoints {
ps := service.NewProductService()
return ProductEndpoints{
GetProductById: makeEndpoint(ps, util.GetFunctionName(ps.GetProductById)),
CreateProduct: makeEndpoint(ps, util.GetFunctionName(ps.CreateProduct)),
}
}
func makeEndpoint(s service.ProductService, funcName string) kitEndpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(domain.ProductDTO)
currFunc := reflect.ValueOf(s).MethodByName(funcName)
args := []reflect.Value{reflect.ValueOf(req)}
res := currFunc.Call(args)[0]
return res, nil
}
}
wondering if there's a better way to achieve. Thanks in advance.
So you're thinking in a fairly OOP fashion, Go does not have inheritance (to clarify it has struct embedding which is what you are doing in your first example). We tend to favour composition to solve problems.
One way you could look at solving your problem is like the below.
package main
import (
"fmt"
)
type Namer interface {
Name() string
}
type Cat struct {
name string
}
func (c Cat) Name() string {
return c.name
}
type Dog struct {
name string
}
func (d Dog) Name() string {
return d.name
}
func PetName(n Namer) {
fmt.Println(n.Name())
}
func main() {
PetName(Dog{name: "Fido"})
PetName(Cat{name: "Mittens"})
}
Names can be improved, but it should act as a basic example of an approach that could be taken.
Edit: Example based on comment left below
package main
import (
"fmt"
)
type Invoker interface {
Invoke()
}
type Dog struct{}
func (Dog) Bark() {
fmt.Println("Woof")
}
func (d Dog) Invoke() {
d.Bark()
}
type Cat struct{}
func (Cat) Meow() {
fmt.Println("Meow")
}
func (c Cat) Invoke() {
c.Meow()
}
func CallFunc(i Invoker) {
i.Invoke()
}
func main() {
CallFunc(Cat{})
CallFunc(Dog{})
}

GoLang defining methods on object receiver behaves wrong, but pointer receiver

I have an interface named Being, which requires two methods SetValue(v int) and GetValue() int. Then I have a base class Animal implementing it, and further a subclass Cat inherited from Animal.
Following is the code (Go Playground):
package main
import (
"fmt"
)
type Being interface {
SetValue(v int)
GetValue() int
}
type Animal struct {
value int
}
type Cat struct {
Animal
}
func (a Animal) SetValue(v int) {
a.value = v
}
func (a Animal) GetValue() int {
return a.value
}
func MakeCat() Being {
return Cat{}
}
func main() {
cat := MakeCat()
cat.SetValue(1)
fmt.Println(cat.GetValue())
}
However, the output is 0, rather than 1.
If I slightly modify the code to this (Go Playground):
package main
import (
"fmt"
)
type Being interface {
SetValue(v int)
GetValue() int
}
type Animal struct {
value int
}
type Cat struct {
Animal
}
//Change the receiver to a pointer
func (a *Animal) SetValue(v int) {
a.value = v
}
func (a Animal) GetValue() int {
return a.value
}
//Return the pointer
func MakeCat() Being {
cat := Cat{}
return &cat
}
func main() {
cat := MakeCat()
cat.SetValue(1)
fmt.Println(cat.GetValue())
}
where the modifications are marked by comments, the code behaves correctly, and output 1.
I cannot think of the reason of such phenomena, could anyone help?

Reuse a function across multiple structs to satisfy an interface

Is there anyway that you can use the same function across multiple structs to satisfy an interface?
For example:
package main
import "fmt"
type Animal interface {
Speak() string
}
type Dog struct {}
func (d Dog) Speak() string {
return "Woof!"
}
type Wolf struct {}
func (w Wolf) Speak() string {
return "HOWWWWWWWWL"
}
type Beagle struct {}
func (b Beagle) Speak() string {
return "HOWWWWWWWWL"
}
type Cat struct {}
func (c Cat) Speak() string {
return "Meow"
}
func main() {
var a Animal
a = Wolf{}
fmt.Println(a.Speak())
}
Because Wolf and Beagle share the exact same function, is there anyway to write that function once, then share it between the two structs so that they both satisfy Animal?
You can create a parent struct that is embedded by each of the animals that "howl". The parent struct implements the Speak() string method, which means Wolf and Beagle implement the Animal interface.
package main
import "fmt"
type Animal interface {
Speak() string
}
type Howlers struct {
}
func (h Howlers) Speak() string {
return "HOWWWWWWWWL"
}
type Dog struct {}
func (d Dog) Speak() string {
return "Woof!"
}
type Wolf struct {
Howlers
}
type Beagle struct {
Howlers
}
type Cat struct {}
func (c Cat) Speak() string {
return "Meow"
}
func main() {
var a Animal
a = Wolf{}
fmt.Println(a.Speak())
}
https://play.golang.org/p/IMFnWdeweD

golang: how is "func() interface {}" and "func() *MyStruct" incompatible types?

Suppose I have code, where a function accepts another one as an argument:
type Person struct {
Name string
}
func personBuilder() * Person {
return &Person{Name: "John"}
}
func printRetrievedItem(callback func() interface {}){
fmt.Print(callback());
}
func doStuff(){
printRetrievedItem(personBuilder);
}
This results in error cannot use personBuilder (type func() *Person) as type func() interface {} in function argument. If I change personBuilder return type to interface{}, it works, but in real project I'm working on I want to have a concrete type for clear design and TDD purposes.
Does Go support such method signature generalization? What are the workarounds, if you could not change the personBuilder part (e.g. you have a lot parameterless functions that return different type of struct, and you want to build a consumer function that accepts any of those builders as argument)?
One workaround is to define an inline function that calls personBuilder.
printRetrievedItem(func() interface{} {return personBuilder()});
Playground
You can create an interface with a method that returns an interface{}:
type Thinger interface {
Thing() interface{}
}
func (p *Person) Thing() interface{} {
return p
}
func printRetrievedItem(t Thinger){
fmt.Print(t.Thing());
}
func doStuff(){
printRetrievedItem(personBuilder);
}
This is just an example, please use a better name!
To answer your question, fun() A is not a func() interface{}, for the same reason that []A is not an []interface{}. It's explained very well in the go wiki.
Either do a wrapper like #GrzegorzŻur suggested or define your own interface and make your xxxxBuilder return it:
type Namer interface {
Name() string
}
type Person struct {
name string
}
func (p *Person) Name() string {
return p.name
}
func personBuilder() Namer {
return &Person{name: "John"}
}
func printRetrievedItem(callback func() Namer) {
fmt.Printf("%T: %v", callback(), callback().Name())
}
You can use pkg reflect for this. (Note however that the solution of #OneOfOne is more idiomatic).
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
}
func personBuilder() *Person {
return &Person{Name: "John"}
}
func printRetrievedItem(callback interface{}) {
vals := reflect.ValueOf(callback).Call([]reflect.Value{})
fmt.Println(vals[0].Interface())
}
func main() {
printRetrievedItem(personBuilder) // &{John}
printRetrievedItem(func() string { return "hello" }) // hello
}
Here's an example in the playground.

Resources