接口
教程地址:点击去往视频教程
1. 接口定义
接口(interface)
是一种类型,它是描述了一组方法
的集合。
比如:
type Animal interface {
//Say 动物可以说话
Say()
//Move 动物可以移动
Move()
//Jump 动物可以跳起来
Jump()
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
通过观察,我们很明显的能发现,接口的方法并没有实现,也就是说
接口只是一组抽象行为的定义
,并不会和特定的实现细节所绑定
func main() {
var animal Animal
//这里打印的结果为nil,接口的零值为nil
//也就是说我们想要使用接口,必须对齐初始化
fmt.Println(animal)
}
1
2
3
4
5
6
2
3
4
5
6
2. 接口实现
要想使用接口,必须实现接口
实现关系在Go语言中是隐式的。两个类型之间的实现关系不需要在代码中显式地表示出来。
Go编译器将自动在需要的时候检查两个类型之间的实现关系。
只要实现接口的类型方法和接口方法一致,我们就说此类型实现了方法
比如:
type Animal interface {
//Say 动物可以说话
Say()
//Move 动物可以移动
Move()
//Jump 动物可以跳起来
Jump()
}
type Dog struct {
}
func (d *Dog) Move() {
fmt.Println("狗在跑")
}
func (d *Dog) Jump() {
fmt.Println("狗在跳")
}
func (d *Dog) Say() {
fmt.Println("汪汪汪")
}
type Cat struct {
}
func (c *Cat) Say() {
fmt.Println("喵喵喵")
}
func main() {
//这里Dog实现了Animal接口,Cat没有实现
var dog Animal = &Dog{}
dog.Say()
}
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
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
接口实现规则:
必须实现接口的所有方法,并且方法的名称,参数,返回值类型都相同
type Fighter interface {
Hurt() int
}
func main() {
var dog Animal = &Dog{}
dog.Say()
//一个类型可以实现多个接口 没有限制
//反过来 一个接口可以被多个类型实现
//只需要符合接口实现规则即可
var fight Fighter = &Dog{}
fmt.Println("造成伤害:", fight.Hurt())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
接口可以嵌套:
type Sayer interface {
Say()
}
type Mover interface {
Move()
}
type Animal interface {
Sayer
Mover
//Jump 动物可以跳起来
Jump()
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
3. 空接口
- 空接口是没有方法的接口
- 因此任何类型都实现了
空接口
- 空接口类型的变量可以存储任意类型的变量
type Any interface{}
func main() {
var a Any
a = 10
fmt.Println(a)
}
1
2
3
4
5
6
7
2
3
4
5
6
7
为了方便空接口的使用,所以go提供了一个类型别名
any
func main() {
var a any
a = 10
fmt.Println(a)
a = "搜码神之路学go"
fmt.Println(a)
}
1
2
3
4
5
6
7
2
3
4
5
6
7
4. 类型断言
空接口可以存储任意类型的值,如何获取具体的类型呢?
这就需要用到类型断言
。
语法为:
x.(T)
1
其中:
- x:表示类型为interface{}的变量
- T:表示断言x可能是的类型。
func main() {
var x interface{}
x = "码神之路"
v, ok := x.(string)
if ok {
fmt.Println(v)
} else {
fmt.Println("类型断言失败")
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
可以用switch
实现:
func justifyType(x interface{}) {
switch v := x.(type) {
case string:
fmt.Printf("x is a string,value is %v\n", v)
case int:
fmt.Printf("x is a int is %v\n", v)
case bool:
fmt.Printf("x is a bool is %v\n", v)
default:
fmt.Println("unsupport type!")
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
5. 泛型
泛型是go1.18新增的功能
比如下面的代码:
//求最小值,一个类型就要写一个函数
func min(x, y int) int {
if x < y {
return x
}
return y
}
func minFloat(x, y float64) float64 {
if x < y {
return x
}
return y
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
使用泛型可以:
//T就是泛型
func min[T int | float64 | float32 | int64](x, y T) T {
if x < y {
return x
}
return y
}
func main() {
//可以通过给min提供类型参数 从而验证类型参数是否可用
mInt := min[int]
fmt.Println(mInt(2, 3))
fmt.Println(min(2.3, 4.5))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
//实际在接口中除了定义方法,也可以嵌入非接口类型
type AllBaseType interface {
int | float64 | float32 | int64
}
func min[T AllBaseType](x, y T) T {
if x < y {
return x
}
return y
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
我们还可以定义多个泛型:
func min[T AllBaseType, E []T](x T, y E) T {
for _, v := range y {
if x < v {
return x
}
}
return y[0]
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
有时我们会看到
~int
这样的表达式,~
标记表示的是底层类型为int的所有类型,包括int
//也可以用于结构体和接口中
type User[T int] struct {
Name T
}
func main() {
user := User[int]{}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9