共计 2411 个字符,预计需要花费 7 分钟才能阅读完成。
本文视频地址
1. 办法汇合
func ShowMethod(i interface{}) {v := reflect.TypeOf(i)
elemTyp := v.Elem()
n := elemTyp.NumMethod()
if n == 0 {fmt.Printf("%s's 办法为空!\n", elemTyp)
return
}
fmt.Printf("%s's 办法:\n", elemTyp)
for j := 0; j < n; j++ {fmt.Println("-", elemTyp.Method(j).Name)
}
fmt.Printf("\n")
}
type Interface interface {X1()
X2()}
type T struct{}
func (t T) X1() {}
func (t *T) X2() {}
func main() {
var t T
var pt *T
ShowMethod(&t)
ShowMethod(&pt)
ShowMethod((*Interface)(nil))
}
输入如下
main.T’s 办法:
- X1
*main.T’s 办法:
- X1
- X2
main.Interface’s 办法:
- X1
- X2
能够看到
1 T 类型的办法集中只有 X1, 无奈成为与 Interface 类型的办法解的超集
2 T 类型的办法汇合是 X1,X2, T 没有间接实现 X1, 但 X1 依然是 T 类型的办法合集中。这合乎 Go 的标准:类型 T 的办法汇合蕴含所有接收者为 T 和 * T 类型的办法。因而,pt 能力赋值给 Interface 类型变量。
接收者抉择类型时须要思考的要点
1 是否反对将 T 类型实例赋值给某个接口类型变量。
2 如果须要反对,就要实现接收者为 T 类型的接口类型办法汇合中的所有办法。
2. 类型嵌入与办法汇合
1) 接口类型中嵌入接口类型
// $GOROOT/src/io/io.go
type Reader interface {Read(p []byte) (n int, err error)
}
type Writer interface {Write(p []byte) (n int, err error)
}
type Closer interface {Close() error
}
以上为三个根本接口类型
上面的接口类型通过嵌入下面根本接口类型而造成
type ReadWriter interface {
Reader
Writer
}
type ReadCloser interface {
Reader
Closer
}
type WriteCloser interface {
Writer
Closer
}
type ReadWriteCloser interface {
Reader
Writer
Closer
}
func main() {ShowMethod((*io.Writer)(nil))
ShowMethod((*io.Reader)(nil))
ShowMethod((*io.Closer)(nil))
ShowMethod((*io.ReadWriter)(nil))
ShowMethod((*io.ReadWriteCloser)(nil))
}
io.Writer’s 办法:
- Write
io.Reader’s 办法:
- Read
io.Closer’s 办法:
- Close
io.ReadWriter’s 办法:
- Read
- Write
io.ReadWriteCloser’s 办法:
- Close
- Read
- Write
通过嵌入其余接口而生成的新接口类型 ReadWriteCloser 的办法汇合蕴含了被嵌套接口类型 io.Reader 的办法汇合。
注:当被嵌入接口有名字反复的时候,新的接口会报错。
2) 构造体类型中嵌入接口类型
在构造体类型中嵌入接口类型后,该构造体类型的办法汇合中将蕴含被嵌入的接口类型的办法汇合。
func main() {ShowMethod((*Interface)(nil))
var t T
var pt *T
ShowMethod(&t)
ShowMethod(&pt)
}
main.Interface's 办法:
- X1
- X2
main.T's 办法:
- X1
- X3
*main.T's 办法:
- X1
- X2
- X3
a@adeiMac panic_demo % clear
a@adeiMac panic_demo % go run main.go
main.Interface's 办法:
- X1
- X2
main.T's 办法:
- X1
- X3
*main.T's 办法:
- X1
- X2
- X3
这个后果和咱们预期统一。当多个接口类型且这些接口类型的办法汇合存在交加的时候,嵌入了其余接口类型的解构体类型的实例在调用办法时,Go 抉择办法秩序:
1 优先选择构造体本身实现的办法;
2 如果构造体本身并未实现,将查找构造体中的嵌入解构类型的办法集中是否有该办法,如果有,则晋升为构造体的办法。
当多个接口蕴含雷同办法的时候,当调用的时候会报错,
说不明确的调用。
3. 类型别名的办法汇合
type T struct{}
func (T) X1() {}
func (*T) X2() {}
type Interface interface {X1()
X2()}
type T1 T
type Interface1 Interface
func main() {
var t T
var pt *T
var t1 T1
var pt1 *T1
ShowMethod(&t)
ShowMethod(&t1)
ShowMethod(&pt)
ShowMethod(&pt1)
ShowMethod((*Interface)(nil))
ShowMethod((*Interface1)(nil))
}
输入如下:main.T's 办法:
- X1
main.T1's 办法为空!
*main.T's 办法:
- X1
- X2
*main.T1's 办法为空!
main.Interface's 办法:
- X1
- X2
main.Interface1's 办法:
- X1
- X2
从下面后果看:
1 解构类型的别名类型与原来接口类型的办法汇合是统一的,如下面 Interface 和 Interface1
2 自定义类型的别名类型则没有“继承”原类型的办法汇合,别名类型的办法汇合是空的。