【问题标题】:Difference between method signatures of structs结构的方法签名之间的区别
【发布时间】:2020-02-14 03:56:33
【问题描述】:

作为一名来自其他语言(如 C++)的程序员,我发现 go 允许为结构指定方法以允许指针或实例作为参数是相当奇怪的。根据go by example,如果我们不想修改原点,可以使用其中任何一个:

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 中实际上是如何调用的)行为?

明确一点:我并不真正关心字符串化,但想了解语言的行为方式。

【问题讨论】:

  • 你没有在这里调用任何方法,所以引用并不真正适用。 fmt.Println 和相关函数检查参数是否实现 fmt.Stringer,但类型 Bar 没有,只​​有 *Bar 有。

标签: go


【解决方案1】:

只需将& 添加到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

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

【讨论】:

    【解决方案2】:

    因为 Bar 没有实现 stringer *Bar 。

    如果您从 Foo 中删除 stringer 的实现,您将获得“{}”。

    同样,当您编写 fmt.Println(Bar{}) 时,这意味着它会查找类似 @​​987654324@ 而不是 func (*Bar) String() 的内容

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

    为此,您必须了解接口。这些都是我的经验,所以也请你自己研究。 fmt.Print 函数在传递的参数上调用 String()。所以实际上 String() 不是在你的结构上调用的,而是一个 stringer 类型的变量。

    接口类型可以保存一个类型(实现它)或指向它的指针, 如果它是用值接收器实现的。这就是为什么Foo{}&Foo{} 两者都有效。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-12
      • 2020-08-14
      • 1970-01-01
      • 2011-12-07
      • 2016-09-23
      相关资源
      最近更新 更多