指向方法args中的接口的指针?

Gist with code

How can I use interface Herbivore instead *Mouse in line 30?

I want to pass to method eatingVictim different structs which implements Herbivore interface, not only Mouse

Let me explain:

First of all in this function:

func (predator Cat) eatingVictim(victim *Mouse) {
    fmt.Println(predator.name + "'s eating victim " + victim.name)
    predator.hungry = false
    victim.alive = false
}

You want to pass Herbivore. This is a bad solution because you will not use methods from Herbivore interface here. Better approach is to define another interface.

type Animal interface {
    GetName() string
    SetAlive(bool)
}

And implement it for Mouse (and Cat if you wish):

func (m *Mouse) GetName() string {
    return m.name
}

func (m *Mouse) SetAlive(alive bool) {
    m.alive = alive
}

Then change interface Predator to:

type Predator interface {
    eatingVictim(victim Animal)
}

and implement it for Cat

func (predator *Cat) eatingVictim(victim Animal) {
    fmt.Println(predator.name + "'s eating victim " + victim.GetName())
    predator.hungry = false
    victim.SetAlive(false)
}

I need to mention that if you want your original structs to be modified then you need to pass a pointer to struct, not a struct as receiver argument:

Here Mouse struct will not be modified. Only a copy of it.

func (herbivore Mouse) eatingGrass() {
    fmt.Println(herbivore.name + "'s eating a grass.. ^___^")
    herbivore.hungry = false
}

And here is the fixed version:

func (herbivore *Mouse) eatingGrass() {
    fmt.Println(herbivore.name + "'s eating a grass.. ^___^")
    herbivore.hungry = false
}

If you want better explanation for this - then visit my blog post

The last thing - as best practice - if you used Struct pointer in one of the methods of your type then all of them should take a pointer to it.

Final solution:

package main

import "fmt"

type Predator interface {
    eatingVictim(victim Animal)
}

type Herbivore interface {
    eatingGrass()
}

type Animal interface {
    GetName() string
    SetAlive(bool)
}

type Cat struct {
    name   string
    hungry bool
    alive  bool
}

type Mouse struct {
    name   string
    hungry bool
    alive  bool
}

func (herbivore *Mouse) eatingGrass() {
    fmt.Println(herbivore.name + "'s eating a grass.. ^___^")
    herbivore.hungry = false
}

func (m *Mouse) GetName() string {
    return m.name
}

func (m *Mouse) SetAlive(alive bool) {
    m.alive = alive
}

func (predator *Cat) eatingVictim(victim Animal) {
    fmt.Println(predator.name + "'s eating victim " + victim.GetName())
    predator.hungry = false
    victim.SetAlive(false)
}

func main() {
    cat := Cat{"cat", true, true}
    mouse := Mouse{"mouse", true, true}

    fmt.Println(cat)
    fmt.Println(mouse)

    mouse.eatingGrass()
    cat.eatingVictim(&mouse)

    fmt.Println(cat)
    fmt.Println(mouse)
}

First you need to add a Name() and a SetAlive() method to the interface and make eatingGrass exported:

type Herbivore interface {
    Name()string
    SetAlive(bool)
    EatingGrass()
}

Then you need to implement Name() for mouse:

func (herbivore *Mouse) Name()string {
    return Mouse.name
}

Then do the same for SetAlive.

Now you can use the interface:

func (predator Cat) eatingVictim(h Herbivore) {
    fmt.Println(predator.name + "'s eating victim " + h.Name())
    predator.hungry = false
    h.SetAlive(false)
}

Note: You should implement all the functions for the *Mouse. Because when you set some values of the struct you should implement the method for the pointer and not the struct. Otherwise you can have bugs.

When implementing it is also better to define the varibale like this:

func (m *Mouse) Name() string {
  return m.name
}