本文为译文 Interfaces - I
interface是一组方法的签名。当一个类型提供了接口方法所有的定义后,我们说这个类型实现了该接口。
For example WashingMachine can be an interface with method signatures Cleaning() and Drying(). Any type which provides definition for Cleaning() and Drying() methods is said to implement the WashingMachine interface.
package main
import (
"fmt"
)
//interface definition
type VowelsFinder interface {
FindVowels() []rune
}
type MyString string
//MyString implements VowelsFinder
func (ms MyString) FindVowels() []rune {
var vowels []rune
for _, rune := range ms {
if rune == 'a' || rune == 'e' || rune == 'i' || rune == 'o' || rune == 'u' {
vowels = append(vowels, rune)
}
}
return vowels
}
func main() {
name := MyString("Sam Anderson")
var v VowelsFinder
v = name // possible since MyString implements VowelsFinder
fmt.Printf("Vowels are %c", v.FindVowels())
}
上面的例子如果我们使用name.FindVowels()也可以。因此貌似interface没啥用,我们下来再看一个例子。
package main
import (
"fmt"
)
type SalaryCalculator interface {
CalculateSalary() int
}
type Permanent struct {
empId int
basicpay int
pf int
}
type Contract struct {
empId int
basicpay int
}
//salary of permanent employee is the sum of basic pay and pf
func (p Permanent) CalculateSalary() int {
return p.basicpay + p.pf
}
//salary of contract employee is the basic pay alone
func (c Contract) CalculateSalary() int {
return c.basicpay
}
/*
total expense is calculated by iterating through the SalaryCalculator slice and summing
the salaries of the individual employees
*/
func totalExpense(s []SalaryCalculator) {
expense := 0
for _, v := range s {
expense = expense + v.CalculateSalary()
}
fmt.Printf("Total Expense Per Month $%d", expense)
}
func main() {
pemp1 := Permanent{
empId: 1,
basicpay: 5000,
pf: 20,
}
pemp2 := Permanent{
empId: 2,
basicpay: 6000,
pf: 30,
}
cemp1 := Contract{
empId: 3,
basicpay: 3000,
}
employees := []SalaryCalculator{pemp1, pemp2, cemp1}
totalExpense(employees)
}
接口的内部表示
package main
import (
"fmt"
)
type Worker interface {
Work()
}
type Person struct {
name string
}
func (p Person) Work() {
fmt.Println(p.name, "is working")
}
func describe(w Worker) {
fmt.Printf("Interface type %T value %v\n", w, w)
}
func main() {
p := Person{
name: "Naveen",
}
var w Worker = p
describe(w)
w.Work()
}
Interface type main.Person value {Naveen}
Naveen is working
注意:上面程序接口w的类型为main.Person值为Naveen
空接口
没有方法的接口叫空接口。所有的类型都实现了空接口。
package main
import (
"fmt"
)
func describe(i interface{}) {
fmt.Printf("Type = %T, value = %v\n", i, i)
}
func main() {
s := "Hello World"
describe(s)
i := 55
describe(i)
strt := struct {
name string
}{
name: "Naveen R",
}
describe(strt)
}
Type = string, value = Hello World
Type = int, value = 55
Type = struct { name string }, value = {Naveen R}
类型断言
类型断言被用于提取接口潜在的值。
具体语法i.(T)
package main
import (
"fmt"
)
func assert(i interface{}) {
s := i.(int) //get the underlying int value from i
fmt.Println(s)
}
func main() {
var intVal = 56
assert(intVal)
/*
panic: interface conversion: interface {} is string, not int
goroutine 1 [running]:
main.assert({0x1091240?, 0xc000092f60?})
*/
// var strVal = "56"
// assert(strVal)
}
第8行代码断言接口一定是int类型。
如果不是int型则会报错,具体解决办法 we can use the syntax
v, ok := i.(T)
package main
import (
"fmt"
)
func assert(i interface{}) {
v, ok := i.(int)
fmt.Println(v, ok)
}
func main() {
var s interface{} = 56
assert(s)
var i interface{} = "Steven Paul"
assert(i)
}
56 true
0 false
type switch
package main
import (
"fmt"
)
type Describer interface {
Describe()
}
type Person struct {
name string
age int
}
func (p Person) Describe() {
fmt.Printf("%s is %d years old", p.name, p.age)
}
func findType(i interface{}) {
switch v := i.(type) {
case Describer:
v.Describe()
case string:
fmt.Printf("I am a string and my value is %s\n", v)
case int:
fmt.Printf("I am an int and my value is %d\n", v)
default:
fmt.Printf("Unknown type\n")
}
}
func main() {
findType("Naveen")
findType(77)
findType(89.98)
p := Person{
name: "Naveen R",
age: 25,
}
findType(p)
}
I am a string and my value is Naveen
I am an int and my value is 77
Unknown type
Naveen R is 25 years old