18 接口-实现方法集合

.container .card .information strong · · 204 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

本文视频地址

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 自定义类型的别名类型则没有“继承”原类型的方法集合,别名类型的方法集合是空的。

image


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:.container .card .information strong

查看原文:18 接口-实现方法集合

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

204 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传