1. 表达式

    Golang 表达式 :根据调用者不同,方法分为两种表现形式:

    前者称为 method value,后者 method expression。

    1. import "fmt"
    2. type User struct {
    3. id int
    4. name string
    5. }
    6. func (self *User) Test() {
    7. fmt.Printf("%p, %v\n", self, self)
    8. }
    9. func main() {
    10. u := User{1, "Tom"}
    11. u.Test()
    12. mValue() // 隐式传递 receiver
    13. mExpression := (*User).Test
    14. mExpression(&u) // 显式传递 receiver
    15. }

    输出结果:

    1. 0xc42000a060, &{1 Tom}
    2. 0xc42000a060, &{1 Tom}
    3. 0xc42000a060, &{1 Tom}

    需要注意,method value 会复制 receiver。

    1. {2 Jack}
    2. {1 Tom}

    在汇编层面,method value 和闭包的实现方式相同,实际返回 FuncVal 类型对象。

    1. FuncVal { method_address, receiver_copy }

    可依据方法集转换 method expression,注意 receiver 类型的差异。

    1. User: 0xc42000a060, {1 Tom}
    2. TestValue: 0xc42000a0a0, {1 Tom}
    3. TestPointer: 0xc42000a060, &{1 Tom}
    4. TestValue: 0xc42000a100, {1 Tom}

    将方法 "还原" 成函数,就容易理解下面的代码了。

    1. package main
    2. func (Data) TestValue() {}
    3. func (*Data) TestPointer() {}
    4. func main() {
    5. var p *Data = nil
    6. p.TestPointer()
    7. (*Data)(nil).TestPointer() // method value
    8. (*Data).TestPointer(nil) // method expression
    9. // p.TestValue() // invalid memory address or nil pointer dereference
    10. // (Data)(nil).TestValue() // cannot convert nil to type Data
    11. }