接口是双方约定的一种合作协议。接口实现者不需要关心接口会被怎样使用,调用者也不需要关心接口的实现细节。
接口是一种类型,也是一种抽象结构,不会暴露所含数据的格式、类型及结构。
声明:
接口类型是由一组方法签名定义的集合
type 接口类型名 interface{
方法名1( 参数列表1 ) 返回值列表1
方法名2( 参数列表2 ) 返回值列表2
…
}
type Goer interface { write() (int,error) Read() error }
var 接口名 接口类型名
var goer Goer
接口本身包含两个数据(值,类型),只有当两者都是nil时才为接口值才为nil
实现:
接口类型的变量可以保存任何实现了这些方法的值。
要求:
接口的方法与实现接口的类型方法格式一致
接口中所有方法均被实现
type Goer interface { write() float64 } func main() { var goer Goer v := Vertex{3, 4} f := MyFloat(-3.14) //goer=v //编译错误,没有v Vertex的对应方法 goer = &v fmt.Println(goer.write()) goer = f fmt.Println(goer.write()) } type MyFloat float64 func (f MyFloat) write() float64 { if f < 0 { return float64(-f) } return float64(f) } type Vertex struct { X, Y float64 } func (v *Vertex) write() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) }
运行结果:
5
3.14
类型和接口之间有一对多和多对一的关系,一个类型可以同时实现多个接口,而接口间彼此独立,不知道对方的实现,同时一个接口的方法,不一定需要由一个类型完全实现,接口的方法可以通过在类型中嵌入其他类型或者结构体来实现
空接口:
指定了零个方法的接口值被称为空接口
由于每个类型的方法都至少实现了0种,所以不用指定方法,可以用来保存任何类型的值或者处理未知类型的值
interface{}
var a interface{}
例子:
func main() { var i interface{} describe(i) i = 42 describe(i) i = "hello" describe(i) } func describe(i interface{}) { fmt.Printf("(%v, %T)\n", i, i) }
输出结果:
(<nil>, <nil>)
(42, int)
(hello, string)
函数接口:
除了结构体和类型能实现接口,函数类型也可以实现接口
// 调用器接口 type Invoker interface { // 需要实现一个Call方法 Call(interface{}) } // 函数定义为类型 type FuncCaller func(interface{}) // 实现Invoker的Call func (f FuncCaller) Call(p interface{}) { // 调用f函数本体 f(p) } func main() { // 声明接口变量 var invoker Invoker // 将匿名函数转为FuncCaller类型,再赋值给接口 invoker = FuncCaller(func(v interface{}) { fmt.Println("from function", v) }) // 使用接口调用FuncCaller.Call,内部会调用函数本体 invoker.Call("hello") }
运行结果:
from function hello