Go:接口方法调用

Tgi*_*day 5 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)
}
Run Code Online (Sandbox Code Playgroud)

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

Q2:L(2)打印"白色"而不是"黄色".

为什么?L(3)似乎正确打印"黑色".

谢谢.

Lin*_*ope 8

Q1:

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

car,ok := col.(Car)
car = col.(Car)
car,_ = col.(Car)
_,ok := col.(Car)
Run Code Online (Sandbox Code Playgroud)

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

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

a,_ := 5
Run Code Online (Sandbox Code Playgroud)

因为该语句只返回一个值,所以go不会让你忽略任何东西.(你会得到错误:"赋值计数不匹配2 = 1").

Q2:

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

car.setColor("yellow")
//...
func (car Car) setColor(s string) {
    car.color = s
    fmt.Println(car.color)
}
Run Code Online (Sandbox Code Playgroud)

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

func (car *Car) setColor(s string) {
    car.color = s
}
Run Code Online (Sandbox Code Playgroud)

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

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

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


Bra*_*AGr 2

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

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

func (c *Car) getColor() string {
    return c.color
}
func (c *Car) setColor(s string) {
    c.color = s
}
Run Code Online (Sandbox Code Playgroud)

上面的链接输出:

&{yellow}
&{yellow}
&{black}
&{black}
Run Code Online (Sandbox Code Playgroud)