GO语言语法基础11 —— 接口 | 青训营

157 阅读4分钟

先看一个例子:

package main
import "fmt"

type Shape interface {
    Area() float64
}

type Rectangle struct {
    width, height float64
}

func (r Rectangle) Area() float64 {
    return r.width * r.height
}

type Circle struct {
    radius float64
}

func (c Circle) Area() float64 {
    return 3.14 * c.radius * c.radius
}

func PrintArea(s Shape) {
    fmt.Println("Area:", s.Area())
}

func main() {
    rectangle := Rectangle{width: 5, height: 3}
    circle := Circle{radius: 2.5}

    PrintArea(rectangle)
    PrintArea(circle)
}

一、接口的定义:

接口是一种在面向对象编程中重要的概念,它定义了一组方法的集合。接口提供了一种约定,规定了实现该接口的类型必须实现指定的方法,但不关心具体的实现细节。接口能够实现多态性,使得代码更加灵活、可扩展和可维护。

二、GO语言中的接口:

在Go语言中,接口的定义使用interface关键字,并采用类型名加方法列表的形式。

例如:

type Animal interface {
    Speak() string
    Move() string
}

上面的代码定义了一个名为Animal的接口,该接口包含了两个方法:Speak()和Move()。任何实现了这两个方法的类型都可以被认为是Animal接口的实现。

三、接口的作用:

    1. 抽象:接口提供了一种抽象的能力,使得我们可以关注于类型应该具备的行为而不关心具体的实现细节。这样就能够实现代码的解耦和灵活性。
    1. 多态性:通过接口,我们可以在不修改原有代码的情况下,对现有的类型进行扩展。可以使用实现了相同接口的不同类型的实例来调用相同的方法,从而实现多态性。
    1. 代码复用:通过接口,我们可以将相似行为的类型进行抽象,并使用相同的接口来处理它们。这样可以减少代码的重复性,提高代码的可维护性。

四、接口的使用:

接口的使用方式包括定义接口、实现接口和使用接口。

    1. 定义接口:使用interface关键字定义接口,并在接口中列出需要实现的方法。
type Animal interface {
    Speak() string
    Move() string
}
    1. 实现接口:任何类型只要实现了接口中定义的所有方法,就被视为实现了该接口。
type Dog struct{}

func (d Dog) Speak() string {
    return "Woof!"
}

func (d Dog) Move() string {
    return "Running"
}
    1. 使用接口:可以创建接口类型的变量,将实现了接口的对象赋值给这个变量,并通过接口调用对应的方法。
var animal Animal
animal = Dog{} // 将Dog类型赋值给Animal类型的变量
fmt.Println(animal.Speak()) // 调用Speak()方法,输出 "Woof!"
fmt.Println(animal.Move()) // 调用Move()方法,输出 "Running"

四、接口的其他作用:

接口还可以作为函数参数和返回值使用,以实现更灵活的功能。

  • 首先,让我们看看如何将接口作为函数的参数。
type Speaker interface {
    Speak() string
}

func LetSpeak(speaker Speaker) {
    fmt.Println(speaker.Speak())
}

小结1:在上面的代码中,我们定义了一个Speaker接口,并编写了一个LetSpeak函数,该函数接受一个实现了Speaker接口的对象作为参数。在函数内部,我们通过speaker.Speak()调用了Speak()方法。

  • 接下来,我们看一下如何将接口作为函数的返回值。
type Animal interface {
    Speak() string
}

type Dog struct{}

func (d Dog) Speak() string {
    return "Woof!"
}

func GetAnimal() Animal {
    return Dog{}
}

小结2:在上述代码中,我们定义了一个Animal接口和一个Dog类型,并为Dog类型实现了Speak()方法。然后,我们编写了一个GetAnimal函数,它返回一个Animal接口类型的对象。

通过这种方式,我们可以根据业务需求返回不同类型的实现了Animal接口的对象,而无需暴露具体的实现细节。这种灵活性使得我们可以在运行时动态决定返回的具体类型。

  • 下面是使用接口作为函数参数和返回值的示例:
func main() {
    dog := Dog{}
    LetSpeak(dog)

    animal := GetAnimal()
    LetSpeak(animal)
}

小结3: 在上述示例中,我们首先创建了一个Dog对象,并将其传递给LetSpeak函数。由于Dog类型实现了Speaker接口的Speak()方法,因此它可以作为参数传递给LetSpeak函数进行处理;

其次,我们调用GetAnimal函数,并将返回的Animal对象传递给LetSpeak函数。尽管GetAnimal函数返回的是一个实现了Animal接口的对象,但是由于Animal接口定义了Speak()方法,因此它也可以作为参数传递给LetSpeak函数。