一、概念
1、 面向物件語言中,介面用于定義物件的行為,介面只指定物件應該做什么,實作這種行為的方法(實作細節)是由物件來決定,
2、 在Go語言中,介面是一組方法簽名,
- •介面只指定了型別應該具有的方法,型別決定了如何實作這些方法,
- •當某個型別為介面中的所有方法提供了具體的實作細節時,這個型別就被稱為實作了該介面,
- •介面定義了一組方法,如果某個物件實作了該介面的所有方法,則此物件就實作了該介面,
3、 Go語言的型別都是隱式實作介面的,任何定義了介面中所有方法的型別都被稱為隱式地實作了該介面,
二、介面的使用
go沒有 implements, extends 關鍵字,其實這種編程語言叫做duck typing編程語言,

package mainimport "fmt"import "base"//定義介面type Phone interface { call()}type AndroidPhone struct {}type IPhone struct {}func (a AndroidPhone) call() { fmt.Println("我是安卓手機,可以打電話了")}func (i IPhone) call() { fmt.Println("我是蘋果手機,可以打電話了")}func main() { // 定義介面型別的變數 var phone Phone //phone = new(AndroidPhone) phone = AndroidPhone{} fmt.Printf("%T , %v , %p \n" , phone , phone , &phone) phone.call() //phone = new(IPhone) phone = IPhone{} fmt.Printf("%T , %v , %p \n" , phone , phone , &phone) phone.call()}View Code
動態型別與靜態型別語言
- •動態型別的好處很多,Python代碼寫起來很快,但是缺陷也是顯而易見的:錯誤往往要在運行時才能被發現,
- •相反,靜態型別語言往往在編譯時就是發現這類錯誤:如果某個變數的型別沒有顯式宣告實作了某個介面,那么,這個變數就不能用在要求一個實作了這個介面的地方,
Go型別系統采取了折中的辦法:
•之所以說這是一種折中的辦法,原因如下:
- 〇第一,結構體型別T不需要顯式地宣告它實作了介面 I,只要型別T實作了介面1規定的所有方法,它就自動地實作了介面 I,這樣就像動態語言一樣省了很多代碼,少了許多限制,
- 〇第二,將結構體型別的變數顯式或者隱式地轉換為介面 I型別的變數i,這樣就可以和其它靜態型別語言一樣,在編譯時檢查引數的合法性,
三、多型
•事物的多種形態
- • Go中的多型性是在介面的幫助下實作的,定義介面型別,倉U建實作該介面的結構體物件,
- •定義介面型別的物件,可以保存實作該介面的任何型別的值,Go語言介面變數的這個特性實作了 Go語言中的多型性,
- •介面型別的物件,不能訪問其實作類中的屬性欄位,

package mainimport "fmt"import "base"type Income interface { calculate() float64 //計算收入總額 source() string //用來說明收入來源}//固定賬單專案type FixedBilling struct { projectName string //工程專案 biddedAmount float64 //專案招標總額}//定時生產專案(定時和材料專案)type TimeAndMaterial struct { projectName string workHours float64 //作業時長 hourlyRate float64 //每小時工資率}//固定收入專案func (f FixedBilling) calculate() float64 { return f.biddedAmount}func (f FixedBilling) source() string { return f.projectName}//定時收入專案func (t TimeAndMaterial) calculate() float64 { return t.workHours * t.hourlyRate}func (t TimeAndMaterial) source() string { return t.projectName}//通過廣告點擊獲得收入type Advertisement struct { adName string clickCount int incomePerclick float64}func (a Advertisement) calculate() float64 { return float64(a.clickCount) * a.incomePerclick}func (a Advertisement) source() string { return a.adName}func main() { p1 := FixedBilling{"專案1", 5000} p2 := FixedBilling{"專案2", 10000} p3 := TimeAndMaterial{"專案3", 100, 40} p4 := TimeAndMaterial{"專案4", 250, 20} p5 := Advertisement{"廣告1", 10000, 0.1} p6 := Advertisement{"廣告2", 20000, 0.05} ic := []Income{p1, p2, p3, p4, p5, p6} fmt.Println("total=",calculateNetIncome(ic))}//計算凈收入func calculateNetIncome(ic []Income) float64 { netincome := 0.0 for _, income := range ic { fmt.Printf("收入來源:%s ,收入金額:%.2f \n", income.source(), income.calculate()) netincome += income.calculate() } return netincome}View Code
四、空介面
•空介面 :該介面中沒有任何的方法,任意型別都可以實作該介面,
•空interface這樣定義:interface{},也就是包含0個method的interface,
•用空介面表示任意資料型別,類似于java中的object,
•空介面常用于以下情形:
〇 1、println的引數就是空介面
〇 2、定義一個map: key是string,value是任意資料型別
〇 3、定義一個切片,其中存盤任意型別的資料

package mainimport ( "fmt")type A interface {}type Cat struct { name string age int}type Person struct { name string sex string}func main() { var a1 A = Cat{"Mimi", 1} var a2 A = Person{"Steven", "男"} var a3 A = "Learn golang with me!" var a4 A = 100 var a5 A = 3.14 showInfo(a1) showInfo(a2) showInfo(a3) showInfo(a4) showInfo(a5) fmt.Println("------------------") //1、fmt.println引數就是空介面 fmt.Println("println的引數就是空介面,可以是任何資料型別", 100, 3.14, Cat{"旺旺", 2}) //2、定義map,value是任何資料型別 map1 := make(map[string]interface{}) map1["name"] = "Daniel" map1["age"] = 13 map1["height"] = 1.71 fmt.Println(map1) fmt.Println("------------------") // 3、定義一個切片,其中存盤任意資料型別 slice1 := make([]interface{}, 0, 10) slice1 = append(slice1, a1, a2, a3, a4, a5) fmt.Println(slice1) transInterface(slice1) //var cat1 A = Cat{"MiaoMiao" , 3} //fmt.Println(cat1.name , cat1.age)}//介面物件轉型//介面物件.(type),配合switch...case陳述句func transInterface(s []interface{}) { for i := range s { fmt.Println("第", i+1 , "個資料:") switch t := s[i].(type) { case Cat: fmt.Printf("\t Cat物件,name屬性:%s,age屬性:%d \n" , t.name , t.age) case Person: fmt.Printf("\t Person物件,name屬性:%s,sex屬性:%s \n" , t.name , t.sex) case string: fmt.Println("\t string型別" , t) case int: fmt.Println("\t int型別" , t) case float64: fmt.Println("\t float64型別" , t) } }}func showInfo(a A) { fmt.Printf("%T , %v \n", a, a)}View Code
五、介面物件轉型
1、 方式一:
• instance, ok :=介面物件.(實際型別)
•如果該介面物件是對應的實際型別,那么instance就是轉型之后物件,ok的值為true
•配合if... else if...陳述句使用
2、 方式二:
•介面物件.(type)
•配合switch...case陳述句使用

package mainimport "fmt"import ( "base" "math")//1、定義介面type Shape interface { perimeter() float64 area() float64}//2.矩形type Rectangle struct { a, b float64}//3.三角形type Triangle struct { a, b, c float64}//4.圓形type Circle struct { radius float64}//定義實作介面的方法func (r Rectangle) perimeter() float64 { return (r.a + r.b) * 2}func (r Rectangle) area() float64 { return r.a * r.b}func (t Triangle) perimeter() float64 { return t.a + t.b + t.c}func (t Triangle) area() float64 { //海倫公式 p := t.perimeter() / 2 //半周長 return math.Sqrt(p * (p - t.a) * (p - t.b) * (p - t.c))}func (c Circle) perimeter() float64 { return 2 * math.Pi * c.radius}func (c Circle) area() float64 { return math.Pow(c.radius, 2) * math.Pi}//介面物件轉型方式1//instance,ok := 介面物件.(實際型別)func getType(s Shape) { if instance, ok := s.(Rectangle); ok { fmt.Printf("矩形:長度%.2f , 寬度%.2f , ", instance.a, instance.b) } else if instance, ok := s.(Triangle); ok { fmt.Printf("三角形:三邊分別:%.2f , %.2f , %.2f , ", instance.a, instance.b, instance.c) } else if instance, ok := s.(Circle); ok { fmt.Printf("圓形:半徑%.2f , ", instance.radius) }}//介面物件轉型——方式2//介面物件.(type), 配合switch和case陳述句使用func getType2(s Shape) { switch instance := s.(type) { case Rectangle: fmt.Printf("矩形:長度為%.2f , 寬為%.2f ,\t", instance.a, instance.b) case Triangle: fmt.Printf("三角形:三邊分別為%.2f ,%.2f , %.2f ,\t", instance.a, instance.b, instance.c) case Circle: fmt.Printf("圓形:半徑為%.2f ,\t", instance.radius) }}func getResult(s Shape) { getType2(s) fmt.Printf("周長:%.2f ,面積:%.2f \n", s.perimeter(), s.area())}func main() { var s Shape s = Rectangle{3, 4} getResult(s) showInfo(s) s = Triangle{3, 4, 5} getResult(s) showInfo(s) s = Circle{1} getResult(s) showInfo(s) x := Triangle{3, 4, 5} fmt.Println(x)}func (t Triangle) String() string { return fmt.Sprintf("Triangle物件,屬性分別為:%.2f, %.2f, %.2f", t.a, t.b, t.c)}func showInfo(s Shape) { fmt.Printf("%T ,%v \n", s, s) fmt.Println("-------------------")}View Code
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/67383.html
標籤:Go
上一篇:GO基礎之結構體
下一篇:go-面向物件編程(上)

