这篇学习接口,接口是golang语言重要的特性之一
一、接口介绍
接口是对其它类型行为的抽象和概括,也就是方法的集合,但不用实现这些方法。
如果一个自定义类型包含了接口里面所有的方法,那么可以说这个自定义类型实现了这个接口,而且是隐式实现的
接口也是一种数据类型(指针),多态特性是通过接口来体现的
接口的作用是高内聚,低耦合
type 接口名 interface { 方法名1(参数列表) 返回值列表 方法名2(参数列表) 返回值列表 方法名3(参数列表) 返回值列表 ... }
package main import "fmt" // Hello接口 type Helloer interface { Sayhello() } // Usa结构体 type Usa struct { Name string } // Chinese结构体 type Chinese struct { Name string } func (h *Usa) Sayhello() { fmt.Println("hello") } func (c *Chinese) Sayhello() { fmt.Println("你好") } func main() { // 将Usa结构体实例赋值给hello接口类型bob var bob Helloer = &Usa{"Bob"} // 将Chinese结构体实例赋值给hello接口类型alice var alice Helloer = &Chinese{"Alice"} // 调用相同的Sayhelo方法不同的结果 bob.Sayhello() // hello alice.Sayhello() // 你好 // 不能访问字段属性,接口只关注方法 fmt.Println(bob.Name) fmt.Println(alice.Name) }
三、接口使用注意与细节
一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)覆给接口类型
package main import "fmt" type Test interface { test01() test02() } // A结构体没有实现Test结构 type A struct { } func (a A) test01() { fmt.Println("test01") } func main() { var a = A{} // 接口体实例 var t Test = a // 将结构体a赋值给接口类型t (报错, 因为a实例并没有实现Test接口,缺少test02方法,所以不能赋值) }
package main import ( "fmt" ) // 定义一个Integer接口 type Integer interface { add(x integer) integer // 声明add方法 } // 自定义类型(int别名) type integer int // 实现了Integer接口, 因为有add方法 func (i integer) add(x integer) integer { return i + x } func main() { var i, s integer = 5 fmt.Println(i.add(s)) // 10 }
package main import ( "fmt" ) // File结构体同时实现了Writer和Reader接口 type Writer interface { writer() } type Reader interface { reader() } type File struct { Name string } func (f *File) reader() { fmt.Println("读取文件: ", f.Name) } func (f *File) writer() { fmt.Println("写入文件: ", f.Name) } func main() { var w Writer = &File{"/etc/passwd"} // 写入文件: /etc/passwd var r Reader = &File{"/etc/passwd"} // 读取文件: /etc/passwd w.writer() r.reader() }
package main import ( "fmt" ) // MI和Huawei结构体实现了同一个Phoner接口 type Phoner interface { Call() Start() } // MI结构体,实现了Phoner接口 type MI struct { Name string } func (m *MI) Call() { fmt.Println("mi: Call") } func (m *MI) Start() { fmt.Println("mi: Start") } // Huawei结构体,实现了Phoner接口 type Huawei struct { Name string } func (h *Huawei) Call() { fmt.Println("huawei: Call") } func (h *Huawei) Start() { fmt.Println("huawei: Start") } func main() { var m Phoner = &MI{"mi"} var h Phoner = &Huawei{"huawei"} m.Start() m.Call() h.Start() h.Call() }
如果一个接口没有声明方法就是空接口,空接口没有初始化使用,那么它的值是nil。由于空接口没有方法,所以任何类型都实现了空接口
// 空接口,它的值是nil type Interface interface { } type Student struct { Name string } func main() { // 空接口的值默认是nil var i Interface if i == nil { fmt.Println(i) // <nil> } // 任何类型都可以实现空接口 var x Interface = &Student{"Bob"} var y Interface = &Student{"Alice"} fmt.Println(x, y) }
package main import "fmt" // A接口 type A interface { test01() } // B接口 type B interface { test02() } // 嵌入A和B接口,实现了接口继承 type C interface { A B test03() } // Test结构体,实现了C接口 type Test struct { } func (t *Test) test01() { fmt.Println("test01") } func (t *Test) test02() { fmt.Println("test02") } func (t *Test) test03() { fmt.Println("test03") } func main() { // 变量的t的类型是C接口 var t C = &Test{} // fmt.Println(t) t.test01() // test01 t.test02() // test02 t.test03() // test03 }
package main import ( "fmt" ) // Bird接口 type Bird interface { Fly() } // Fish接口 type Fish interface { Swimming() } type Monkey struct { Name string } // 继承Monkey结构体 type Little struct { Monkey } // Monkey的climbing方法 func (m *Monkey) climbing() { fmt.Println(m.Name, "生来会爬树") } // Little结构体方法,实现Bird接口(扩展) func (l *Little) Fly() { fmt.Println(l.Name, "会飞翔") } // Little结构体方法, 实现Fish接口(扩展) func (l *Little) Swimming() { fmt.Println(l.Name, "会游泳") } func main() { dasheng := &Little{Monkey{"大圣"}} // fmt.Println(dasheng.Name) dasheng.climbing() // 大圣 生来会爬树 dasheng.Fly() // 大圣 会飞翔 dasheng.Swimming() // 大圣 会游泳 }
package main import "fmt" type Animal interface{ Say() } // 实现Animal接口 type Cat struct { Name string }
// 实现Animal接口 type Dog struct { Name string } func (c *Cat) Say() { fmt.Println("喵喵") } func (d *Dog) Say() { fmt.Println("汪汪") } func say(s Animal) { s.Say() } func main() { miao := &Cat{"小猫"} dog := &Dog{"小狗"} say(miao) // 喵喵 miao是Cat类型的实例,Cat结构体实现了Animal接口,所以可以传给say函数的s参数(Animal类型) say(dog) // 汪汪 dog是Dog类型的实例,Dog结构体实现了Animal接口,所以可以传给say函数肚饿s参数(Animal类型) }
package main import "fmt" func main() { // 空接口 var i interface{} i = 10 // 谁都可以实现空接口i // fmt.Println(i) // 断言, i接口变量是int类型吗? data, ok := i.(int) if ok { fmt.Printf("data的类型为int, 值是: %v\n", data) } i = 3.14 // fmt.Println(i) // 断言, i接口变量是float64类型吗? d, isok := i.(float64) if isok { fmt.Printf("data的类型为float64, 值是: %v\n", d) } else { fmt.Println("data类型不是float64") } }
func main() { // 空接口变量a var a interface{} // Point结构体体实例point,实现了空接口a var point Point = Point{1,2} // 将point赋值给a a = point // 声明一个变量b,类型为Point var b Point // 类型断言,判断a是否为指向Point类型的变量,如果是转换成Point类型并赋给b变量,否则报错 b, ok = a.(Point) if ok { fmt.Println(b) } else { fmt.Println("error handle") } }
package main import "fmt" type Usb interface { start() stop() } type Phone struct{ Name string } type Camera struct { Name string } func (p *Phone) start() { fmt.Println(p.Name, "开始工作") } func (p *Phone) stop() { fmt.Println(p.Name, "停止工作") } func (p *Phone) call() { fmt.Println(p.Name, "打电话") } func (c *Camera) start() { fmt.Println(c.Name, "开始工作") } func (c *Camera) stop() { fmt.Println(c.Name, "停止工作") } func Working(usb Usb) { usb.start() if ob, ok := usb.(*Phone); ok { ob.call() } usb.stop() } func main() { array := [2]Usb{&Phone{"xiaomi"}, &Camera{"canon"}} for _, i := range array { // fmt.Println(i) Working(i) } }
// 自定义类型 type Student struct { Name string Age int } func CheckType(items ...interface{}) { for _, x := range items { // type是固定的写法 switch x.(type) { case int, int64: fmt.Printf("参数是int类型, 值是%v\n", x) case float64: fmt.Printf("参数是float64类型, 值是%v\n", x) case string: fmt.Printf("参数是string类型, 值是%v\n", x) case bool: fmt.Printf("参数是bool类型, 值是%v\n", x) case Student: fmt.Printf("参数是Student类型, 值是%v\n", x) case *Student: fmt.Printf("参数*Student类型, 值是%v\n", x) case nil: fmt.Printf("参数是nil类型, 值是%v\n", x) default: fmt.Printf("参数是不知道的类型, 值是%v\n", x) } } } func main() { // 可以传不同类型的参数到CheckType函数,因为CheckType函数的参数是一个空接口 CheckType(1, "abc", 3.14, true, Student{"Bob", 20}, &Student{"Alice", 30}) } // 输出 参数是int类型, 值是1 参数是string类型, 值是abc 参数是float64类型, 值是3.14 参数是bool类型, 值是true 参数是Student类型, 值是{Bob 20} 参数*Student类型, 值是&{Alice 30