一、概述
接口类型是对 ”其他类型行为“ 的抽象和概况;因为接口类型不会和特定的实现细节绑定在一起;很多面向对象都有类似接口概念,但Golang语言中interface的独特之处在于它是满足隐形实现的。也就是说,我们没有必要对于给定的具体类型定义所有满足的接口类型;简单拥有一些必需的就ok了;
此时,我们对于interface还是比较迷茫,关键在于interface与其他具体类型(除interface之后都是具体类型)的不同之处在于,interface是抽象的;比如我们看到int类型,就知道int类型具有的算术操作;切片类型的索引操作等等;具体的类型还可以通过它的方法提供额外的行为操作;总之,当拿到一个具体的类型时,就知道它本身是什么和可以用它来做什么;
interface类型:抽象的类型,它不会暴露出它所代表的对象的内部值的结构和这个对象支持的基础操作的集合(而且它自己也没有,所以接口本身也没法展示),它只会展示出它自己的方法;
也就是说,当看到一个interface时,我们并不知道它是什么,唯一知道的就是可以通过它的方法来做什么;(这会又迷糊了...zZZ)
1 func Printf(format string, a ...interface{}) (n int, err error){ 2 return Fprintf(os.Stdout, format, a...) 3 } 4 5 func Sprintf(format string, args ...interface{}) string{ 6 var buf bytes.Buffer 7 Fprintf(&buf, format, args...) 8 return buf.String() 9 } 10 11 func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error){ 12 ... 13 }
关键点在于:第2行,第7行中调用Fprintf()函数时,传递的第一个参数;
第2行实参: os.Stdout 是*os.File类型
第7行实参: buf 是bytes.Buffer类型
而实现函数的形参是io.Writer类型,是interface类型
1 package io 2 // Writer is the interface that wraps the basic Write method. 3 type Writer interface { 4 // Write writes len(p) bytes from p to the underlying data stream. 5 // It returns the number of bytes written from p (0 <= n <= len(p)) 6 // and any error encountered that caused the write to stop early. 7 // Write must return a non-nil error if it returns n < len(p). 8 // Write must not modify the slice data, even temporarily. 9 // 10 // Implementations must not retain p. 11 Write(p []byte) (n int, err error) 12 }
此时就将interface的意义展示的淋漓尽致了;
interface(io.Write) 定义了函数Fprintf和该函数的调用者之间的约定:
- 对调用者的约束:实参必须有一个特定的签名和提供一个Write函数
- 对函数的约束: Fprintf接受任何满足io.Writer接口的参数都可以正常工作
一个类型(形参)可以自由的使用另一个满足相同接口的类型(实参)来进行替换被称为可替代性(LSP里氏替换) —— c++的多态
1 package main 2 3 import "fmt" 4 5 type Msg struct { 6 Id int 7 Name string 8 } 9 10 func (this *Msg) Write(p []byte) (int, error) { 11 this.Id += int(len(p)) 12 this.Name = "interface" 13 return this.Id, nil 14 } 15 16 func main() { 17 msg := new(Msg) 18 msg.Id = 100 19 msg.Name = "interface test print" 20 21 var name = "Dolly" 22 fmt.Fprintf(msg, "%s", name) //convert msg, call Write(my func) 23 fmt.Println(msg) //stdout 24 }
调用fmt.Fprintf函数,第一个参数传入自定义的参数,该参数必须实现Write函数,否则编译报错;
二、接口类型
接口类型具体描述了一系列方法的集合,一个实现了这些方法的具体类型称为该接口的实例;