上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
6.2 方法集
类型有个与之相关的方法集合(method set),这决定了它是否实现某个接口。
根据接收参数(receiver)的不同,可分为 T
和 *T
两种视角。
T.set = T
*T.set = T + *T
type T int func (T) A() {} // 导出成员,否则反射无法获取。 func (T) B() {} func (*T) C() {} func (*T) D() {} // ----------------------------- func show(i interface{}) { t := reflect.TypeOf(i) for i := 0; i < t.NumMethod(); i++ { println(t.Method(i).Name) } } func main() { var n T = 1 var p *T = &n show(n) // T = [A, B] println("---") show(p) // *T = [A, B, C, D] }
直接方法调用,不涉及方法集。编译器自动转换所需参数(receiver)。
而转换(赋值)接口(interface)时,须检查方法集是否完全实现接口声明。
type Xer interface { B() C() } // ----------------------------- func main() { var n T = 1 // 方法调用:不涉及方法集。 n.B() n.C() // 接口:检查方法集。 // var x Xer = n // ~ T does not implement Xer (C method has pointer receiver) var x Xer = &n x.B() x.C() }
首先,接口会复制对象,且复制品 不能寻址 (unaddressable)。
如
T
实现接口,透过接口调用时,receiver
可被复制,却不能获取指针(&T
)。相反,
*T
实现接口,目标对象在接口以外,无论是取值还是复制指针都没问题。这就是方法集与接口相关,且
T = T
,*T = T + *T
的原因。
除直属方法外,列表里还包括匿名类型( E
)的方法。
T{ E } = T + E
T{ *E } = T + E + *E
*T{ E | *E } = T + *T + E + *E
type E int func (E) V() {} func (*E) P() {} // ----------------------------- func show(i interface{}) { t := reflect.TypeOf(i) for i := 0; i < t.NumMethod(); i++ { println(" ", t.Method(i).Name) } } func main() { println("T{ E }") show(struct{ E }{}) println("T{ *E }") show(struct{ *E }{}) println("*T{ E }") show(&struct{ E }{}) println("*T{ *E }") show(&struct{ *E }{}) } // T{ E }: V // T{ *E }: P, V // *T{ E }: P, V // *T{ *E }: P, V
别名扩展
通过类型别名,对方法集进行分类,更便于维护。或新增别名,为类型添加扩展方法。
type X int func (*X) A() { println("X.A") } type Y = X // 别名 func (*Y) B() { println("Y.B") } // 扩展方法 func main() { var x X x.A() x.B() var y Y y.A() y.B() }
通过反射,可以看到 “扩展” 被合并的效果。
func main() { var n X t := reflect.TypeOf(&n) for i := 0; i < t.NumMethod(); i++ { fmt.Println(t.Method(i)) } } // A: func(*main.X) // B: func(*main.X)
需要注意,不同包的类型可定义别名,但不能定义方法。
type X = bytes.Buffer // func (*X) B() { println("X.b") } // ~~ cannot define new methods on non-local type
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论