10.1 接口

接口用于实现面向对象中的多态。
接口也是可以嵌套的。
一个接口是很多个方法的集合,但是这些方法不用实现,由实现这个接口的类型去实现。
也就是说,实现了接口里的全部方法,也就实现了这个接口。
下面声明了一个Man接口,man结构体类型实现了Man的全部方法,也就是man实现了接口Man。

  1. package main
  2. import "fmt"
  3. //定义一个Man接口,有两个方法,run和sing
  4. type Man interface {
  5. run()
  6. sing()
  7. }
  8. //man结构体
  9. type man struct {
  10. }
  11. //实现run方法
  12. func (m *man) run() {
  13. fmt.Println("我是双脚走的")
  14. }
  15. //实现sing方法
  16. func (m *man) sing() {
  17. fmt.Println("我用嘴唱歌")
  18. }
  19. func main() {
  20. var me Man //声明接口
  21. var m1 man //声明结构体
  22. me = &m1 //结构体变量赋值给接口
  23. me.run()
  24. me.sing()
  25. }

有什么用呢?这里完全可以不用接口啊,直接用结构体调用方法就可以。

  1. var m1 man
  2. m1.run()
  3. m1.sing()

但是,如果还有其他类型,其他结构体也实现了这个接口,但是不一样的实现。此时,如果调用方法,就是有多少个结构体,就要调用多少次run方法。

  1. var m1 man
  2. m1.run()
  3. m1.sing()
  4. var m2 woman
  5. m2.run()
  6. m2.sing()
  7. ......

接口的作用就体现出来了,比如上述的例子,还有一个woman结构体也实现了接口,那么,想要它们调用同一个函数时,有不一样的输出,就是接口的作用,多态。

  1. package main
  2. import "fmt"
  3. //定义一个Man接口,有两个方法,run和sing
  4. type Man interface {
  5. run()
  6. sing()
  7. }
  8. //man结构体
  9. type man struct {
  10. }
  11. //实现run方法
  12. func (m *man) run() {
  13. fmt.Println("我是双脚走的")
  14. }
  15. //实现sing方法
  16. func (m *man) sing() {
  17. fmt.Println("我用嘴唱歌")
  18. }
  19. type woman struct {
  20. }
  21. //实现run方法
  22. func (m *woman) run() {
  23. fmt.Println("我是单脚走的")
  24. }
  25. //实现sing方法
  26. func (m *woman) sing() {
  27. fmt.Println("我不用嘴唱歌")
  28. }
  29. func Run(p Man) {
  30. p.run()
  31. p.sing()
  32. }
  33. func main() {
  34. Run(&man{}) //同时调用Run方法
  35. Run(&woman{}) //各自输出
  36. }

再来一个直观点的例子:
一个Dog接口,两个结构体jinmao和chaiquan,都实现了接口Dog,在add函数种,接收参数类型是接口,然后不同的接口变量调用同一个getage()函数,得到不一样的age,而不用写两遍。这里如果是成千上万个用户,那么效果更加明显,如果没有接口,那么就需要调用成千上万次getage()。

  1. package main
  2. import "fmt"
  3. type Dog interface {
  4. getage() int
  5. }
  6. type jinmao struct{ age int }
  7. type chaiquan struct{ age int }
  8. func (j jinmao) getage() int {
  9. return j.age
  10. }
  11. func (c chaiquan) getage() int {
  12. return c.age
  13. }
  14. func add(s []Dog) {
  15. var sum int
  16. for _, i := range s {
  17. sum += i.getage() //接口的真正意义
  18. }
  19. fmt.Println(sum)
  20. }
  21. func main() {
  22. jj := jinmao{1}
  23. cc := chaiquan{2}
  24. sdog := []Dog{jj, cc}
  25. add(sdog)
  26. }

10.2 类型断言

如何检测和转换接口变量的类型?一个接口类型的变量可以包含任意类型的值,必须有一种方式来检测它的到动态类型,即运行时在变量中存储的值的实际类型。利用类型断言来测试某个时刻接口变量是否包含某个类型的值:

  1. if v, ok := vari.(*T); ok {
  2. fmt.Printf("变量var1的类型为: %T", v)
  3. } else {
  4. fmt.Println("变量var1不包含类型: ", v)
  5. }

例子:

  1. package main
  2. import "fmt"
  3. //定义一个Man接口
  4. type Man interface {
  5. run()
  6. }
  7. //man结构体
  8. type man struct {
  9. name string
  10. age int
  11. }
  12. //实现run方法
  13. func (m *man) run() {
  14. fmt.Println("我是双脚走的")
  15. }
  16. type woman struct {
  17. }
  18. //实现run方法
  19. func (m *woman) run() {
  20. fmt.Println("我是单脚走的")
  21. }
  22. func main() {
  23. var vari Man
  24. man1 := man{}
  25. vari = &man1
  26. if v, ok := vari.(*man); ok {
  27. fmt.Printf("变量var1的类型为: %T", v) //*main.man
  28. } else {
  29. fmt.Println("变量var1不包含类型: ", v)
  30. }
  31. if u, ok := vari.(*woman); ok {
  32. fmt.Printf("变量var1的类型为: %T", u)
  33. } else {
  34. fmt.Printf("变量var1不包含类型: %T", u) //*main.woman
  35. }
  36. }

10.3 类型判断:type-swith

接口变量的类型也可以使用一种特殊形式的switch来检测,不用if来判断:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. //定义一个Man接口
  6. type Man interface {
  7. run()
  8. }
  9. //man结构体
  10. type man struct {
  11. name string
  12. age int
  13. }
  14. //实现run方法
  15. func (m *man) run() {
  16. fmt.Println("我是双脚走的")
  17. }
  18. type woman struct {
  19. }
  20. //实现run方法
  21. func (m *woman) run() {
  22. fmt.Println("我是单脚走的")
  23. }
  24. func main() {
  25. var vari Man
  26. man1 := man{}
  27. vari = &man1
  28. switch t := vari.(type) {
  29. case *man:
  30. fmt.Printf("类型%T,值为%v", t, t) //类型*main.man,值为&{ 0}
  31. case *woman:
  32. fmt.Printf("类型%T,值为%v", t, t)
  33. case nil:
  34. fmt.Printf("nil 值")
  35. default:
  36. fmt.Println("未知类型")
  37. }
  38. }

接口的不写了,没搞懂………