Go語言學習6:接口

interface

接口定義了一組方法,但是這些方法不包含實現代碼(它們是抽象的),接口裏也不能包含變量。

接口指定了一個類型應該具有的方法,並由該類型決定如何實現這些方法。類型通過實現一個接口的所有方法來實現該接口。

通常在有兩個或以上的具體類型(struct)以相同的方式(method)進行處理時使用接口。

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 sum of basic pay and pf
//此方法表示類型Permanent實現了接口SalaryCalculator
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 though the SalaryCalculator slice and summing
the salaries of the individual employees
*/
func totalExpense(s []SalaryCalculator) {
    expense := 0
    for _, v := range s {
    	//v是接口類型,但會去執行對應結構體上的方法
        expense = expense + v.CalculateSalary()
    }
    fmt.Printf("Total Expense Per Month $%d", expense)
}

func main() {
    pemp1 := Permanent{1, 1000, 10}
    pemp2 := Permanent{2, 2000, 20}
    cemp1 := Contract{3, 3000}
    employees := []SalaryCalculator{pemp1, pemp2, cemp1}
    totalExpense(employees)
}

上述例子中,對象pemp1是Permanent類型,對象cemp1是Contract類型,這兩個類型都實現了SalaryCalculator接口中的所有方法,即實現了這個接口。所以pemp1和cemp1也都屬於SalaryCalculator接口類型。

所有實現了接口的類型,都可以把它的值保存在一個接口類型的變量中。在 Go 中,我們使用接口的這種特性來實現面向對象編程中的多態。

空interface

空interface(interface{})不包含任何的方法,所以所有的類型都實現了空interface。一般用在需要存儲任意類型的數值的時候,如一個函數把interface{}作爲參數,那麼它可以接收任意類型的值作爲參數。

判斷interface變量存儲的類型

interface可以存儲任意類型的數值,怎麼反向知道到底存儲了什麼類型呢?兩個方法:

  1. 類型斷言:value, ok = element.(T)
    value是變量的值,ok是bool類型,element是interface變量,T是類型。

  2. switch實現上述方法:

    for index, element := range list {
    	switch value := element.(type) {
    		case int:
    			// do something
    		case string:
    			// do something
    		default:
    			// ...
    	}
    }
    

嵌入interface

儘管 Go 語言沒有提供繼承機制,但可以通過嵌套其他的接口,創建一個新接口。

類似struct的匿名字段,一個interface1也可以作爲另一個interface2的嵌入字段,此時,interface2就包含了interface1的方法。

package main

import (  
    "fmt"
)

type SalaryCalculator interface {  
    DisplaySalary()
}

type LeaveCalculator interface {  
    CalculateLeavesLeft() int
}

type EmployeeOperations interface {  
    SalaryCalculator
    LeaveCalculator
}

type Employee struct {  
    firstName string
    lastName string
    basicPay int
    pf int
    totalLeaves int
    leavesTaken int
}

func (e Employee) DisplaySalary() {  
    fmt.Printf("%s %s has salary $%d", e.firstName, e.lastName, (e.basicPay + e.pf))
}

func (e Employee) CalculateLeavesLeft() int {  
    return e.totalLeaves - e.leavesTaken
}

func main() {  
    e := Employee {
        firstName: "Naveen",
        lastName: "Ramanathan",
        basicPay: 5000,
        pf: 200,
        totalLeaves: 30,
        leavesTaken: 5,
    }
    var empOp EmployeeOperations = e
    empOp.DisplaySalary()
    fmt.Println("\nLeaves left =", empOp.CalculateLeavesLeft())
}

上述例子中,接口 EmployeeOperations嵌套了兩個接口:SalaryCalculatorLeaveCalculator

如果一個類型定義了 SalaryCalculatorLeaveCalculator 接口裏包含的方法,我們就稱該類型實現了 EmployeeOperations 接口。

由於 Employee 結構體定義了 DisplaySalaryCalculateLeavesLeft 方法,因此它實現了接口 EmployeeOperations

所以可以把Employee類型的e賦值給EmployeeOperations類型的empOpempOp 就可以調用 DisplaySalary()CalculateLeavesLeft() 方法了。


學習資料:https://studygolang.com/subject/2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章