10.1 接口
接口用于实现面向对象中的多态。
接口也是可以嵌套的。
一个接口是很多个方法的集合,但是这些方法不用实现,由实现这个接口的类型去实现。
也就是说,实现了接口里的全部方法,也就实现了这个接口。
下面声明了一个Man接口,man结构体类型实现了Man的全部方法,也就是man实现了接口Man。
package main
import "fmt"
//定义一个Man接口,有两个方法,run和sing
type Man interface {
run()
sing()
}
//man结构体
type man struct {
}
//实现run方法
func (m *man) run() {
fmt.Println("我是双脚走的")
}
//实现sing方法
func (m *man) sing() {
fmt.Println("我用嘴唱歌")
}
func main() {
var me Man //声明接口
var m1 man //声明结构体
me = &m1 //结构体变量赋值给接口
me.run()
me.sing()
}
有什么用呢?这里完全可以不用接口啊,直接用结构体调用方法就可以。
var m1 man
m1.run()
m1.sing()
但是,如果还有其他类型,其他结构体也实现了这个接口,但是不一样的实现。此时,如果调用方法,就是有多少个结构体,就要调用多少次run方法。
var m1 man
m1.run()
m1.sing()
var m2 woman
m2.run()
m2.sing()
......
接口的作用就体现出来了,比如上述的例子,还有一个woman结构体也实现了接口,那么,想要它们调用同一个函数时,有不一样的输出,就是接口的作用,多态。
package main
import "fmt"
//定义一个Man接口,有两个方法,run和sing
type Man interface {
run()
sing()
}
//man结构体
type man struct {
}
//实现run方法
func (m *man) run() {
fmt.Println("我是双脚走的")
}
//实现sing方法
func (m *man) sing() {
fmt.Println("我用嘴唱歌")
}
type woman struct {
}
//实现run方法
func (m *woman) run() {
fmt.Println("我是单脚走的")
}
//实现sing方法
func (m *woman) sing() {
fmt.Println("我不用嘴唱歌")
}
func Run(p Man) {
p.run()
p.sing()
}
func main() {
Run(&man{}) //同时调用Run方法
Run(&woman{}) //各自输出
}
再来一个直观点的例子:
一个Dog接口,两个结构体jinmao和chaiquan,都实现了接口Dog,在add函数种,接收参数类型是接口,然后不同的接口变量调用同一个getage()函数,得到不一样的age,而不用写两遍。这里如果是成千上万个用户,那么效果更加明显,如果没有接口,那么就需要调用成千上万次getage()。
package main
import "fmt"
type Dog interface {
getage() int
}
type jinmao struct{ age int }
type chaiquan struct{ age int }
func (j jinmao) getage() int {
return j.age
}
func (c chaiquan) getage() int {
return c.age
}
func add(s []Dog) {
var sum int
for _, i := range s {
sum += i.getage() //接口的真正意义
}
fmt.Println(sum)
}
func main() {
jj := jinmao{1}
cc := chaiquan{2}
sdog := []Dog{jj, cc}
add(sdog)
}
10.2 类型断言
如何检测和转换接口变量的类型?一个接口类型的变量可以包含任意类型的值,必须有一种方式来检测它的到动态类型,即运行时在变量中存储的值的实际类型。利用类型断言来测试某个时刻接口变量是否包含某个类型的值:
if v, ok := vari.(*T); ok {
fmt.Printf("变量var1的类型为: %T", v)
} else {
fmt.Println("变量var1不包含类型: ", v)
}
例子:
package main
import "fmt"
//定义一个Man接口
type Man interface {
run()
}
//man结构体
type man struct {
name string
age int
}
//实现run方法
func (m *man) run() {
fmt.Println("我是双脚走的")
}
type woman struct {
}
//实现run方法
func (m *woman) run() {
fmt.Println("我是单脚走的")
}
func main() {
var vari Man
man1 := man{}
vari = &man1
if v, ok := vari.(*man); ok {
fmt.Printf("变量var1的类型为: %T", v) //*main.man
} else {
fmt.Println("变量var1不包含类型: ", v)
}
if u, ok := vari.(*woman); ok {
fmt.Printf("变量var1的类型为: %T", u)
} else {
fmt.Printf("变量var1不包含类型: %T", u) //*main.woman
}
}
10.3 类型判断:type-swith
接口变量的类型也可以使用一种特殊形式的switch来检测,不用if来判断:
package main
import (
"fmt"
)
//定义一个Man接口
type Man interface {
run()
}
//man结构体
type man struct {
name string
age int
}
//实现run方法
func (m *man) run() {
fmt.Println("我是双脚走的")
}
type woman struct {
}
//实现run方法
func (m *woman) run() {
fmt.Println("我是单脚走的")
}
func main() {
var vari Man
man1 := man{}
vari = &man1
switch t := vari.(type) {
case *man:
fmt.Printf("类型%T,值为%v", t, t) //类型*main.man,值为&{ 0}
case *woman:
fmt.Printf("类型%T,值为%v", t, t)
case nil:
fmt.Printf("nil 值")
default:
fmt.Println("未知类型")
}
}
接口的不写了,没搞懂………