我只是在弄乱,并写了下面的代码,
package main
import (
"fmt"
)
type Person struct {
name string
}
func (p Person) printName() {
fmt.Println(p.name)
}
type Man struct {
name string
f func()
}
func main() {
p := Person{name: "John"}
m := Man{name: "Adam"}
m.f = p.printName
p.printName()
m.f()
}
上面的代码导致以下输出。这也适用于所有程序包。
John
John
所以,这是我的问题。
m.f = p.printName
时会发生什么?答案 0 :(得分:3)
这个问题主要涉及接收者,可能会扩展到嵌入。 来自relevant section of the spec:
方法是具有接收器的函数。方法声明绑定了 标识符,方法名称,方法,并将该方法关联 带有接收者的基本类型。
MethodDecl =“ func”接收器MethodName签名[FunctionBody]。
Receiver = Parameters。
接收器是通过在 方法名称。该参数部分必须声明一个非变量 参数,接收者。其类型必须为T或* T (可能使用括号),其中T是类型名称。表示的类型 用T表示的是接收方基本类型;它不能是指针或 接口类型,它必须与 方法。据说该方法绑定到基本类型和方法 名称仅在类型T或* T的选择器中可见。
方法中的非空白接收者标识符必须唯一 签名。如果没有在体内引用接收者的值 在方法中,其标识符可以在声明中省略。的 通常,这同样适用于函数和方法的参数。
对于基本类型,与其绑定的方法的非空白名称必须为 独特。如果基本类型是结构类型,则非空白方法和 字段名称必须是唯一的。
给出类型Point,声明
func (p *Point) Length() float64 { return math.Sqrt(p.x * p.x + p.y *p.y) } func (p *Point) Scale(factor float64) { p.x *= factor p.y *= factor }
将接收器类型为* Point的方法Length和Scale绑定到 基本类型Point。
方法的类型是接收者为 第一个论点。
例如,方法Scale具有类型
func(p * Point,因子float64)
但是,以这种方式声明的函数不是方法。
Man有一个名为f的字段,该字段是不带任何参数且不返回任何内容的函数。 如上所见,golang内部对待
func (p Person) printName()
为
func printName(p Person)
,并且当它对Person结构起作用时,它可以被认为是没有参数的函数(并且这样做是因为p是Person而p.printName作用于p)。因此,可以将其分配给Man.f
因此,当您将Man结构上的f字段分配给一个函数时,该函数已经捕获了名称为“ John”的Person实例并从中读取名称,因此,您将获得打印第二个“ John”的效果。 Man.name字段从未在该字段上起作用。
我怀疑通过将Person结构嵌入到Man中可以实现正常行为。
答案 1 :(得分:2)
在Go中,方法基本上是带有receiver
的函数。该接收器由编译器包装,除此之外,与普通函数没有什么不同。这意味着,无论您如何调用该方法,无论在何处,该方法总是可以获取它所绑定的接收者,将其分配给另一个变量或其他任何变量。
在您的代码中,f
不是类型Man
的方法。它只是类型func()
的字段。您可以将任何内容设置为与签名匹配的内容,并且该函数将对Man
或其实例一无所知。这意味着m.f
不了解m
,也无法访问m.name
或m
的任何其他字段。
还有一个注释,您可以调用以下方法:Person.PrintName(p)
,其中p的类型为Person
。
答案 2 :(得分:0)
函数也是一个值,它也可以作为参数传递或由其他函数分配,Golang中的方法也是一个函数,不同的是,它的接收者是它的值,因此在使用时将一个方法分配给一个具有相同签名的函数,它是指接收者,并以该方法中的代码执行目标函数