Go中的指针和接口

时间:2018-12-19 06:35:55

标签: pointers go interface

我正试图了解我在这里做错了..所有回复表示赞赏:)

如果取消注释“ // grow()”有效,

其他错误:

  

prog.go:38:2:不可能的类型切换情况:p(类型工厂)不能具有   动态类型plant1(增长方法具有指针接收器)prog.go:39:16:   不可能的类型断言:plant1不实现plant(增长   方法具有指针接收器)prog.go:40:2:不可能的类型切换   情况:p(植物类型)不能具有动态植物2(增长方法具有   指针接收器)prog.go:41:16:不可能的类型断言:plant2   不实现工厂(增长方法具有指针接收器)   prog.go:60:12:不能在参数中使用p1(类型plant1)作为植物类型   以showHeight表示:plant1未实现plant(增长方法具有   指针接收器)prog.go:61:12:无法将p2(类型plant2)用作类型   在showHeight的参数中使用plant:plant2没有实现plant   (增长方法具有指针接收器)

https://play.golang.org/p/oMv7LdW85yK

package main

import (
    "fmt"
)

type plant1 struct {
    name   string
    height int
}

type plant2 struct {
    species string
    height  int
}

func (self *plant1) grow() {
    self.height++
}
func (self *plant2) grow() {
    self.height++
}

func (self plant1) getHeight() int {
    return self.height
}
func (self plant2) getHeight() int {
    return self.height
}

type plant interface {
    getHeight() int
    //grow()
}

func showHeight(p plant) {
    switch p.(type) {
    case plant1:
        fmt.Println(p.(plant1).name, `Height = `, p.(plant1).getHeight())
    case plant2:
        fmt.Println(p.(plant2).species, `Height = `, p.(plant2).getHeight())
    }

}

func main() {

    p1 := plant1{
        name:   `Plant 10`,
        height: 1,
    }
    p2 := plant2{
        species:   `Plant 20`,
        height: 1,
    }
    p1.grow()
    p1.grow()
    p2.grow()   

    showHeight(p1)
    showHeight(p2)
}

3 个答案:

答案 0 :(得分:2)

包装到接口中的值不可寻址。该值必须是可寻址的,才能在指针接收器上调用方法。 grow方法是使用指针接收器声明的。因此,编译器看到plant类型和plant1类型都没有实现plant2接口。因此,您无法将plant1plant2作为plant传递给showHeight函数。而且切换是不可能的,因为plant接口的实现不包括plant1plant2类型。

请参见Why value stored in an interface is not addressable in Golang

答案 1 :(得分:0)

您的函数func showHeight(p plant)接受一个接口作为参数,而一个接口仅接受您实现的类型。

案例评论//grow()

自从您评论grow() plant以来,您仅为getHeight()plant 1实现了一种方法plant 2,一切顺利。

不加注释的grow()

现在您的所有类型(工厂1或工厂2)都没有实现plant接口,因为grow()是在*plant1上定义的,而*plant2不在plant1上定义的,并且plant2。结果;您的函数showHeight(p plant)可以接受接口类型工厂,不能接受plp2,因为这些函数不再是plant类型。

修复:

将指针传递为showHeight(&p1)showHeight(&p2),并在函数定义的情况和打印语句中,将plant1plant2替换为*plant1和{{1 }}

可能发生的混乱是,*plant2getHeight尚未实现*plant1,为什么*plant2*plant1属于{{1 }}? 逻辑:传递指针时,可以从其中派生值以调用*plant2,但是传递值时,不能派生任何地址来调用plant

旁注:getHeight可以更改为grow(),因为p是接口,它可以调用自己的方法。

答案 2 :(得分:0)

This due to the way the Method Set in Go works. In Go, a Method on a concrete receiver type implements both the value type and pointer type, while a method on a pointer receiver type implements only the pointer value.

In the case of the grow method, the pointer receiver type *plant1/*plant2 are used, so only a pointer value of those types can implement the grow method on an interface and the concrete value type can't.

Since the receiver type on getHeight method is a concrete receiver type, it implements both the pointer type value (*plant1/*plant2) and the type value of both plant & plant2.

If you change the parameter(p) passed to showHeight to a *plant1/*plant2 type and change the type assertion to expect *plant1/*plant2 this would solve the error.

check this code example playground link