Go面向对象-接口

目录

一、Go 接口

1、接口的作用

2、Duck type 式接口实现

a、什么是 Duck type

b、接口定义

c、接口实现

d、接口定义和实现示例

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

二、空接口与断言

1、空接口可以表示任何类型

2、调试效果

3、用更简洁的 switch 来实现

三、Go接口最佳实践

1、倾向于使用小的接口定义,很多接口只包含一个方法

2、较大的接口定义,可以由多个小接口定义组合而成

3、只依赖于必要功能的最小接口


一、Go 接口

1、接口的作用

接口是用来定义对象间交互的协议。

2、Duck type 式接口实现

a、什么是 Duck type

Duck type 就是鸭子类型,什么叫鸭子类型,也就是脚上有璞,身上有羽毛,嘴扁扁的, 虽然我们也不知道它是什么鸟,但是看起来像鸭子,我们就叫它鸭子。

b、接口定义

type Programmer interface {
	WriteHelloWorld() string
}

c、接口实现

//定义接口的数据结构
type GoProgrammer struct {
	Language string
}

//方法名和返回值都必须和接口定义的保持一致,
//同时把这个方法绑定到 GoProgrammer 这个结构的指针上
func (goProgrammer *GoProgrammer) WriteHelloWorld() string {
	return goProgrammer.Language + " print Hello World"
}

d、接口定义和实现示例

package _interface

import "testing"

//定义接口
type Programmer interface {
	WriteHelloWorld() string
}

//定义接口的数据结构
type GoProgrammer struct {
	Language string
}

//实例的方法名和返回值都必须和接口定义的保持一致,
//同时把这个方法绑定到 GoProgrammer 这个结构的指针上
func (goProgrammer *GoProgrammer) WriteHelloWorld() string {
	return goProgrammer.Language + " print Hello World"
}

//调用这个接口的实现
func TestClient(t *testing.T) {
	goProgrammer := &GoProgrammer{Language: "Go"}

	res := goProgrammer.WriteHelloWorld()

	t.Log(res)	//Go print Hello World
}

结论:GoProgrammer 这个结构实现了 Programmer 这个接口 , 但是 Go 语言没有将显示的使用 implements 来进行依赖绑定, 而是使用了 duck type 的方式,只要方法名,参数和返回值是一样的 我们就认为这个实例就是 Programmer 接口的实现。

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

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

 

二、空接口与断言

1、空接口可以表示任何类型

通过断言来将空接口转换为指定类型,而不是使用强制类型转换

//空接口转换为其它任何类型的格式
//val 为转换后的结果值,当 ok==true 时,表示转换成功
val, ok := empty_interface.(type)

2、调试效果

package empty_interface

import (
	"fmt"
	"testing"
)

//空接口类型转换
func ConvertEmptyInterface(p interface{})  {
	if val, ok := p.(int); ok {
		fmt.Printf("Empty interface convert to integer : %v\n", val)
	} else if val, ok := p.(string); ok {
		fmt.Printf("Empty interface convert to string : %v\n", val)
	} else if val, ok := p.([2]int); ok {
		fmt.Printf("Empty interface convert to array : %v\n", val)
	} else if val, ok := p.([]int); ok {
		fmt.Printf("Empty interface convert to slice : %v\n", val)
	} else if val, ok := p.(map[int]int); ok {
		fmt.Printf("Empty interface convert to map : %v\n", val)
	} else {
		fmt.Print("Unknow")
	}
}


//空接口可以转换为任何类型
func TestEmptyInterfaceAssertion(t *testing.T) {
	number := 10
	ConvertEmptyInterface(number)
	//Empty interface convert to integer : 10

	str := "Go"
	ConvertEmptyInterface(str)
	//Empty interface convert to string : Go

	map1 := make(map[int]int, 10)
	ConvertEmptyInterface(map1)
	//Empty interface convert to map : map[]

	arr := [2]int{1, 2}
	ConvertEmptyInterface(arr)
	//Empty interface convert to array : [1 2]

	slice1 := make([]int, 3, 5)
	ConvertEmptyInterface(slice1)
	//Empty interface convert to slice : [0 0 0]
}

3、用更简洁的 switch 来实现

package empty_interface

import (
	"fmt"
	"testing"
)

//空接口类型转换
func ConvertEmptyInterface(p interface{})  {
	// p.(type)这种写法只能用于 switch 中
	switch val:= p.(type) {
	case int:
		fmt.Printf("Empty interface convert to integer : %v\n", val)
	case string:
		fmt.Printf("Empty interface convert to string : %v\n", val)
	case [2]int:
		fmt.Printf("Empty interface convert to array : %v\n", val)
	case []int:
		fmt.Printf("Empty interface convert to slice : %v\n", val)
	case map[int]int:
		fmt.Printf("Empty interface convert to map : %v\n", val)
	default:
		fmt.Print("Unknow")
	}
}


//空接口可以转换为任何类型
func TestEmptyInterfaceAssertion(t *testing.T) {
	number := 10
	ConvertEmptyInterface(number)
	//Empty interface convert to integer : 10

	str := "Go"
	ConvertEmptyInterface(str)
	//Empty interface convert to string : Go

	arr := [2]int{1, 2}
	ConvertEmptyInterface(arr)
	//Empty interface convert to array : [1 2]

	slice1 := make([]int, 3, 5)
	ConvertEmptyInterface(slice1)
	//Empty interface convert to slice : [0 0 0]

	map1 := make(map[int]int, 10)
	ConvertEmptyInterface(map1)
	//Empty interface convert to map : map[]

}

为何写这种两段式的switch语句会报错呢 (use of .(type) outside type switch)?

对于这个情况,后面的 val 有什么用呢?前面 val 已经被赋值并且可以在下面使用了。 val 的值是

类型,你可以通过 %T 来输出。

//空接口类型转换
func ConvertEmptyInterface(p interface{})  {
    switch val := p.(type); val {
        //code
    }
}

 

三、Go接口最佳实践

1、倾向于使用小的接口定义,很多接口只包含一个方法

更小的接口,让接口的负担更轻,接口的复用性更高,在Go里面有很多 Single method (即只有一个方法的接口),例如像下面这样:

type Reader interface {
	Read (p []byte) (num int)
}

type Writer interface {
	Write (p []byte) (num int)
}

2、较大的接口定义,可以由多个小接口定义组合而成

type ReaderWriter interface {
	Reader
	Writer
}

3、只依赖于必要功能的最小接口

//例如我这个方法只需要用到了 Reader,就只依赖 Reader 接口,
//没必要依赖 ReaderWriter 接口
func GetAllReaders(reader Reader) error {
	//code
	return nil
}

当我们定义了较小的接口后,为了发挥小接口的优势,我们使用的方法一定要尽量依赖它最小的接口,这样接口中的方法才能被更多的地方去复用。

:这篇博文是我学习中的总结,如有转载请注明出处:

https://blog.csdn.net/DaiChuanrong/article/details/118073601

上一篇Go面向对象-行为的定义和实现

下一篇Go面向对象-拓展和多肽

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值