Go方法集 – 使用接收器T调用指针类型*T的方法

huangapple go评论89阅读模式
英文:

Go methods sets — Calling method for pointer type *T with receiver T

问题

根据Go语言规范中的说明,类型T的方法集由所有接收者类型为T的方法组成。相应指针类型T的方法集由所有接收者类型为T或T的方法组成(也就是说,它还包含了类型T的方法集)。

你的理解是正确的:类型T有自己的方法集,而类型T有自己的方法集以及类型T的方法集,因为它可以将接收者 T解引用为T并调用方法。因此,我们可以使用接收者类型为*T的方法来调用变量类型为T的方法。

你决定验证自己的逻辑,提供了一个示例代码。你有点困惑。看起来我可以在T上调用“*T的方法”?你还提供了一个更复杂的示例,也让你感到困惑。是否存在某种相反的类型推断?

你是否漏掉了什么,还是我的逻辑有误?

谢谢!

英文:

Go spec says:

> The method set of any other type T consists of all methods with receiver type T. The method set of the corresponding pointer type *T is the set of all methods with receiver *T or T (that is, it also contains the method set of T).

I understand this as: T has its own method set, while *T has it own method set plus the method set of T, because it can dereference receiver *T to T and call the method. Therefore, we can call some method with receiver *T of variable type T.

So I decided to verify my logic:

package main

import (
  "fmt"
  "reflect"
)

type User struct{}

func (self *User) SayWat() {
  fmt.Println(self)
  fmt.Println(reflect.TypeOf(self))
  fmt.Println("WAT\n")
}

func main() {
  var user User = User{}
  
  fmt.Println(reflect.TypeOf(user), "\n")
  
  user.SayWat()
}

http://play.golang.org/p/xMKuLzUbIf

I am a bit confused. It looks like I can call methods "of *T" on T? I have a bit wider example http://play.golang.org/p/RROPMj534A, which confuses me too. Is there some vice versa type inference?

Am I missing something, or my logic is incorrect?

Thanks!

答案1

得分: 10

你不能在T上调用*T的方法,但编译器足够智能,会为你获取变量的引用,从而有效地调用

(&user).SayWat()

这在这里有解释:

> 调用:如果方法集(类型的)x包含m,并且参数列表可以分配给m的参数列表,则方法调用x.m()是有效的。如果x是可寻址的,并且&x的方法集包含m,则x.m()是(&x).m()的简写。

为了理解区别,你可以考虑一个返回值(不可寻址):

func aUser() User {
    return User{}
}

...

aUser().SayWat()

会出现错误:

prog.go:40: cannot call pointer method on aUser()
prog.go:40: cannot take the address of aUser()

http://play.golang.org/p/HOTKiiOK7S

英文:

You cannot call a method of *T on T, but the compiler is smart enough to take the reference of the variable for you, effectively calling

(&user).SayWat()

This is explained here:

> Calls: A method call x.m() is valid if the method set of (the type of) x
contains m and the argument list can be assigned to the parameter list of
m. If x is addressable and &x's method set contains m, x.m() is shorthand
for (&x).m().

To understand the difference, you can for instance take a return value (non-addressable):

func aUser() User {
    return User{}
}

...

aUser().SayWat()

Fails with error:

prog.go:40: cannot call pointer method on aUser()
prog.go:40: cannot take the address of aUser()

http://play.golang.org/p/HOTKiiOK7S

huangapple
  • 本文由 发表于 2013年10月18日 01:08:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/19433050.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定