目录
一、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面向对象-拓展和多肽