7

从以下代码中,我有两个关于 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)似乎正确打印“黑色”。

谢谢。

4

2 回答 2

10

Q1:

不,你不能说 car,_ := col.(Car)。其原因不是很明显。以下是 L1 中的 OK 语句列表:

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

":=" 是声明/赋值的简写形式,因为 car 已经在那个范围内声明, := 会给你一个错误("no new variable on left side of :=")。将“ok”放在那里声明了一个新变量(“ok”),但是,下划线/忽略伪变量不计入 := 的新变量。

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

a,_ := 5

因为该语句只返回一个值,并且 go 不会让您忽略任何内容。(你会得到错误:“assignment count mismatch 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 。但是,请注意,这些方法在您正在编写的即时包之外将不可用。为了使它们可见,它们必须以大写字母开头。

于 2013-07-31T05:00:34.950 回答
2

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

这是您的示例已更改,以便通过指向 Car 的指针来满足接口

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

上面的链接输出:

&{yellow}
&{yellow}
&{black}
&{black}
于 2013-07-31T04:59:42.513 回答