接口

教程地址:点击去往视频教程open in new window

1. 接口定义

接口(interface)是一种类型,它是描述了一组方法的集合。

比如:

type Animal interface {
	//Say 动物可以说话
	Say()
	//Move 动物可以移动
	Move()
	//Jump 动物可以跳起来
	Jump()
}
1
2
3
4
5
6
7
8

通过观察,我们很明显的能发现,接口的方法并没有实现,也就是说接口只是一组抽象行为的定义,并不会和特定的实现细节所绑定

func main() {
	var animal Animal
     //这里打印的结果为nil,接口的零值为nil
    //也就是说我们想要使用接口,必须对齐初始化
	fmt.Println(animal)
}
1
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

接口实现规则:必须实现接口的所有方法,并且方法的名称,参数,返回值类型都相同

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

接口可以嵌套:

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

3. 空接口

  • 空接口是没有方法的接口
  • 因此任何类型都实现了空接口
  • 空接口类型的变量可以存储任意类型的变量
type Any interface{}

func main() {
	var a Any
	a = 10
	fmt.Println(a)
}
1
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

4. 类型断言

空接口可以存储任意类型的值,如何获取具体的类型呢?

这就需要用到类型断言

语法为:

x.(T)
1

其中:

  1. x:表示类型为interface{}的变量
  2. 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

可以用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

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

使用泛型可以:

//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
//实际在接口中除了定义方法,也可以嵌入非接口类型
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

我们还可以定义多个泛型:

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

有时我们会看到~int这样的表达式,~标记表示的是底层类型为int的所有类型,包括int

//也可以用于结构体和接口中
type User[T int] struct {
	Name T
}

func main() {
	user := User[int]{}
}

1
2
3
4
5
6
7
8
9