方法参数中的接口指针?

huangapple go评论64阅读模式
英文:

Pointer to interface in method args?

问题

你可以在第30行将Mouse替换为Herbivore接口。这样,你就可以传递实现了Herbivore接口的不同结构体给eatingVictim方法,而不仅仅是Mouse

英文:

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

答案1

得分: 0

让我解释一下:

首先,在这个函数中:

func (predator Cat) eatingVictim(victim *Mouse) {
    fmt.Println(predator.name + "的吃掉了" + victim.name)
    predator.hungry = false
    victim.alive = false
}

你想传递一个草食动物(Herbivore)。这是一个不好的解决方案,因为你在这里不会使用Herbivore接口的方法。更好的方法是定义另一个接口。

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

并为Mouse(和如果需要的话,Cat)实现它:

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

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

然后将Predator接口更改为:

type Predator interface {
    eatingVictim(victim Animal)
}

并为Cat实现它:

func (predator *Cat) eatingVictim(victim Animal) {
    fmt.Println(predator.name + "的吃掉了" + victim.GetName())
    predator.hungry = false
    victim.SetAlive(false)
}

我需要提到的是,如果你希望修改原始的结构体,则需要传递一个指向结构体的指针,而不是一个结构体作为接收器参数:

在这里,Mouse结构体不会被修改,只会复制它。

func (herbivore Mouse) eatingGrass() {
    fmt.Println(herbivore.name + "正在吃草.. ^___^")
    herbivore.hungry = false
}

这是修复后的版本:

func (herbivore *Mouse) eatingGrass() {
    fmt.Println(herbivore.name + "正在吃草.. ^___^")
    herbivore.hungry = false
}

如果你想要更好的解释,请访问我的博客文章

最后一件事 - 作为最佳实践 - 如果你在类型的某个方法中使用了结构体指针,那么所有方法都应该使用指针。

最终解决方案:

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 + "正在吃草.. ^___^")
    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 + "的吃掉了" + victim.GetName())
    predator.hungry = false
    victim.SetAlive(false)
}

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

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

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

    fmt.Println(cat)
    fmt.Println(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)
}

答案2

得分: 0

首先,你需要在接口中添加一个 Name() 方法和一个 SetAlive() 方法,并将 eatingGrass 导出:

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

然后,你需要为 Mouse 实现 Name() 方法:

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

然后,对于 SetAlive 方法也做同样的操作。

现在你可以使用该接口:

func (predator Cat) eatingVictim(h Herbivore) {
    fmt.Println(predator.name + "正在吃受害者" + h.Name())
    predator.hungry = false
    h.SetAlive(false)
}

注意:你应该为 *Mouse 实现所有的函数。因为当你设置结构体的某些值时,应该为指针实现方法,而不是结构体本身。否则可能会出现错误。

在实现时,最好像这样定义变量:

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

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
}

huangapple
  • 本文由 发表于 2017年8月5日 15:59:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/45519669.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定