141 lines
3.2 KiB
Markdown
141 lines
3.2 KiB
Markdown
|
### 多个嵌入方式
|
|||
|
- 接口嵌入
|
|||
|
- 结构体嵌入
|
|||
|
|
|||
|
### 嵌入总结
|
|||
|
- 结构体类型的方法集合包含嵌入的接口类型的方法集合
|
|||
|
- 当结构体类型 T 包含嵌入字段 E 时,*T 的方法集合不仅包含类型 E 的方法集合,还要包含类型 *E 的方法集合
|
|||
|
- 基于非接口类型的 defined 类型创建的新 defined 类型不会继承原类型的方法集合
|
|||
|
- 通过类型别名定义的新类型则和原类型拥有相同的方法集合
|
|||
|
|
|||
|
### 接口嵌入
|
|||
|
- 接口就是一个方法集合
|
|||
|
- 新接口类型(如接口类型 I)将嵌入的接口类型(如接口类型 E)的方法集合,并入到自己的方法集合中
|
|||
|
- 在 Go 1.14 版本之前是有约束的:如果新接口类型嵌入了多个接口类型,这些嵌入的接口类型的方法集合不能有交集,同时嵌入的接口类型的方法集合中的方法名字,也不能与新接口中的其他方法同名
|
|||
|
```go
|
|||
|
type I interface {
|
|||
|
M1()
|
|||
|
M2()
|
|||
|
M3()
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
type I interface {
|
|||
|
E
|
|||
|
M3()
|
|||
|
}
|
|||
|
```
|
|||
|
- 以某个类型名、类型的指针类型名或接口类型名,直接作为结构体字段的方式就叫做结构体的类型嵌入,这些字段也被叫做嵌入字段(Embedded Field)
|
|||
|
- 结构体可以嵌入结构体和接口类型
|
|||
|
- 嵌入字段类型的底层类型不能为指针类型
|
|||
|
- 嵌入字段的名字在结构体定义也必须是唯一的,如果两个类型的名字相同,它们无法同时作为嵌入字段放到同一个结构体定义中
|
|||
|
### 结构体嵌入
|
|||
|
```go
|
|||
|
type T1 int
|
|||
|
type t2 struct{
|
|||
|
n int
|
|||
|
m int
|
|||
|
}
|
|||
|
|
|||
|
type I interface {
|
|||
|
M1()
|
|||
|
}
|
|||
|
|
|||
|
type S1 struct {
|
|||
|
T1
|
|||
|
*t2
|
|||
|
I
|
|||
|
a int
|
|||
|
b string
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
### 嵌入后方法集合
|
|||
|
- 结构体类型的方法集合,包含嵌入的接口类型的方法集合
|
|||
|
```go
|
|||
|
|
|||
|
type I interface {
|
|||
|
M1()
|
|||
|
M2()
|
|||
|
}
|
|||
|
|
|||
|
type T struct {
|
|||
|
I
|
|||
|
}
|
|||
|
|
|||
|
func (T) M3() {}
|
|||
|
|
|||
|
func main() {
|
|||
|
var t T
|
|||
|
var p *T
|
|||
|
dumpMethodSet(t)
|
|||
|
dumpMethodSet(p)
|
|||
|
}
|
|||
|
|
|||
|
main.T's method set:
|
|||
|
- M1
|
|||
|
- M2
|
|||
|
- M3
|
|||
|
|
|||
|
*main.T's method set:
|
|||
|
- M1
|
|||
|
- M2
|
|||
|
- M3
|
|||
|
```
|
|||
|
|
|||
|
- 嵌入了其他类型的结构体类型本身是一个代理
|
|||
|
- 调用其实例所代理的方法时,Go 会首先查看结构体自身是否实现了该方法
|
|||
|
- 如果实现方法了,Go 就会优先使用结构体自己实现的方法
|
|||
|
- 如果没有实现,那么 Go 就会查找结构体中的嵌入字段的方法集合中,是否包含了这个方法
|
|||
|
- 如果多个嵌入字段的方法集合中都包含这个方法,那么方法集合存在交集。Go 编译器就会因无法确定究竟使用哪个方法而报错
|
|||
|
- 去掉因嵌入造成的交集的方法或者结构体自身实现交集的方法
|
|||
|
```go
|
|||
|
type E1 interface {
|
|||
|
M1()
|
|||
|
M2()
|
|||
|
M3()
|
|||
|
}
|
|||
|
|
|||
|
type E2 interface {
|
|||
|
M1()
|
|||
|
M2()
|
|||
|
M4()
|
|||
|
}
|
|||
|
|
|||
|
type T struct {
|
|||
|
E1
|
|||
|
E2
|
|||
|
}
|
|||
|
|
|||
|
func main() {
|
|||
|
t := T{}
|
|||
|
t.M1()
|
|||
|
t.M2()
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
### 打印一个interface的方法集合
|
|||
|
```go
|
|||
|
func dumpMethodSet(i interface{}) {
|
|||
|
dynTyp := reflect.TypeOf(i)
|
|||
|
|
|||
|
if dynTyp == nil {
|
|||
|
fmt.Printf("there is no dynamic type\n")
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
n := dynTyp.NumMethod()
|
|||
|
if n == 0 {
|
|||
|
fmt.Printf("%s's method set is empty!\n", dynTyp)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
fmt.Printf("%s's method set:\n", dynTyp)
|
|||
|
for j := 0; j < n; j++ {
|
|||
|
fmt.Println("-", dynTyp.Method(j).Name)
|
|||
|
}
|
|||
|
fmt.Printf("\n")
|
|||
|
}
|
|||
|
|
|||
|
```
|