结构的方法签名之间的区别

时间:2018-12-11 10:27:42

标签: go

作为来自C ++等其他语言的程序员,我发现go允许为允许使用指针或实例作为参数的结构指定方法是很奇怪的。根据{{​​3}}的说法,如果我们不想修改原点,则一次可以使用它们:

  

Go自动处理方法调用的值和指针之间的转换。您可能希望使用指针接收器类型,以避免在方法调用上进行复制或允许方法更改接收结构。

考虑以下代码:

package main

import (
    "fmt"
)

type Foo struct {}

type Bar struct {}

func (this Foo) String() string {
  return "Foo"
}

func (this *Bar) String() string {
  return "Bar"
}

func main() {
  fmt.Println(Foo{}) // "Foo"
  fmt.Println(Bar{}) // "{}"
}

为什么不能同时使用两个签名版本来修改结构的 stringify (我不知道它实际上在go中如何调用)行为?

请明确一点:我并不真的在乎stringify,而是想了解语言的行为。

2 个答案:

答案 0 :(得分:2)

只需将&添加到Bar{}并使其成为指针接收器,如下所示:

fmt.Println(&Bar{}) // "Bar"

对输出的代码进行一些调整:

Foo
Bar

请参阅:

package main

import "fmt"

type Foo struct{}

func (Foo) String() string {
    return "Foo"
}

type Bar struct{}

func (*Bar) String() string {
    return "Bar"
}

func main() {
    fmt.Println(Foo{}) // "Foo"
    pb := &Bar{}
    fmt.Println(pb) // "Bar"
}

注意:

  

接收者名称应反映其身份;不要使用   通用名称,例如“ this”或“ self”

您的示例不需要此处的名称。

很高兴阅读Golang methods receivers

  

值接收器对原始类型值的副本进行操作。这个   意味着涉及成本,尤其是当结构非常   大,接收到的指针效率更高。

答案 1 :(得分:1)

因为Bar没有实现stringify * Bar却实现了。

如果从Foo中删除stringify的实现,则会得到“ {}”。

类似地,当您写fmt.Println(Bar{})时,它表示它将查找类似func (Bar) String()而不是func (*Bar) String()

另外,当您写fmt.Println(&Foo{})时,故事会有所不同,您可能会认为它会打印“ {}”,因为没有func (*Foo) String(),但它会打印“ Foo”。

为此,您将必须了解接口。这些是我的经验,所以也请自己做研究。 fmt.Print函数使用stringify中的String()。因此,实际上不是在您的结构上调用String(),而是调用stringify类型的变量。

  

接口类型可以保存一个类型(实现它的类型)或指向它的指针,   如果它是通过价值接收者实现的。这就是Foo{}和   &Foo{}都可以。

     

接口类型只能保存类型的指针(实现了该指针),   如果它是用指针​​接收器实现的。为什么?因为当你   用指针接收器实现一个接口,它需要一个地址   只能提供一个指针。这就是为什么只有&Bar{}   有效,而不是Bar{}