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教程。