我读了一些奇怪的代码,它们将一个方法转换为一个函数,该函数的第一个参数是指向该方法结构的指针。
我写了一个例子来证明它:
package main
import "fmt"
type fooS struct{}
func (s *fooS) fooF(fooArg interface{}) {
fmt.Println("fooF: ", fooArg)
}
type wowS struct {
callback func(s *fooS, fooArg interface{})
}
func main() {
wow := new(wowS)
wow.callback = (*fooS).fooF // strange
wow.callback(nil, 123)
}
示例的语法很奇怪,但没有错误。
任何人都可以告诉我这些代码是如何运作的,或者给我一份关于它们的官方文件吗?
感谢:)
答案 0 :(得分:7)
如果
M
位于T
类型的方法集中,T.M
是一个函数, 可以作为常规函数调用,其参数与M
前缀相同 通过另一个参数,即方法的接收者。MethodExpr = ReceiverType "." MethodName . ReceiverType = TypeName | "(" "*" TypeName ")" | "(" ReceiverType ")" .
考虑使用两个方法
T
的结构类型Mv
,其接收方为。{ 键入T
和Mp
,其接收者的类型为*T
。type T struct { a int } func (tv T) Mv(a int) int { return 0 } // value receiver func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver var t T
表达式
T.Mv
产生一个等于
Mv
的函数,但显式接收器为 它的第一个论点;它有签名func(tv T, a int) int
可以使用显式接收器正常调用该函数,因此 这五个调用是等价的:
t.Mv(7) T.Mv(t, 7) (T).Mv(t, 7) f1 := T.Mv; f1(t, 7) f2 := (T).Mv; f2(t, 7)
同样,表达式
(*T).Mp
产生一个表示带签名
的Mp的函数值func(tp *T, f float32) float32
对于具有值接收器的方法,可以使用a派生函数 显式指针接收器,所以
(*T).Mv
产生一个代表
的函数值Mv
并带有签名func(tv *T, a int) int
这样的函数通过接收器间接创建值 作为接收者传递给基础方法;方法没有 覆盖在函数调用中传递其地址的值。
最后一种情况,指针接收器的值接收器功能 方法,是非法的,因为指针接收器方法不在 值类型的方法集。
使用函数调用调用从方法派生的函数值 句法;接收器作为呼叫的第一个参数提供。 也就是说,在
f := T.Mv
的情况下,f
被调用为f(t, 7)
而不是t.f(7)
。至 构造一个绑定接收器的函数,使用函数文字 或方法价值。从接口方法派生函数值是合法的 类型。结果函数采用了明确的接收器 界面类型。
见:
Go - difference between parameter and receiver
Is there a performance penalty for passing "this" by value in Go methods?
differences between pointer and value slice in for-range loop