[Go] 通过反射判断类型实现的接口方法是值接收器还是指针接收器
最近有一个需求需要检验 Go 语言的接口方式是值接收器(Value Receiver)方法还是指针接收器(Pointer Receiver)方法。貌似 Go 没有直接提供的方式,所以需要手动实现。
Go 语言里面,值类型T
和对应的指针类型*T
有着不同的方法集。T
是所有值接收器方法的集合,而*T
是所有值接收器方法和所有指针接收器方法的集合。
获取类型的两种方法集
如果有以下的类型:
type S struct{}
func (s S) A() {}
func (s *S) B() {}
则可以通过如下的反射代码来分别获取T
和*T
类型的方法集:
func main() {
t := reflect.TypeOf(S{})
for i := 0; i < t.NumMethod(); i++ {
m := t.Method(i)
fmt.Println("Value method:", m.Name)
}
fmt.Println()
t = reflect.PtrTo(t)
for i := 0; i < t.NumMethod(); i++ {
m := t.Method(i)
fmt.Println("Pointer method:", m.Name)
}
}
以上代码会输出:
$ go run s.go
Value method: A
Pointer method: A
Pointer method: B
可以看到,值类型T
只有值接收器方法,而指针类型*T
同时有值接收器方法和指针接收器方法。
所以总结一下:
- 如果一个方法仅出现在指针类型的方法集中,那么它是指针接收器
- 如果一个方法同时出现在指针类型和值类型的方法集中,那么它是值接收器
通过反射判断方法是值接收器还是指针接收器
首先定义两个接口:
type IA interface {
A()
}
type IB interface {
B()
}
结构体还是上面代码的S
结构体。
可以通过编写如下代码在运行时判断接收器的类型:
func main() {
// 拿到两种接口的反射类型信息
tia := reflect.TypeOf((*IA)(nil)).Elem()
tib := reflect.TypeOf((*IB)(nil)).Elem()
t := reflect.TypeOf(S{})
// 如果指针类型实现了...
if reflect.PtrTo(t).Implements(tia) {
// 并且值类型也实现了 ...
if t.Implements(tia) {
fmt.Println("A is value receiver")
} else {
fmt.Println("A is pointer receiver")
}
}
// 如果指针类型实现了...
if reflect.PtrTo(t).Implements(tib) {
// 并且值类型也实现了 ...
if t.Implements(tib) {
fmt.Println("B is value receiver")
} else {
fmt.Println("B is pointer receiver")
}
}
}
上面的代码将输出:
$ go run s.go
A is value receiver
B is pointer receiver