定义
方法是与对象实例绑定的特殊函数. 方法与函数定义的语法区别在于前者有前置实例接收参数, 编译器以此确定方法所属类型. 一般来说定义方式如下:
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() }
|