zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ", a.addr, a.group)
    
     26: }
    
     27: 
    
     28: type Mystr string
    
     29: 
    
     30: func (a *Mystr) sayHi() {
    
     31: 	fmt.Printf("Mystr(%s) sayhi
    ", *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
    ", 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
    ", index, value)
    
     16: 		} else if value, ok := data.(string); ok == true {
    
     17: 			fmt.Printf("x[%d] 类型为string,内容为%s
    ", index, value)
    
     18: 		} else if value, ok := data.(Student); ok == true {
    
     19: 			fmt.Printf("x[%d] 类型为Student,内容为%s,%d
    ", 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
    ", index, value)
    
     11: 			case string:
    
     12: 				fmt.Printf("x[%d] 类型为string,内容为%s
    ", index, value)
    
     13: 			case struct:
    
     14: 				fmt.Printf("x[%d] 类型为Student,内容为%s,%d
    ", index, value.name, value.id)
    
     15: 		}
    
     16: 	}
    
     17: 	switch data.(type)
    
     18: }

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

  • 相关阅读:
    视频像素点级的标注
    unet
    Emmet缩写语法
    Nginx漏洞利用与安全加固
    算法时间复杂度
    动态规划dp
    数据结构Java实现04---树及其相关操作
    关于递归
    Java正则表达式
    Java String相关
  • 原文地址:https://www.cnblogs.com/haoqirui/p/10201700.html
Copyright © 2011-2022 走看看