实例讲解 Go 的 Interface
Go 接口
Go中的接口是使用一组方法签名定义的类型。该接口为类似类型的对象定义行为。
例如,这是一个定义几何形状行为的接口:
// Go 接口 - `形状`
type Shape interface {
Area() float64
Perimeter() float64
}
使用** type **关键字声明接口,然后使用接口名称和关键字interface
声明接口。然后,在花括号内指定一组方法签名。
在 Go 中实现接口
要实现接口,您只需实现接口中声明的所有方法。
Go接口是隐式实现的
与Java之类的其他语言不同,您无需明确指定类型使用诸如implements
关键字之类的东西来实现接口。您只需实现接口中声明的所有方法即可。
这是两种实现Shape
接口的Struct类型:
//结构类型`Rectangle`-通过实现其所有方法来实现`Shape`接口。
type Rectangle struct {
Length, Width float64
}
func (r Rectangle) Area() float64 {
return r.Length * r.Width
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Length + r.Width)
}
//结构类型`Circle`-通过实现其所有方法来实现`Shape`接口。
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
func (c Circle) Diameter() float64 {
return 2 * c.Radius
}
使用具有具体值的接口类型
除非我们将接口与实现其所有方法的具体类型一起使用,否则接口本身并不是那么有用。
让我们看看如何将接口与具体值一起使用。
-接口类型可以包含实现其所有方法的任何值
```
package main
import (
"fmt"
)
func main() {
var s Shape = Circle{5.0}
fmt.Printf("Shape Type = %T, Shape Value = %v\n", s, s)
fmt.Printf("Area = %f, Perimeter = %f\n\n", s.Area(), s.Perimeter())
s = Rectangle{4.0, 6.0}
fmt.Printf("Shape Type = %T, Shape Value = %v\n", s, s)
fmt.Printf("Area = %f, Perimeter = %f\n", s.Area(), s.Perimeter())
}
```
```
# 输出
Shape Type = main.Circle, Shape Value = {5}
Area = 78.539816, Perimeter = 31.415927
Shape Type = main.Rectangle, Shape Value = {4 6}
Area = 24.000000, Perimeter = 20.000000
```
-使用接口类型作为函数的参数
package main import ( "fmt" ) // 通用函数,用于计算不同类型的多个形状的总面积 func CalculateTotalArea(shapes ...Shape) float64 { totalArea := 0.0 for _, s := range shapes { totalArea += s.Area() } return totalArea } func main() { totalArea := CalculateTotalArea(Circle{2}, Rectangle{4, 5}, Circle{10}) fmt.Println("Total area = ", totalArea) }
# 输出 Total area = 346.7256359733385
//接口类型也可以用作字段
package main import ( "fmt" ) // Interface types can also be used as fields type MyDrawing struct { shapes []Shape bgColor string fgColor string } func (drawing MyDrawing) Area() float64 { totalArea := 0.0 for _, s := range drawing.shapes { totalArea += s.Area() } return totalArea } func main() { drawing := MyDrawing{ shapes: []Shape{ Circle{2}, Rectangle{3, 5}, Rectangle{4, 7}, }, bgColor: "red", fgColor: "white", } fmt.Println("Drawing", drawing) fmt.Println("Drawing Area = ", drawing.Area()) }
# 输出 Drawing {[{2} {3 5} {4 7}] red white} Drawing Area = 55.56637061435917
接口的值:接口类型如何处理具体的值
在底层,接口的值可以认为是由值和具体类型组成的元组:
// 接口
(value, type)
接下来让我们看一个例子:
package main
import (
"fmt"
)
func main() {
var s Shape
s = Circle{5}
fmt.Printf("(%v, %T)\n", s, s)
fmt.Printf("Shape area = %v\n", s.Area())
s = Rectangle{4, 7}
fmt.Printf("(%v, %T)\n", s, s)
fmt.Printf("Shape area = %v\n", s.Area())
}
# 输出
({5}, main.Circle)
Shape area = 78.53981633974483
({4 7}, main.Rectangle)
Shape area = 28
检出上述程序的输出,并注意变量s
如何获得有关该值的信息以及为其分配的Shape
的类型。
当我们在接口值上调用方法时,将在其基础类型上执行相同名称的方法。
例如, 在上述程序中,当我们在变量s
上调用方法Area()
时,它将执行其基础类型的Area()
方法。
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
推荐文章: