一、接口的定义
接口是和调用方的一种约定 是一个高度抽象的类型 不同和具体的实现细节绑定在一起
示例代码:
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
| type Person interface { //定义一个Person接口
Speak(msg string)
Walk()
}
type Student struct {
name string
}
type Teacher struct {
name string
}
/**
Student实现Person接口的两个方法
*/
func (s Student) Speak(msg string) {
fmt.Println(s.name, " say ", msg)
}
func (s Student) Walk() {
fmt.Println(s.name, " 会走路 ")
}
func (t Teacher) Speak(msg string) {
fmt.Println(t.name, " say ", msg)
}
func (t Teacher) Walk() {
fmt.Println(t.name, " 会走路 ")
}
func main() {
var p1 Person = Student{name: "小明"}
var p2 Person = Teacher{name: "王老师"}
p1.Speak("老师好")
p2.Speak("同学们好")
}
|
二、解释说明
一个类型实现了一个接口的所有方法就说明这个类型实现了这个接口
接口就是一个需要实现的方法列表
当我们使用指针实现接口时,只有指针类型的变量才会实现该接口;当我们使用结构体实现接口时,指针类型和结构体类型都会实现该接口。
三、空接口
空interface(interface{})不包含任何的method,正因为如此,所有的类型都实现了空interface
作为数据容器时,空interface可以存储任意类型的数值。
interface{} 类型不是任意类型
空接口作为函数参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| func show(a interface{}) {
fmt.Printf("type:%T value:%v\n", a, a)
}
func main() {
show(555)
show(float64(5.1234567890123456789))
show(float32(5.123456789))
show("hello")
}
//运行结果
type:int value:555
type:float64 value:5.123456789012345
type:float32 value:5.123457
type:string value:hello
|
float32 和 float64
Go语言中提供了两种精度的浮点数 float32 和 float64。
float32,也即我们常说的单精度,存储占用4个字节,也即4*8=32位,其中1位用来符号,8位用来指数,剩下的23位表示尾数
float64,也即我们熟悉的双精度,存储占用8个字节,也即8*8=64位,其中1位用来符号,11位用来指数,剩下的52位表示尾数
那么精度是什么意思?有效位有多少位?
精度主要取决于尾数部分的位数。
对于 float32(单精度)来说,表示尾数的为23位,除去全部为0的情况以外,最小为2-23,约等于1.19*10-7,所以float小数部分只能精确到后面6位,加上小数点前的一位,即有效数字为7位。
同理 float64(单精度)的尾数部分为 52位,最小为2-52,约为2.22*10-16,所以精确到小数点后15位,加上小数点前的一位,有效位数为16位。
空接口作为map值
1
2
3
4
5
6
| var studentInfo = make(map[string]interface{})
studentInfo["name"] = "Wilen"
studentInfo["age"] = 18
studentInfo["married"] = false
fmt.Println(studentInfo) //map[age:18 married:false name:Wilen]
//例如gin框架的gin.H{}
|
四、注意事项
只有当有两个或两个以上的具体类型必须以相同的方式进行处理时才需要定义接口。不要为了接口而写接口,那样只会增加不必要的抽象,导致不必要的运行时损耗。