这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战
interface
接口是一种数据类型, Go语言中的所有类型都默认实现了空接口, 因此, 一个空接口类型的变量可以存储任意类型的值
一个接口类型的变量, 零值为nil
定义一个接口变量
// 定义一个接口类型的变量
var i interface{};
// 接口类型变量的零值为nil
fmt.Printf("%#v \n", i)
// 一个接口类型的变量, 可以存储任何类型的值
// 存储整型
i = 3
fmt.Println("类型: ", reflect.TypeOf(i), "值: ", i)
// 存储浮点型
i = 3.14
fmt.Println("类型: ", reflect.TypeOf(i), "值: ", i)
// 存储字符串
i = "hi, shaosiming"
fmt.Println("类型: ", reflect.TypeOf(i), "值: ", i)
// 存储结构体
type Person struct {
name string
age int
}
i = Person{name: "shaosiming", age: 18}
fmt.Println("类型: ", reflect.TypeOf(i), "值: ", i)
使用接口中的方法
// 创建一个老师, 并调用它的方法
t := Teacher{"shaosiming"}
t.eat()
t.sleep()
// 创建一个学生, 并调用它的方法
s := Student{"yuer"}
s.eat()
s.sleep()
// 声明一个接口类型, 并为它赋值
var p Personer
fmt.Println("为接口变量赋值老师结构体")
p = t
p.eat()
p.sleep()
p = s
fmt.Println("为接口变量赋值学生结构体")
p.eat()
p.sleep()
接口的嵌入
// 接口的嵌入
type Reader interface {
read()
}
type Writer interface {
write()
}
// 一个接口可以嵌入另一个接口, 只需要实现另一个接口中的所有方法
type IoOperater interface {
Reader
Writer
open()
close()
}
类型断言
/*
我们可以把老师或者学生结构体类型的变量赋值给Personer接口类型的变量
那么通过Personer接口类型的变量, 如何知道具体的变量类型, 类型断言来干这个事情
*/
value, ok := p.(Teacher)
// 如果ok为false, 则说明断言失败
if ok {
fmt.Println("p中存储的数据类型为老师类型: ", value)
}
value2, ok := p.(Student)
// 如果ok为true, 则说明断言成功, value2则为转换成功后的Student类型的值
if ok {
fmt.Println("p中存储的数据类型为学生类型: ", value2)
}
// 使用switch语句断言
var value3 interface{} = p
switch str := value3.(type) {
case Student:
fmt.Println("p类型为学生类型: ", str)
case Teacher:
fmt.Println("p类型为老师类型: ", str)
default:
fmt.Println("我也不知道什么类型了")
}
类型检查
// 类型检查
var value4 interface{} = t
value5, ok := value4.(Teacher)
if ok {
fmt.Printf("value类型断言结果为:%T\n", value5)
} else {
fmt.Printf("value不是Teacher类型 \n")
}
接口的继承
// 接口的继承, 一个接口可以包含其它多个接口, 实现多重继承
type MyReaderWriter interface {
io.Reader
io.Writer
io.Closer
}
总结
任何类型如果实现了某个接口中的所有方法, 也就隐式实现了这个接口
Go中的接口降低了代码的耦合度, 改善了代码的复用性, 可以让我们设计出更优秀的架构
Go中没有类的概念, 因此不需要维护传统的面向对象语言中类的层次结构
Go中的接口包罗万象, 灵活使用接口这个类型, 相信可以写出更优雅的Go代码!!!