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是一种通用的几何形式。它无法绘制。Rectangle和Circle是特定的几何图形,可以画出来,也可以计算面积。
type Shape interface {
Area() float64
}
我们定义了Shape接口。它有一个函数签名:Area。
type Rectangle struct {
Width, Height float64
}
type Circle struct {
Radius float64
}
我们定义了两种类型:Rectangle和Circle。
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
我们为Rectangle和Circle定义了Area函数;我们说这两种类型实现了Shape接口。
func getArea(shape Shape) {
fmt.Println(shape.Area())
}
getArea函数将Shape接口作为参数。我们可以同时传递Rectangle和Circle,因为它们都是形状。
$ 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接口和Dog、Cat和Cow类型。
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教程。
