这篇学习接口,接口是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