Go 中的方法

定义
方法和函数定义语法区别在于前者有实例接收参数,编译器以此确定方法所属类别。在某些语言里,尽管没有显示定义,但会在调用时隐式传递 this 实例参数。
方法集
类型有一个与之相关的方法集,这决定了它是否实现某个接口。

  • 类型 T 方法集包含所有 receiver T 方法。
  • 类型 *T 方法集包含所有 receiver T + *T 方法。
  • 匿名嵌入 S,T 方法集包含了所有 receiver S 方法。
  • 匿名嵌入 *S,T 方法集包含了所有 receiver S + *S 方法。
  • 匿名嵌入 S 或 *S,*T 方法集包含了所有 receiver S + *S 方法。
    可利用反射测试这些规则。
package main

import (
	"fmt"
	"reflect"
)

type S struct {}

type T struct {
	S
}

func (S) SVal ()  {}

func (*S) SPtr ()  {}

func (T) TVal ()  {}

func (*T) TPtr ()  {}

func methodSet(s interface{})  {
	t := reflect.TypeOf(s)
	for i := 0; i < t.NumMethod(); i++ {
		m := t.Method(i)
		fmt.Println(m.Name, m.Type)
	}

}

func main()  {
	var t T
	methodSet(t)
	fmt.Println("------------")
	methodSet(&t)
}

面向对象的三大特征“封装”、“集成”和“多态”,Go 仅实现了部分特征,它更倾向于 “组合优于继承”这种思想。将模块分解成相互独立的更小单元,分别处理不同方面的需求,最后以匿名方式组合到一起,共同实现对外接口。而且其剪短一致的调用方式,更是隐藏了内部实现细节。
表达式

package main

import "fmt"

type N int

func (n N) test()  {
	fmt.Printf("test.n: %p, %d\n", &n, n)
}

func main()  {
	var n N = 25
	fmt.Printf("main.n: %p, %d\n", &n, n)

	f1 := N.test
	f1(n)

	f2 := (*N).test
	f2(&n)

}

其输出为:
main.n: 0xc000094000, 25
test.n: 0xc000018078, 25
test.n: 0xc000094018, 25
尽管 *N 方法集包装的 test 方法 receiver 类型不同,但编译器会保证按原定义类型拷贝传值。
基于实例或指针引用的 method value,参数签名不会改变,依旧按照正常方式调用。
但当 method value 被赋值给变量或作为参数传递时,会立即计算并复制该方法执行所需要的 receiver 对象,与其绑定,以便在稍后执行时,能隐式传入 receiver 参数。

package main

import "fmt"

type N int

func (n N) test()  {
	fmt.Printf("test.n: %p, %v\n", &n, n)
}

func main()  {
	var n N = 100
	p := &n

	n++
	f1 := n.test   // 因为 test 方法的 receiver 是 N 类型,索引复制n,其等于 101

	n++
	f2 := p.test   // 复制 *p, 等于 102

	n++
	fmt.Printf("main.n: %p, %v\n", p, n)

	f1()
	f2()
}

其输出为:
main.n: 0xc000018070, 103
test.n: 0xc00009e000, 101
test.n: 0xc000018088, 102
当然,如果目标方法的 receiver 是指针类型,那么被复制的仅是指针。

package main

import "fmt"

type N int

func (n *N) test()  {
	fmt.Printf("test.n: %p, %v\n", n, *n)
}

func main()  {
	var n N = 100
	p := &n

	n++
	f1 := n.test        // 因为 test 方法的 receiver 是 *N 类型,所以复制的是 &n

	n++
	f2 := p.test       // 复制 p 指针

	n++
	fmt.Printf("main.n: %p, %v\n",p, n)

	f1()
	f2()

}

其输出为:
main.n: 0xc000018078, 103
test.n: 0xc000018078, 103
test.n: 0xc000018078, 103

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值