开放的编程资料库

当前位置:我爱分享网 > Go教程 > 正文

如何在Golang中使用接口

Go接口教程展示了如何在Golang中使用接口。

接口是一组函数签名,它是一种特定类型。另一种类型通过实现其功能来实现接口。虽然Java或C#等语言显式实现了接口,但Go中没有明确的意图声明。

接口的主要任务是仅提供由名称、输入参数和返回类型组成的函数签名。实现功能取决于类型(例如结构类型)。

接口也被称为公开的API或契约。如果一个类型实现了一个可排序接口的函数(API),我们就知道它是可以排序的;它遵守可排序的约定。

接口指定行为。一个接口只包含函数的签名,而不包含它们的实现。

使用接口可以使代码更清晰、更短、更易读。

$ go version
go version go1.18.1 linux/amd64

我们使用Go版本1.18。

Go接口示例

下面的例子使用了一个简单的Shape接口。

package main

import (
    "fmt"
    "math"
)

type Shape interface {
    Area() float64
}

type Rectangle struct {
    Width, Height float64
}

type Circle struct {
    Radius float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

func getArea(shape Shape) {

    fmt.Println(shape.Area())
}

func main() {

    r := Rectangle{Width: 7, Height: 8}
    c := Circle{Radius: 5}

    getArea(r)
    getArea(c)
}

Shape是一种通用的几何形式。它无法绘制。RectangleCircle是特定的几何图形,可以画出来,也可以计算面积。

type Shape interface {
    Area() float64
}

我们定义了Shape接口。它有一个函数签名:Area

type Rectangle struct {
    Width, Height float64
}

type Circle struct {
    Radius float64
}

我们定义了两种类型:RectangleCircle

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

我们为RectangleCircle定义了Area函数;我们说这两种类型实现了Shape接口。

func getArea(shape Shape) {

    fmt.Println(shape.Area())
}

getArea函数将Shape接口作为参数。我们可以同时传递RectangleCircle,因为它们都是形状。

$ go run geo_shapes.go 
56
78.53981633974483

Go接口切片

在下面的例子中,我们创建了一个Animal接口的切片。

package main

import (
    "fmt"
)

type Animal interface {
    Sound() string
}

type Dog struct {
}

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

type Cat struct {
}

func (c Cat) Sound() string {
    return "Meow!"
}

type Cow struct {
}

func (l Cow) Sound() string {
    return "Moo!"
}

func main() {

    animals := []Animal{Dog{}, Cat{}, Cow{}}

    for _, animal := range animals {

        fmt.Println(animal.Sound())
    }
}

该示例定义了一个Animal接口和DogCatCow类型。

type Animal interface {
    Sound() string
}

type Dog struct {
}

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

Dog类型实现了Animal接口的Sound合约函数。

animals := []Animal{Dog{}, Cat{}, Cow{}}

for _, animal := range animals {

    fmt.Println(animal.Sound())
}

因为这三种类型都实现了一个通用接口,所以我们可以将它们放在一个切片中。

$ go run interface_slice.go 
Woof!
Meow!
Moo!

GoStringer接口

Stringer接口在fmt包中定义。当一个类型被传递给任何打印函数时,它的String函数被调用。我们可以自定义自己类型的输出消息。

type Stringer interface {
    String() string
}

这是Stringer接口。

package main

import (
    "fmt"
)

type User struct {
    Name       string
    Occupation string
}

func (u User) String() string {

    return fmt.Sprintf("%s is a(n) %s", u.Name, u.Occupation)
}

func main() {

    u1 := User{"John Doe", "gardener"}
    u2 := User{"Roger Roe", "driver"}

    fmt.Println(u1)
    fmt.Println(u2)
}

在代码示例中,我们为User类型定义了Stringer接口的String函数。

func (u User) String() string {

    return fmt.Sprintf("%s is a(n) %s", u.Name, u.Occupation)
}

该实现返回一个字符串,告诉用户姓名和职业。

$ go run stringer.go 
John Doe is a(n) gardener
Roger Roe is a(n) driver

转到界面{}

Gointerface{}是一个空接口;Go中的所有类型都满足空接口。任何类型都可以分配给声明为空接口的变量。

package main

import (
    "fmt"
)

type Body struct {
    Msg interface{}
}

func main() {

    b := Body{"Hello there"}
    fmt.Printf("%#v %T\n", b.Msg, b.Msg)

    b.Msg = 5
    fmt.Printf("%#v %T\n", b.Msg, b.Msg)
}

我们有interface{}Msg变量。在示例中,我们为变量分配了一个字符串和一个整数。

$ go run empty_interface.go 
"Hello there" string 
5 int

Go类型断言

类型断言x.(T)断言存储在x中的具体值是T类型,并且x不是nil

package main

import (
    "fmt"
)

func main() {

    var val interface{} = "falcon"

    r, ok := val.(string)
    fmt.Println(r, ok)

    r2, ok2 := val.(int)
    fmt.Println(r2, ok2)

    r3 := val.(string)
    fmt.Println(r3)

    //r4 := val.(int)
    //fmt.Println(r4)
}

在代码示例中,我们检查了val变量的类型。

r, ok := val.(string)
fmt.Println(r, ok)

r变量中,我们有值。ok是一个布尔值,判断该值是否为字符串类型。

//r4 := val.(int)
//fmt.Println(r4)

注释行会导致恐慌:interfaceconversion:interface{}isstring,notint

$ go run type_assertion.go 
falcon true
0 false
falcon

在下面的示例中,我们有一个包含string类型键和interface{}值的映射。它允许我们使用各种类型的值。

package main

import (
    "fmt"
    "log"
)

func main() {

    user := make(map[string]interface{}, 0)

    user["name"] = "John Doe"
    user["age"] = 21
    user["weight"] = 70.3

    age, ok := user["age"].(int)

    if !ok {
        log.Fatal("assert failed")
    }

    user["age"] = age + 1

    fmt.Printf("%+v", user)
}

由于值被定义为空接口,年龄的基础类型丢失了。我们需要将该值转换为int以使其递增。

Go类型开关

类型开关用于将接口的具体类型与case语句中提供的多种类型进行比较。

package main

import "fmt"

type User struct {
    Name string
}

func checkType(a interface{}) {

    switch a.(type) {

    case int:
        fmt.Println("Type: int, Value:", a.(int))
    case string:
        fmt.Println("Type: string, Value:", a.(string))
    case float64:
        fmt.Println("Type: float64, Value:", a.(float64))
    case User:
        fmt.Println("Type: User, Value:", a.(User))
    default:
        fmt.Println("unknown type")
    }
}

func main() {

    checkType(4)
    checkType("falcon")
    checkType(User{"John Doe"})
    checkType(7.9)
    checkType(true)
}

checkType函数确定其参数在switch语句中的类型。

$ go run type_switch.go 
Type: int, Value: 4
Type: string, Value: falcon
Type: User, Value: {John Doe}
Type: float64, Value: 7.9
unknown type

(adsbygoogle=window.adsbygoogle||[]).push({});

在本教程中,我们介绍了Golang中的接口类型。

列出所有Go教程。

未经允许不得转载:我爱分享网 » 如何在Golang中使用接口

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏