Go:接口方法调用

时间:2013-07-31 04:41:54

标签: go

我从以下代码中有两个关于Go接口的问题。

type Color interface {
    getColor() string
    setColor(string)
}

type Car struct {
    color string
}
func (c Car) getColor() string {
    return c.color
}
func (c Car) setColor(s string) {
    c.color = s
}

func main() {
    car := Car{"white"}
    col := Color(car)

    car = col.(Car)         // L(1)
    car.setColor("yellow")
    fmt.Println(col)        // L(2)
    fmt.Println(car)
    car.color = "black"
    fmt.Println(col)        // L(3)
    fmt.Println(car)
}

Q1:写L(1) as "car, _ := col.(Car)"?

是否可以

Q2:L(2)打印“白色”而不是“黄色”。

为什么? L(3)似乎正确打印“黑色”。

感谢。

2 个答案:

答案 0 :(得分:8)

Q1:

不,你不能说汽车,_:= col。(汽车)。其原因并不明显。这是L1中的正确陈述列表:

car,ok := col.(Car)
car = col.(Car)
car,_ = col.(Car)
_,ok := col.(Car)

“:=”是声明/赋值的简短形式,因为car已在该范围内声明,:=将给出错误(“左侧没有新变量:=”)。设置“ok”会声明一个新变量(“ok”),但是,下划线/忽略伪变量不会被计为新变量:=。

编辑:要清楚,您可以在此处输入“ok”或下划线,因为类型断言返回类型声明值和指示断言是否成功的布尔值。如果问题实际上是关于“_”的一般情况而不是关于“:=”运算符的问题:不,在一般情况下你不能做类似的事情

a,_ := 5

因为该语句只返回一个值而且go不会让你忽略任何东西。 (你会得到错误:“赋值计数不匹配2 = 1”)。

Q2:

在Go中,方法可以是指针或值/基类型。我相信你会发现以下内容可以正常使用:

car.setColor("yellow")
//...
func (car Car) setColor(s string) {
    car.color = s
    fmt.Println(car.color)
}

在此代码中,它将正确打印“黄色”。这是因为您通过 value 传递方法接收器。事实上,它确实修改了汽车 - 但是与你通过汽车不同的汽车,这辆汽车恰好是你称之为方法的汽车的完美副本。要解决这个问题,你需要一个指针接收器,

func (car *Car) setColor(s string) {
    car.color = s
}

这将使调用后的更改可见,因为您为该方法提供了汽车所在的位置,而不仅仅是它所拥有的数据。为了彻底,有一些涉及“引用类型”(地图,切片,通道)的案例,您可以在非指针方法之外看到副作用,但这些是规则的例外。

请注意,如果您为此方法指定一个指针接收器,则Car类型的变量不再实现接口Color。相反,实现接口的类型是* Car(指向Car的指针)。事实上,由于指针在Go中是透明的,即使你将getColor与非指针接收器一起使用也是如此,但通常更好的形式是在一个类型上实现接口的所有方法指针或基类型,而不是两者兼而有之。

一个杂项注释,因为你似乎在学习:本身没有任何错误,开头的setColor和getColor都是小写字母。但是,请注意,在您编写的直接包装之外,这些方法将无法使用。要使它们可见,它们必须以大写字母开头。

答案 1 :(得分:2)

为了让setColor改变Car对象,你希望你必须传递一个指针,你的代码传递一个Car by value,并改变那个值的颜色,然后在方法返回时立即丢弃Car值的那个副本

Here is your example已更改,以便通过指向Car

的指针满足界面
func (c *Car) getColor() string {
    return c.color
}
func (c *Car) setColor(s string) {
    c.color = s
}

上面的链接输出:

&{yellow}
&{yellow}
&{black}
&{black}