为了账号安全,请及时绑定邮箱和手机立即绑定

Go 如何将方法绑定到对象?

Go 如何将方法绑定到对象?

Go
慕森王 2022-07-11 10:40:49
前几天刚开始学习 Go。今天,我们在调试一段代码时,发现了一些似乎违反 Go 直觉的事情。首先,我们定义了一个接口和一个实现它的数据结构。type Executer interface {    Execute()}type whatever struct {    name string}func (this *whatever) Execute() {    log.Println(this.name)}现在考虑我有一个 nil 指针whatever,我尝试调用该方法Execute。在我迄今为止使用的其他面向对象语言中,这将在调用方法(即w.Execute())时调用空指针错误,因为对象指针为空。Execute有趣的是,在 Go 中,该方法被调用,当我尝试取消引用时,该方法出现空指针错误this.name。为什么不在调用方法的时候呢?func main() {    var w *whatever    w.Execute()}那么,我现在想要了解的是这怎么可能?这是否意味着 Go 仅在编译时进行早期方法绑定,而在运行时没有方法与特定对象的绑定?
查看完整描述

1 回答

?
汪汪一只猫

TA贡献1898条经验 获得超8个赞

接收者只是函数的“普通”参数。普通参数可以是指针类型。如果是,则允许您nil作为参数传递,这是完全有效的。您需要记住的只是不要取消引用nil指针参数。这同样适用于特殊的接收器参数。如果它是一个指针,它可能是nil,你不能取消引用它。


规范:方法声明:


接收者是通过方法名称前面的额外参数部分指定的。


...该方法被称为绑定到它的接收者基类型,并且方法名称仅在type或的选择器中可见。T*T


允许nil接收器值不仅是不被禁止的,它还有实际用途。例如,请参阅测试嵌套结构中的 nil 值。


null在 Java 中,您也可以在对象上调用静态方法。确实你不能在 Go 中做同样的事情,因为 Go 没有像static,public等修饰符private。在 Go 中只有导出和非导出的方法(由它们的名字的后一个暗示)。


但是 Go 也提供了类似的东西:方法表达式和方法值。如果您有一个接收器类型的方法m,T则表达式T.m将是一个函数值,其签名包含m接收器类型“前缀”的参数和结果类型。


例如:


type Foo int


func (f Foo) Bar(s string) string { return fmt.Sprint(s, f) }


func main() {

    fooBar := Foo.Bar // A function of type: func(Foo, string) string

    res := fooBar(1, "Go")

    fmt.Println(res)

}

Foo.Bar将是一个带有 type 的函数func (Foo, string) string,你可以像任何其他普通函数一样调用它;而且您还必须将接收器作为第一个参数传递。上面的应用程序输出(在Go Playground上试试):


Go1

稍微“前进”,我们不需要存储Foo.Bar在变量中,我们可以直接调用Foo.Bar:


fmt.Println(Foo.Bar(1, "Go"))

输出相同(在Go Playground上尝试)。现在这几乎看起来像staticJava 中的方法调用。


而作为“最后”步骤,当我们对自身的值(而不是类型标识符)使用上述表达式时Foo,我们会得到方法值,这会保存接收者,因此方法值的类型不包括接收者,它的签名将是方法的签名,我们可以调用它而无需传递接收者:


var f Foo = Foo(1)

bar := f.Bar

fmt.Println(bar("Go"))

这将再次输出相同的内容,请在Go Playground上尝试。


查看完整回答
反对 回复 2022-07-11
  • 1 回答
  • 0 关注
  • 249 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号