本文视频地址

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.gotype 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- X2main.T's 办法:- X1- X3*main.T's 办法:- X1- X2- X3a@adeiMac panic_demo % cleara@adeiMac panic_demo % go run main.gomain.Interface's 办法:- X1- X2main.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 Ttype Interface1 Interfacefunc 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 办法:- X1main.T1's 办法为空!*main.T's 办法:- X1- X2*main.T1's 办法为空!main.Interface's 办法:- X1- X2main.Interface1's 办法:- X1- X2

从下面后果看:
1 解构类型的别名类型与原来接口类型的办法汇合是统一的,如下面 Interface 和 Interface1
2 自定义类型的别名类型则没有“继承”原类型的办法汇合,别名类型的办法汇合是空的。