什么是 Interface
在面向?qū)ο蟮氖澜缰校涌诘囊话愣x是“接口定義對(duì)象的行為”兔毙,即只定義對(duì)象的行為柠辞,至于對(duì)象如何行動(dòng)則具體實(shí)現(xiàn)在對(duì)象中。
在 Golang 中走触,接口是一組方法簽名晦譬,當(dāng)一個(gè)類型為接口中的所有方法提供定義時(shí),就說實(shí)現(xiàn)了該接口互广。接口指定類型應(yīng)具有的方法敛腌,類型決定如何實(shí)現(xiàn)這些方法。
接口的定義和實(shí)現(xiàn)
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())
interface 應(yīng)用場(chǎng)景
類 java 中的多態(tài)
package main
import (
"fmt"
)
// 接口定義
type SalaryCalculator interface {
CalculateSalary() int
}
// 類型1
type Permanent struct {
empId int
basicpay int
pf int
}
// 類型2
type Contract struct {
empId int
basicpay int
}
// Permanent salary 計(jì)算實(shí)現(xiàn)
func (p Permanent) CalculateSalary() int {
return p.basicpay + p.pf
}
// Contract salary 計(jì)算實(shí)現(xiàn)
func (c Contract) CalculateSalary() int {
return c.basicpay
}
/*
通過對(duì)SalalCalculator切片進(jìn)行迭代并求和來計(jì)算總費(fèi)用個(gè)人雇員的工資
*/
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{1, 5000, 20}
pemp2 := Permanent{2, 6000, 30}
cemp1 := Contract{3, 3000}
employees := []SalaryCalculator{pemp1, pemp2, cemp1}
totalExpense(employees)
}
在上述程序片段中惫皱,totalExpense
接收一個(gè) interface slice像樊,可以應(yīng)用于任何實(shí)現(xiàn)SalaryCalculator
interface 的類型,若我們添加一個(gè)新的類型旅敷,實(shí)現(xiàn)一種新的薪資計(jì)算方式生棍,上述代碼可以完全不需要修改即可使用。
用于內(nèi)部表示
可以將接口視為由元組(類型媳谁,值)在內(nèi)部表示涂滴。type是接口的基礎(chǔ)具體類型,value持有具體類型的值晴音。
type Tester interface {
Test()
}
type MyFloat float64
func (m MyFloat) Test() {
fmt.Println(m)
}
func describe(t Tester) {
fmt.Printf("Interface type %T value %v\n", t, t)
}
func main() {
var t Tester
f := MyFloat(89.7)
t = f // 此處將類型賦值柔纵,
describe(t) // 此處的輸出為 Interface type main.MyFloat value 89.7
t.Test()
}
空接口
空接口中沒有任何方法,表示為 interface{}
段多,由于空接口沒有任何方法首量,因此可以理解為所有類型默認(rèn)實(shí)現(xiàn)了此接口。
func describe(i interface{}) {
fmt.Printf("Type = %T, value = %v\n", i, i)
}
func main() {
s := "Hello World"
describe(s) // Type = string, value = Hello World
i := 55
describe(i) // Type = int, value = 55
strt := struct {
name string
}{
name: "Naveen R",
}
describe(strt) // Type = struct { name string }, value = {Naveen R}
}
類型判定
可以使用語法 i.(T)
獲取變量i中T
類型的值进苍,以此來判斷傳入的類型是否正確
s := i.(int) // 獲取變量 i 中 int 類型的數(shù)據(jù)加缘,若 i 不是 int, 則 panic
v, ok := i.(int) // 用這種方式避免 panic
此外觉啊,也可以配合 switch
實(shí)現(xiàn)類型判斷
func findType(i interface{}) {
switch i.(type) {
case string:
fmt.Printf("I am a string and my value is %s\n", i.(string))
case int:
fmt.Printf("I am an int and my value is %d\n", i.(int))
default:
fmt.Printf("Unknown type\n")
}
}
當(dāng)然拣宏,也可以將類型與接口進(jìn)行比較。如果我們有一個(gè)類型杠人,并且該類型實(shí)現(xiàn)了一個(gè)接口勋乾,則可以將該類型與其實(shí)現(xiàn)的接口進(jìn)行比較宋下。
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()
default:
fmt.Printf("unknown type\n")
}
}
通過嵌入接口,實(shí)現(xiàn)繼承的功能
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
}
// Employee 實(shí)現(xiàn)了 DisplaySalary 和 CalculateLeavesLeft 兩個(gè)接口辑莫,也就默認(rèn)實(shí)現(xiàn)了 EmployeeOperations 接口
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,
}
// 此處可以說 Employee 實(shí)現(xiàn)了 EmployeeOperations接口
var empOp EmployeeOperations = e
empOp.DisplaySalary()
fmt.Println("\nLeaves left =", empOp.CalculateLeavesLeft())
}
接口的 0 值
接口的零值為nil学歧。
nil接口具有其基礎(chǔ)值和具體類型(如nil)。
type Describer interface {
Describe()
}
func main() {
var d1 Describer
if d1 == nil {
// 此處輸出 d1 is nil and has type <nil> value <nil>
fmt.Printf("d1 is nil and has type %T value %v\n", d1, d1)
}
}
喜歡的話各吨,訪問我的主頁吧枝笨,請(qǐng)多關(guān)照!