1. 表达式

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

  1. instance.method(args...) ---> <type>.func(instance, args...)

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

两者都可像普通函数那样赋值和传参,区别在于 method value 绑定实例,而 method expression 则须显式传参。

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

输出结果:

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

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

  1. package main
  2. import "fmt"
  3. type User struct {
  4. id int
  5. name string
  6. }
  7. func (self User) Test() {
  8. fmt.Println(self)
  9. }
  10. func main() {
  11. u := User{1, "Tom"}
  12. mValue := u.Test // 立即复制 receiver,因为不是指针类型,不受后续修改影响。
  13. u.id, u.name = 2, "Jack"
  14. u.Test()
  15. mValue()
  16. }

输出结果

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

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

  1. FuncVal { method_address, receiver_copy }

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

  1. package main
  2. import "fmt"
  3. type User struct {
  4. id int
  5. name string
  6. }
  7. func (self *User) TestPointer() {
  8. fmt.Printf("TestPointer: %p, %v\n", self, self)
  9. }
  10. func (self User) TestValue() {
  11. fmt.Printf("TestValue: %p, %v\n", &self, self)
  12. }
  13. func main() {
  14. u := User{1, "Tom"}
  15. fmt.Printf("User: %p, %v\n", &u, u)
  16. mv := User.TestValue
  17. mv(u)
  18. mp := (*User).TestPointer
  19. mp(&u)
  20. mp2 := (*User).TestValue // *User 方法集包含 TestValue。签名变为 func TestValue(self *User)。实际依然是 receiver value copy。
  21. mp2(&u)
  22. }

输出:

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

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

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