定义
方法是与对象实例绑定的特殊函数. 方法与函数定义的语法区别在于前者有前置实例接收参数, 编译器以此确定方法所属类型. 一般来说定义方式如下:
1 2 3 4 5 6 7 8
   | type structName struct{     fieldName fieldType      }
  func (receiver structName) MethodName(参数列表) (返回值列表){      }
  | 
 
特点和注意事项如下:
- 可以为当前包,已经除接口和指针以外的任何类型定义方法
 
- 方法被看作特殊的函数, 同样不支持重载, receiver 类型可以是基础类型或指针类型, 这关系到调用时对象实例是否被复制
 
- 可以使用实例值或指针值调用方法, 编译器会根据方法 receiver 类型自动在基础实例和指针类型间转换
 
- 对于结构体嵌套, 外层结构体可以直接重载或直接调用内层结构体的方法
 
示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
   | import (     "fmt" )
  type N int type S struct{     N }
  func (n N) value() {     n++     fmt.Printf("%p, %v\n", &n, n) } func (n *N) pointer() {     (*n)++     fmt.Printf("%p, %v\n", n, *n) }
  func main() {     var n N = 20     n.value()                          fmt.Printf("%p, %v\n", &n, n)      n.pointer()                        fmt.Printf("%p, %v\n", &n, n) 
      s := S{23000}     s.value()                          fmt.Printf("%p, %v\n", &s, s)      s.pointer()                        fmt.Printf("%p, %v\n", &s, s)  }
   | 
 
面向对象的三大特征 “封装”, “继承” “多态”, Go 仅实现了部分特征, 它更倾向于 “组合优于继承” 这种思想. 将模块分解成相互独立的更小单元, 分别处理不同方面的需求, 最后以匿名嵌入方式组合到一起, 共同实现对外接口. 而其简短一致的调用方式, 更是隐藏了内部实现细节.
方法转化为表达式
方法和函数一样, 除直接调用外, 还可以作为参数传递, 依照具体引用方式不同, 可以分为 expression 和 value 两种状态.
表达式类型
通过类型引用的 method expression 会被还原为普通函数样式, receiver 是第一参数, 需要显示传参. 至于类型, 可以是 T 或 *T.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | import (     "fmt" )
  type N int
  func (n N) test() {     fmt.Printf("test.n: %p, %v\n", &n, n) }
  func main() {     var n N = 25     fmt.Printf("main.n: %p, %v\n", &n, n)     f1 := N.test             f1(n)     f2 := (*N).test          f2(&n) }
 
 
 
 
   | 
 
变量类型
- 基于实例或指针引用的 method value, 依旧按照正常方式调用. 但当 method value 被赋值给变量或作为参数传递时, 会立即计算并复制该方法执行所需的 receiver 对象, 并与其绑定. 在后续调用时, 能够隐式传入 receiver 对象
 
- 如果目标方法的 receiver 是指针类型, 那么被复制的仅是指针. 会在调用时寻找该指针指向的对象, 所以传入的对象参数为调用时的上下文中的对象
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
   | import (     "fmt" )
  type N int
  func (n N) value() {     fmt.Printf("test.n: %p, %v\n", &n, n) } func (n *n) pointer(){     fmt.Printf("test.n: %p, %v\n", &n, n) }
  func main() {     var n N = 100     p := &n     n++       f1 := n.value            f3 := n.pointer          n++       f2 := p.value            f4 := m.pointer          n++       fmt.Printf("main.n: %p, %v\n", &n, n)     f1()     f3()         f2()     f4()     }
 
 
 
 
 
 
   |