Go语言教程之边写边学:接口 interface
声明接口类型
接口是一种抽象类型。
接口描述方法集的所有方法,并为每个方法提供签名。
若要创建接口,请使用interface关键字,后跟包含方法名称列表的大括号,以及方法应具有的任何参数或返回值。
// Declare an Interface Type and methods does not have a body
type Employee interface {
PrintName() string // Method with string return type
PrintAddress(id int) // Method with int parameter
PrintSalary(b int, t int) float64 // Method with parameters and return type
}
接口充当方法集的蓝图,它们必须在使用之前实现。满足接口的类型即实现该接口。
定义满足接口的类型
使用两种方法定义名为Employee的接口类型。然后,它定义一个名为Emp的类型,该类型满足员工。
我们在Emp上定义了满足员工所需的所有方法
package main
import "fmt"
// 声明接口
type Employee interface {
PrintName(name string)
PrintSalary(basic int, tax int) int
}
// Emp用户自定义类型
type Emp int
// 实现接口方法
func (e Emp) PrintName(name string) {
fmt.Println("Employee Id:\t", e)
fmt.Println("Employee Name:\t", name)
}
// 实现接口方法
func (e Emp) PrintSalary(basic int, tax int) int {
var salary = (basic * tax) / 100
return basic - salary
}
func main() {
var e1 Employee
e1 = Emp(1)
e1.PrintName("John Doe")
fmt.Println("Employee Salary:", e1.PrintSalary(25000, 5))
}
如果一个类型具有接口中声明的所有方法,则不需要进一步的声明来显式表示Emp满足 Employee。
声明一个以Employee作为其类型的e1变量,然后创建一个Emp值并将其分配给 e1。
定义满足多个接口的类型
接口允许任何用户定义类型同时满足多种接口类型。
使用类型断言,您可以获取具体类型的值,并且可以调用在其他接口上定义的方法,但不是满足接口的一部分。
package main
import "fmt"
type Polygons interface {
Perimeter()
}
type Object interface {
NumberOfSide()
}
type Pentagon int
func (p Pentagon) Perimeter() {
fmt.Println("Perimeter of Pentagon", 5*p)
}
func (p Pentagon) NumberOfSide() {
fmt.Println("Pentagon has 5 sides")
}
func main() {
var p Polygons = Pentagon(50)
p.Perimeter()
var o Pentagon = p.(Pentagon)
o.NumberOfSide()
var obj Object = Pentagon(50)
obj.NumberOfSide()
var pent Pentagon = obj.(Pentagon)
pent.Perimeter()
}
当用户定义类型实现接口类型声明的方法集时,可以将用户定义类型的值分配给接口类型的值。此赋值将用户定义类型的值存储到接口值中。对接口值进行方法调用时,将执行存储的用户定义值的等效方法。由于任何用户定义类型都可以实现任何接口,因此针对接口值的方法调用本质上是多态的。此关系中的用户定义类型通常称为具体类型。
通用方法接口
两个或多个接口可以在方法集列表中具有一个或多个常用方法。在这里,Structure是Vehicle和Human两个界面之间的常用方法。
package main
import "fmt"
type Vehicle interface {
Structure() []string // Common Method
Speed() string
}
type Human interface {
Structure() []string // Common Method
Performance() string
}
type Car string
func (c Car) Structure() []string {
var parts = []string{"ECU", "Engine", "Air Filters", "Wipers", "Gas Task"}
return parts
}
func (c Car) Speed() string {
return "200 Km/Hrs"
}
type Man string
func (m Man) Structure() []string {
var parts = []string{"Brain", "Heart", "Nose", "Eyelashes", "Stomach"}
return parts
}
func (m Man) Performance() string {
return "8 Hrs/Day"
}
func main() {
var bmw Vehicle
bmw = Car("World Top Brand")
var labour Human
labour = Man("Software Developer")
for i, j := range bmw.Structure() {
fmt.Printf("%-15s <=====> %15s\n", j, labour.Structure()[i])
}
}
输出
ECU <=====> Brain
Engine <=====> Heart
Air Filters <=====> Nose
Wipers <=====> Eyelashes
Gas Task <=====> Stomach
接受变量地址的接口
Print()方法接受接收器指针。因此,接口还必须接受接收器指针。
如果方法接受类型值,则接口必须接收类型值;如果方法具有指针接收器,则接口必须接收相应类型的变量的地址。
package main
import "fmt"
type Book struct {
author, title string
}
type Magazine struct {
title string
issue int
}
func (b *Book) Assign(n, t string) {
b.author = n
b.title = t
}
func (b *Book) Print() {
fmt.Printf("Author: %s, Title: %s\n", b.author, b.title)
}
func (m *Magazine) Assign(t string, i int) {
m.title = t
m.issue = i
}
func (m *Magazine) Print() {
fmt.Printf("Title: %s, Issue: %d\n", m.title, m.issue)
}
type Printer interface {
Print()
}
func main() {
var b Book
var m Magazine
b.Assign("Jack Rabbit", "Book of Rabbits")
m.Assign("Rabbit Weekly", 26)
var i Printer
fmt.Println("Call interface")
i = &b
i.Print()
i = &m
i.Print()
}
空接口类型
类型接口{}称为空接口,它用于接受任何类型的值。空接口没有任何满足它所需的方法,因此每种类型都满足它。
package main
import "fmt"
func printType(i interface{}) {
fmt.Println(i)
}
func main() {
var manyType interface{}
manyType = 100
fmt.Println(manyType)
manyType = 200.50
fmt.Println(manyType)
manyType = "Germany"
fmt.Println(manyType)
printType("Go programming language")
var countries = []string{"india", "japan", "canada", "australia", "russia"}
printType(countries)
var employee = map[string]int{"Mark": 10, "Sandy": 20}
printType(employee)
country := [3]string{"Japan", "Australia", "Germany"}
printType(country)
}
manyType变量被声明为类型接口 {},并且能够为其分配不同类型的值。printType()函数采用类型接口{}的参数,因此该函数可以采用任何有效类型的值。
输出
100
200.5
Germany
Go programming language
[india japan canada australia russia]
map[Mark:10 Sandy:20]
[Japan Australia Germany]
多态性
多态性是编写代码的能力,这些代码可以通过类型实现来承担不同的行为。
我们声明了一个名为五边形、六边形、八边形和十边形的结构,其中包含Geometry接口的实现。
package main
import (
"fmt"
)
type Geometry interface {
Edges() int
}
type Pentagon struct{}
type Hexagon struct{}
type Octagon struct{}
type Decagon struct{}
func (p Pentagon) Edges() int { return 5 }
func (h Hexagon) Edges() int { return 6 }
func (o Octagon) Edges() int { return 8 }
func (d Decagon) Edges() int { return 10 }
func Parameter(geo Geometry, value int) int {
num := geo.Edges()
calculation := num * value
return calculation
}
func main() {
p := new(Pentagon)
h := new(Hexagon)
o := new(Octagon)
d := new(Decagon)
g := [...]Geometry{p, h, o, d}
for _, i := range g {
fmt.Println(Parameter(i, 5))
}
}
输出
25
30
40
50
我们有多态Edges()函数,它接受实现Geometry接口的值。使用多态方法,Parameter()使用传入的每个具体类型值。
接口嵌入
接口可以嵌入其他接口,此行为是接口多态性的一个方面,称为临时多态性。
package main
import "fmt"
type Geometry interface {
Edges() int
}
type Polygons interface {
Geometry // 嵌入接口
}
type Pentagon int
type Hexagon int
type Octagon int
type Decagon int
func (p Pentagon) Edges() int { return 5 }
func (h Hexagon) Edges() int { return 6 }
func (o Octagon) Edges() int { return 8 }
func (d Decagon) Edges() int { return 10 }
func main() {
p := new(Pentagon)
h := new(Hexagon)
o := new(Octagon)
d := new(Decagon)
polygons := [...]Polygons{p, h, o, d}
for i := range polygons {
fmt.Println(polygons[i].Edges())
}
}
当一种类型嵌入到另一种类型中时,嵌入类型的方法可用于嵌入类型。嵌入式接口的方法可供嵌入接口访问。