• ch16、面向对象编程-Go语言的相关接口


    ch16、面向对象编程 - Go语言的相关接口

    1、Duck Type式接口实现

    接口定义与实现:

    // 定义接口
    type 接口名称 interface{
        函数声明
    }
    
    // 定义一个struct(类似object),然后实现该行为(方法)
    type GoProgrammer struct{
    }
    
    func (p *GoProgrammer) funcName() returnType {
    	return "fmt.Println(\"Hello World.\")"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    实例如下:

    package interfacetest
    
    import "testing"
    
    type Programmer interface {
    	WriteHelloWorld() string
    }
    
    type GoProgrammer struct {
    }
    
    func (p *GoProgrammer) WriteHelloWorld() string {
    	return "fmt.Println(\"Hello World.\")"
    }
    
    func TestClient(t *testing.T) {
    	var p Programmer    // 接口变量
    	p = new(GoProgrammer)
    	t.Log(p.WriteHelloWorld())
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    与其它主要编程语言的差异:

    • 接口为非入侵性,实现不依赖于接口定义
    • 所有接口的定义可以包含在接口使用者的包内

    Go接口注意点:

    • 接口中只能有方法的声明不能有方法的实现
    • 接口中只能有方法什么不能有字段
    • 只有实现了接口中所有的方法, 才算实现了接口, 才能用该接口类型接收
    package main
    
    import "fmt"
    
    // 1.定义一个接口
    type usber interface {
    	start()
    	stop()
    }
    type Computer struct {
    	name  string
    	model string
    }
    
    // 2.实现接口中的所有方法
    func (cm Computer) start() {
    	fmt.Println("启动电脑")
    }
    func (cm Computer) stop() {
    	fmt.Println("关闭电脑")
    }
    
    // 2.只实现了接口中部分方法
    type Phone struct {
    	name  string
    	model string
    }
    
    func (p Phone) start() {
    	fmt.Println("启动手机")
    }
    func main() {
    	// 1.定义一个usber接口类型变量
    	var i usber
    	// 2.用usber接口类型变量接收Computer类型结构体
    	i = Computer{"戴尔", "F1234"} // 实现了所有方法, 不会报错
    	// 3.用usber接口类型变量接收Phone类型结构体
    	//i = Phone{"华为", "M10"} // 只实现了部分方法, 会报错
    	fmt.Println(i)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 和结构体一样,接口中也可以嵌入接口(但不能嵌入自己)
    package main
    
    import "fmt"
    
    type A interface {
    	fna()
    }
    type B interface {
    	fnb()
    }
    type C interface {
    	A // 嵌入A接口
    	B // 嵌入B接口
    	fnc()
    }
    type Person struct{}
    
    func (p Person) fna() {
    	fmt.Println("实现A接口中的方法")
    }
    func (p Person) fnb() {
    	fmt.Println("实现B接口中的方法")
    }
    func (p Person) fnc() {
    	fmt.Println("实现C接口中的方法")
    }
    func main() {
    	var ic C
    	var ia A
    	var ib B
    	ia = Person{}
    	ia.fna()
    	ib = Person{}
    	ib.fnb()
    	ic = Person{}
    	ic.fna() // 实现A接口中的方法
    	ic.fnb() // 实现B接口中的方法
    	ic.fnc() // 实现C接口中的方法
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 接口中嵌入接口时不能出现相同的方法名称
    • 超集接口变量可以自动转换成子集接口变量, 子集接口变量不能转换为超集接口变量(本质就是没有实现所有方法)
    package main
    
    import "fmt"
    
    type aer interface {
    	fna()
    }
    type ber interface {
    	aer
    	fnb()
    }
    
    // Person实现了超集接口所有方法
    type Person struct{}
    
    func (p Person) fna() {
    	fmt.Println("实现A接口中的方法")
    }
    func (p Person) fnb() {
    	fmt.Println("实现B接口中的方法")
    }
    
    // Student实现了子集接口所有方法
    type Student struct{}
    
    func (p Student) fna() {
    	fmt.Println("实现A接口中的方法")
    }
    func main() {
    	var i ber
    	// 子集接口变量不能转换为超集接口变量
    	//i = Student{}
    	fmt.Println(i)
    	var j aer
    	// 超集接口变量可以自动转换成子集接口变量,
    	j = Person{}
    	fmt.Println(j)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 空接口类型可以接收任意类型数据(常用的)
    package main
    
    import "fmt"
    
    func main() {
    	type Computer struct {
    		name  string
    		model string
    	}
    	// 1.定义一个空接口类型变量
    	var i interface{}
    	// 2.用接口类型保存任意类型数据
    	i = 123
    	fmt.Println(i) // 123
    	i = 3.14
    	fmt.Println(i) // 3.14
    	i = "lnj"
    	fmt.Println(i) // lnj
    	i = [3]int{1, 3, 5}
    	fmt.Println(i) // [1 3 5]
    	i = []int{2, 4, 6}
    	fmt.Println(i) // [2 4 6]
    	i = map[string]string{"name": "lnj"}
    	fmt.Println(i) // map[name:lnj]
    	i = Computer{"戴尔", "F1234"}
    	fmt.Println(i) // {戴尔 F1234}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    2、接口变量(类似多态)

    在这里插入图片描述

    3、自定义类型

    type CustomerTypeName type

    package customer_type
    
    import (
    	"fmt"
    	"testing"
    	"time"
    )
    
    // 自定义类型
    type IntConv func(op int) int
    
    func timeSpent(inner IntConv) IntConv {
    	return func(n int) int {
    		start := time.Now()
    		ret := inner(n)
    		fmt.Println("time spent: ", time.Since(start).Seconds())
    		return ret
    	}
    }
    
    func slowFunc(op int) int {
    	time.Sleep(time.Second * 1)
    	return op
    }
    func TestFn(t *testing.T) {
    	tsSF := timeSpent(slowFunc) // 传入的是函数,返回的也是函数实例 - 函数式编程
    	t.Log(tsSF(10))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 只要是自定义类型就可以实现接口
    package main
    
    import "fmt"
    
    // 1.定义一个接口
    type usber interface {
    	start()
    	stop()
    }
    
    // 2.自定义int类型
    type integer int
    
    // 3.实现接口中的所有方法
    func (i integer) start() {
    	fmt.Println("int类型实现接口")
    }
    func (i integer) stop() {
    	fmt.Println("int类型实现接口")
    }
    func main() {
    	var i integer = 666
    	i.start() // int类型实现接口
    	i.stop()  // int类型实现接口
    	fmt.Println(i)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    4、接口类型转换

    • 接口类型变量可以接收实现了该接口类型的变量, 但是只能调用该变量中的方法, 不能访问该变量的属性
    package main
    
    import "fmt"
    
    type studier interface {
    	read()
    }
    type Person struct {
    	name string
    	age  int
    }
    
    func (p Person) read() {
    	fmt.Println(p.name, "正在学习")
    }
    func main() {
    	// 1.定义一个接口类型变量
    	var s studier
    	// 2.用接口类型变量接收实现了接口的结构体
    	s = Person{"lnj", 33}
    	s.name = "zs" // 报错, 由于s是接口类型, 所以不能访问属性
    	fmt.Println(s)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 想要访问变量中的属性, 必须将接口类型还原为原始类型
      • 利用ok-idiom模式将接口类型还原为原始类型,s.(Person)这种格式我们称之为: 类型断言
      • 通过 type switch将接口类型还原为原始类型,注意: type switch不支持fallthrought
    package main
    
    import "fmt"
    
    type studier interface {
    	read()
    }
    type Person struct {
    	name string
    	age  int
    }
    
    func (p Person) read() {
    	fmt.Println(p.name, "正在学习")
    }
    func main() {
    	var s studier
    	s = Person{"lnj", 33}
    	// s.name = "zs" // 报错, 由于s是接口类型, 所以不能访问属性
    	// 2.定义一个结构体类型变量
    	//var p Person
    	// 不能用强制类型转换方式将接口类型转换为原始类型
    	//p = Person(s) // 报错
    
    	// 2.利用ok-idiom模式将接口类型还原为原始类型
    	// s.(Person)这种格式我们称之为: 类型断言
    	if p, ok := s.(Person); ok {
    		p.name = "zs"
    		fmt.Println(p)
    	}
    
    	// 2.通过 type switch将接口类型还原为原始类型
    	// 注意: type switch不支持fallthrought
    	switch p := s.(type) {
    	case Person:
    		p.name = "zs3"
    		fmt.Println(p) // {zs 33}
    	default:
    		fmt.Println("不是Person类型")
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 除了可以将接口类型转换为原始类型以外, 企业开发中有时候还需要将抽象接口类型转换为具体接口类型
    package main
    
    import "fmt"
    
    type studier interface {
    	read()
    }
    type Person struct {
    	name string
    	age  int
    }
    
    func (p Person) read() {
    	fmt.Println(p.name, "正在学习")
    }
    func main() {
    	// 1.定义一个抽象接口类型
    	var i interface{}
    	i = Person{"lnj", 33}
    	// 不能调用read方法, 因为抽象接口中没有这个方法
    	//i.read()
    	// 2.利用ok-idiom模式将抽象接口转换为具体接口
    	if s, ok := i.(studier); ok {
    		// 可以调用read方法,因为studier中声明了这个方法,并且结构体中实现了这个方法
    		s.read() // lnj 正在学习
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
  • 相关阅读:
    git将当前分支A强制推送远程分支pro上
    Pytorch学习笔记(GPU训练)
    【博弈论】基础知识
    涨知识,关于代码签名证书10大常见问题解答
    Go重写Redis中间件 - Go实现内存数据库
    HC-05 蓝牙 2.0 串口模块
    卡特兰数
    FlinkSQL自定义UDATF实现TopN
    OpenCV C++案例实战二十八《手写数字识别》
    ROS1云课→30导航仿真演示
  • 原文地址:https://blog.csdn.net/u012558127/article/details/126026488