对于这些接口实现和调用的代码感到困惑吗?

时间:2018-10-11 14:17:10

标签: go interface

Go版本

  • go版本go1.11 darwin / amd64

代码1:

package main

import "fmt"

type myintf interface {
    GotU()
}

type esc struct {
     i int
}

//func GotU(t esc);
func (e esc)GotU() {
    e.i = 10
}

func TestFunc(it myintf) string {
    it.GotU()
    return  "kk"
}

func main() {

    var test esc
    test.i = 9

    TestFunc(test)

    fmt.Println(test.i)

}

代码2:

package main

import "fmt"

type myintf interface {
    GotU()
}

type esc struct {
     i int
}

func (e esc)GotU() {
    e.i = 10
}

func TestFunc(it myintf) string {
    it.GotU()
    return  "kk"
}

func main() {

    var test esc
    test.i = 9

    TestFunc(&test)

    fmt.Println(test.i)

}

代码3:

package main

import "fmt"

type myintf interface {
    GotU()
}

type esc struct {
     i int
}

func (e *esc)GotU() {
    e.i = 10
}

func TestFunc(it myintf) string {
    it.GotU()
    return  "kk"
}

func main() {

    var test esc
    test.i = 9

    TestFunc(test)

    fmt.Println(test.i)

}

输出:

  • 代码1输出:9
  • 代码2输出:9
  • 代码3由于类型不匹配而无法编译

由于仅实现了func (e esc)GotU(),为什么这两段代码都应该工作并产生相同的结果? 将结构的指针传递给该函数(TestFunc)以获得相同的答案,这让我感到困惑。

2 个答案:

答案 0 :(得分:1)

最后一个代码段实现了指针类型的方法接收器。如果要修改接收器的值,将考虑这种情况。

func (e *esc) GotU() {
    e.i = 10
}

在上述情况下,由于您要在实现接口的方法上传递指针类型的接收器。

type myintf interface {
    GotU()
}

因此,您需要在TestFunc中传递struct的地址。这就是您收到类型不匹配错误的原因,因为您传递的是esc类型的变量,而方法需要*esc的变量。

func main() {

    var test esc
    test.i = 9
    TestFunc(&test)
    fmt.Println(test.i)

}

Go playground上的工作示例

在Golang中,有两种方法可以传递方法接收器。

func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct)  valueMethod()   { } // method on value
  

对于不习惯使用指针的程序员,两者之间的区别   这两个例子可能令人困惑,但实际情况是   很简单的。在类型上定义方法时,接收方(   上面的示例)的行为就好像它是   方法。将接收器定义为值还是指针是   那么,同样的问题,如函数参数是否应为   值或指针。有几个注意事项

首先,也是最重要的一点,该方法是否需要修改接收器?如果是这样,则接收者必须是指针。 (切片和地图用作参考,因此它们的故事有些微妙,但是例如,要更改方法中切片的长度,接收者必须仍然是指针。)在上面的示例中,如果pointerMethod修改了s,调用者将看到这些更改,但是valueMethod是通过调用者参数的副本(即传递值的定义)进行调用的,因此,所做的更改对于调用者而言将是不可见的。

答案 1 :(得分:1)

第一个版本和第二个版本之间的区别在于,您直接在一个版本中传递结构,而在另一个版本中传递指向结构的指针。在这种情况下,这些程序的工作原理相同,因为指针还包括该结构上所有已定义的函数。

但是,这反过来是行不通的。您在指针接收器上定义方法GotU。该结构不了解此功能。如果您愿意打电话

TestFunc(&test)

在第三个程序中,它将编译,但工作方式与其他两个程序不同:输出为:“ 10”

由于在指针接收器上定义了GotUtest被作为引用传递,并且修改持续存在。在其他程序中,test作为值传递,即将其复制,并在GotU中修改副本。当func退出时,副本将被丢弃,并且旧版本仍与以前相同。