Reuse a function across multiple structs to satisfy an interface - go

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

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{})
}

How to check if an attribute exists in an object's dynamic struct

I'm confused about how to check if an attribute exists in an object's dynamic struct. I.e. if we have the following structs:
type Animal struct {
Name string
Origin string
}
type Bird struct {
Animal
Speed float32
CanFly bool
}
type Bear struct {
Animal
Lazy bool
}
And now I have a function using Animal as a parameter:
func checkAminalSpeed (a Animal){
// if the struct of current animal doesn't have the Speed attribute
// print ("I don't have a speed")
//otherwise, return the speed of this animal
}
This function is trying to check the varible's runtime type to choose action.
I'd like to know in this case, how to write this checkAminalSpeed function? Thanks!
Go does not support inheritance, but perhaps you'll find the following approach tolerable.
Use an interface to define the Animal's behaviour:
type Animal interface {
GetName() string
GetOrigin() string
GetSpeed() float32
}
Use a "base" type that will contain common fields and also implement the behaviour:
type AnimalBase struct {
Name string
Origin string
}
func (a AnimalBase) GetName() string { return a.Name }
func (a AnimalBase) GetOrigin() string { return a.Origin }
func (a AnimalBase) GetSpeed() float32 { return -1 }
Embed the "base" type and override any behaviour you need to:
type Bird struct {
AnimalBase
Speed float32
CanFly bool
}
func (b Bird) GetSpeed() float32 { return b.Speed }
And then...
func checkAminalSpeed(a Animal) {
if speed := a.GetSpeed(); speed == -1 {
fmt.Println("I don't have speed")
} else {
fmt.Println(speed)
}
}
https://play.golang.org/p/KIjfC7Rdyls
mkopriva is right. Go does not support inheritance, you can use reflect and interface{} also
ps: reflect cost more time than interface
package main
import (
"fmt"
"reflect"
)
type Animal struct {
Name string
Origin string
}
type Bird struct {
Animal
Speed float32
CanFly bool
}
type Bear struct {
Animal
Lazy bool
}
func checkAminalSpeed (a interface{}){
v := reflect.ValueOf(a)
if f, ok := v.Type().FieldByName("Speed"); ok{
fmt.Printf("%v\n", f)
}
}
func main() {
checkAminalSpeed(Bird{})
checkAminalSpeed(Bear{})
}

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?

Adding a pointer to a struct to a slice

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.

Resources