Go语言学习笔记(十四)之接口类型

21.接口类型

接口类型是其他类型行为的概括与抽象。接口是一种抽象类型,它并没有暴露了基于这个精确布局的内部操作。

  1: type Humaner interface {
  2: 	SayHi()
  3: }

接口命令习惯以er结尾
接口只有方法声明,没有实现,没有数据字段
接口可以匿名嵌入其他接口,或嵌入到结构中

接口实现

接口是用来定义行为的类型。这些被定义的行为不由接口直接实现,而是由用户定义的类型实现,一个实现了这些方法的具体类型是这个接口类型的实例。

如果用户定义的类型实现了某个接口类型声明的一组方法,那么这个用户定义的类型的值就可以赋给这个接口类型的值。这个赋值会把用户定义的类型的存入接口类型的值。

代码示例:

  1: package main
  2: 
  3: import (
  4: 	"fmt"
  5: )
  6: 
  7: type Humaner interface{
  8: 	sayHi()
  9: }
 10: type Student struct {
 11: 	name string
 12: 	id int
 13: }
 14: 
 15: //这样就可以说Student实现了此方法
 16: func (a *Student) sayHi() {
 17: 	fmt.Printf("Student(%d, %s) sayhi\n", a.id, a.name)
 18: }
 19: type Teacher struct {
 20: 	addr string
 21: 	group string
 22: }
 23: // 同上
 24: func (a *Teacher) sayHi() {
 25: 	fmt.Printf("Teacher(%s, %s) sayhi\n", a.addr, a.group)
 26: }
 27: 
 28: type Mystr string
 29: 
 30: func (a *Mystr) sayHi() {
 31: 	fmt.Printf("Mystr(%s) sayhi\n", *a)
 32: }
 33: 
 34: func main() {
 35: 	//定义接口类型的变量
 36: 	var i Humaner
 37: 	// 只要实现了此接口方法的类型,那么这个类型的变量就可以给i赋值
 38: 	s := &Student{"mike", 666}
 39: 	i = s
 40: 	i.sayHi()
 41: 
 42: 	t := &Teacher{"bj", "go"}
 43: 	i = t
 44: 	i.sayHi()
 45: 
 46: 	var str Mystr = "hello mike"
 47: 	i = &str
 48: 	i.sayHi()
 49: }
  1: >>> Student(666, mike) sayhi
  2: Teacher(bj, go) sayhi
  3: Mystr(hello mike) sayhi

换一种写法,接上面,更换main函数,结果一样

  1: // 定义一个普通函数,函数的参数为接口类型
  2: func WhoSayHi(i Human) {
  3: 	i.sayHi()
  4: }
  5: 
  6: func main()  {
  7: 	s := &Student{"mike", 666}
  8: 	t := &Teacher{"bj", "go"}
  9: 	var str Mystr = "hello mike"
 10: 	// 调用同一个函数,可以有不同表现,多态性的表现
 11: 	WhoSayHi(s)
 12: 	WhoSayHi(t)
 13: 	WhoSayHi(&str)
 14: }

也可以用切片

  1: func main()  {
  2: 	s := &Student{"mike", 666}
  3: 	t := &Teacher{"bj", "go"}
  4: 	var str Mystr = "hello mike"
  5: 
  6: 	x := make([]Human, 3)
  7: 	x[0] = s
  8: 	x[1] = t
  9: 	x[2] = &str
 10: 
 11: 	for _, i := range x{
 12: 		i.sayHi()
 13: 	}	
 14: }

接口的继承

  1: package main
  2: 
  3: import "fmt"
  4: 
  5: type Human interface { // 子集
  6: 	sayHi()
  7: }
  8: 
  9: type Person interface { //超集
 10: 	Human // 匿名字段
 11: 	sing(lrc string)
 12: }
 13: 
 14: type Student struct{
 15: 	name string
 16: 	id int
 17: }
 18: 
 19: func (a *Student) sayHi() {
 20: 	fmt.Printf("Student[%s, %d] sayhi\n", a.name, a.id)
 21: }
 22: 
 23: func (a *Student) sing(lrc string) {
 24: 	fmt.Println("Student在唱着:", lrc)
 25: }
 26: 
 27: func main() {
 28: 	//定义一个接口类型的变量
 29: 	var i Person
 30: 	s := &Student{"Mike", 666}
 31: 	i = s
 32: 	i.sayHi() //继承来的方法
 33: 	i.sing("学生歌")
 34: }
  1: >>> Student[Mike, 666] sayhi
  2: Student在唱着: 学生歌

接口的转换

如上,超集可以转换为子集,反过来不可以

  1: func main() {
  2: 	var iPro Person // 超集
  3: 	iPro = &Student{"Mike", 666}
  4: 	var i Human // 子集
  5: 	// iPro = i 错误
  6: 	i = iPro
  7: 	i.sayHi()
  8: }
  1: >>> Student[Mike, 666] sayhi

空接口

空接口不包含任何的方法。因此空接口可以存储任意类型的数值,因此空接口是可以存储任意类型的数值。

  1: var v1 interface{} = 1
  2: var v2 interface{} = "abc"
  3: var v3 interface{} = &v2
  4: var v4 interface{} = struct{x int }{1}
  5: var v5 interface{} = &struct{x int}{1}

当函数可以接受任意的对象实例时,我们会将其声明为interface{},最典型的例子是标准库fmt中PrintXXX系列的函数,例如:

  1: func Printf(fmt string,args ...interface{})
  2: func Println(args ...interface{})

类型查询

我们知道interface的变量里面可以存储任意类型的数值。反向知道这个变量里面实际保存了的是那个类型的对象,两种方法
comma-ok断言

  1: type Student struct {
  2: 	name string
  3: 	id   int
  4: }
  5: 
  6: func main() {
  7: 	i := make([]interface{}, 3)
  8: 	i[0] = 1
  9: 	i[1] = "hello go"
 10: 	i[2] = Student{"mike", 666}
 11: 
 12: 	// 类型查询,类型断言
 13: 	for index, data := range i {
 14: 		if value, ok := data.(int); ok == true {
 15: 			fmt.Printf("x[%d] 类型为int,内容为%d\n", index, value)
 16: 		} else if value, ok := data.(string); ok == true {
 17: 			fmt.Printf("x[%d] 类型为string,内容为%s\n", index, value)
 18: 		} else if value, ok := data.(Student); ok == true {
 19: 			fmt.Printf("x[%d] 类型为Student,内容为%s,%d\n", index, value.name, value.id)
 20: 		}
 21: 	}
 22: }

switch测试

  1: func main() {
  2: 	i := make([]interface{}, 3)
  3: 	i[0] = 1
  4: 	i[1] = "hello go"
  5: 	i[2] = Student{"mike", 666}
  6: 
  7: 	for index,data := range i {
  8: 		switch value := data.(type){
  9: 			case int:
 10: 				fmt.Printf("x[%d] 类型为int,内容为%d\n", index, value)
 11: 			case string:
 12: 				fmt.Printf("x[%d] 类型为string,内容为%s\n", index, value)
 13: 			case struct:
 14: 				fmt.Printf("x[%d] 类型为Student,内容为%s,%d\n", index, value.name, value.id)
 15: 		}
 16: 	}
 17: 	switch data.(type)
 18: }

小结:
go语言通过特殊的方式实现面对对象编程中的封装,继承,多态这些概念。
封装:通过方法实现
继承:通过匿名字段实现
多态:通过接口实现

猜你喜欢

转载自www.cnblogs.com/haoqirui/p/10201700.html