作为来自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,而是想了解语言的行为。
答案 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{}