18、Interfaces - I

123 阅读2分钟

本文为译文 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