【问题标题】:Passing an interface pointer in a function parameter在函数参数中传递接口指针
【发布时间】:2020-02-07 02:32:46
【问题描述】:

我正在尝试理解 Golang (1.12) 接口。我发现接口指针必须显式取消引用,这与结构不同:

import "fmt"

// A simple interface with one function
type myinter interface {
    hello()
}

// Implement myinter
type mystruct struct {}

func (mystruct) hello() {
    fmt.Println("I am T!")
}

// Some function that calls the hello function as defined by myinter
func callHello(i *myinter) {   
    i.hello()  // <- cannot resolve reference 'hello'
}

func main() {
    newMystruct := &mystruct{}
    callHello(newMystruct)
}

在这里,我的callHello 函数无法解析对接口中定义的hello 函数的引用。当然,取消引用接口是可行的:

func callHello(i *myinter) {   
    (*i).hello()  // <- works!
}

但是在结构体中,我们可以直接调用函数,none of this cumbersome dereference notation is necessary:

func callHello(s *mystruct) {   
    s.hello()  // <- also works!
}

为什么会这样?为什么我们必须显式取消引用interface 指针? Go 是否试图阻止我将 interface 指针传递给函数?

【问题讨论】:

  • Go 中很少使用指向接口的指针。问题中没有任何内容表明有理由使用指向接口的指针。通过将*myinter 更改为myinter 进行修复。这修复了callHello(newMystruct)i.hello() 的错误。
  • Interface can not call self method 的可能重复项,

标签: function go struct parameters interface


【解决方案1】:

这与类型系统的工作方式有关。接口类型I 定义了一个方法集。方法集是为I 类型定义的,而不是为*I 类型定义的。因此,*I 的使用受到限制。函数要设置接口值的时候可以用,但是比较少见:

func f(x *error) {
  *x = fmt.Errorf("Some error")
}

注意接口本身可以有一个底层的指针值:

func f(x someInterface) {
   *x.(*someType) = value
}

func main() {
   x := someType{}
   f(&x)
}

这对于非接口类型是不同的。当您为非接口类型T 定义方法时,该方法同时为T*T 定义。如果为*T 定义了一个方法,那么它只是为*T 定义的,而不是为T 定义的。

【讨论】:

  • 但是如果我想把一个接口作为一个函数的参数,那么通过值传入一个具体类型不是效率低下吗?接口代表抽象类型,传递指针不是比传值好,尤其是当我们不知道具体类型的大小时?
  • 如果将接口传递给函数,则传递的是指向底层值的指针和指向类型的指针。如果接口的底层值是一个结构(不是指针),接口指向该结构的副本。如果您将具体结构传递给函数,该结构将被复制。如果将指针传递给结构,则只会传递一个指针。所以传入一个结构需要一个副本,不管你是否通过接口传递它。
【解决方案2】:

Go 是否试图阻止我将接口指针传递给函数?

是的。

指针接口操作系统错误在(几乎*)所有情况下。

(* 非常罕见且微妙的情况下,指向接口的指针是有意义的,但很有可能每 5 年您不会看到它们超过一次。)

(Nitpick:该语言称为“Go”。“golang.org”是网站。像这样的基本内容包含在兼容性承诺中,并且不依赖于版本:Go 1.0、1.12 和 1.16 的行为完全相同在这方面。)

【讨论】:

  • 你能详细说明为什么这是错误的吗?从过去繁重的 Java 开发来看,接口指针似乎会更常见(将指针传递给抽象类型)。
  • @KennyWorden 如果您想改变某事,则需要指向某事的指针。接口值本身很少被修改。修改的是接口值中包含的实际值:通常将指针存储在接口内部,但这与指向接口值本身的指针完全不同。
猜你喜欢
  • 1970-01-01
  • 2012-05-03
  • 2016-11-07
  • 1970-01-01
  • 1970-01-01
  • 2010-09-05
  • 2017-10-18
  • 1970-01-01
相关资源
最近更新 更多