2013-07-31 72 views
4

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

谢谢。

+1

'setColor'不会做你认为它做的事。你应该让'c'(接收器)一个*指针*给一辆车。 – MatrixFrog

回答

2

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

Here is your example改变,使得该接口是由一个指针纳到汽车

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

上述输出的链接:

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

Q1:

不,你不能说汽车,_:= col。(汽车)。原因并不明显。这里没关系语句在L1列表:

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

“:=”是报关/分配的缩写形式,因为汽车在该范围内已宣布,:=会给你一个错误(“没有新的变量在= =“的左侧)。把“ok”声明为一个新变量(“ok”),然而,下划线/忽略伪变量不会被计算为一个新的变量:=。

编辑:为了清楚起见,您可以在此处放置“ok”或下划线,因为类型断言返回类型断言值和表示断言是否成功的布尔值。如果问题其实是关于“_”一般情况下,而不是在一个问题“:=”操作符:没有,在一般情况下,你不能这样做

a,_ := 5 

由于该语句只返回一个价值,不会让你忽略任何东西。 (你会得到错误:“分配计数不匹配2 = 1”)。

Q2:

在Go中,方法可以是在指针或值/基本类型。我相信你会发现以下将工作正常:

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

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

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

这将使变化可见的电话后,因为你给的方法,其中汽车所在,而不仅仅是它具有数据的位置。为了彻底,有一些涉及“参考类型”(地图,切片,频道)的案例,您可以在非指针方法之外看到副作用,但这些都是规则的例外情况。

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

因为您似乎在学习,所以一个杂注:本身没有错,开始时setColor和getColor都带有小写字母。但是,请注意,这些方法将不在您正在编写的即时包中提供。为了让他们可见,他们必须以大写字母开头。