tft每日頭條

 > 圖文

 > 面向對象 接口

面向對象 接口

圖文 更新时间:2024-07-26 11:10:25

面向對象 接口?雖然Go語言沒有繼承和多态,但是Go語言可以通過匿名字段實現繼承,通過接口實現多态,我來為大家科普一下關于面向對象 接口?以下内容希望對你有幫助!

面向對象 接口(Go學習十四:面向對象-接口)1

面向對象 接口

雖然Go語言沒有繼承和多态,但是Go語言可以通過匿名字段實現繼承,通過接口實現多态。

1.介紹1.1 概念

在Go語言中,接口是一組方法簽名。接口指定了類型應該具有的方法,類型決定了如何實現這些方法。當某個類型為接口中的所有方法提供了具體的實現細節時,這個類型就被稱為實現了該接口。接口定義了一組方法,如果某個對象實現了該接口的所有方法,則此對象就實現了該接口。

1.2 聲明語法

type 接口名稱 interface { Method1([參數列表]) [返回值列表] Method2([參數列表]) [返回值列表] ... }

示例

// 定義一個接口 type Bird interface { fly() // 無參數無返回值方法 eat(string2 string) // 有參數無返回值方法 walk(string2 string) string // 有參數有返回值方法 }

2.定義和實現2.1 定義接口

// 定義一個鳥類接口 type Birder interface { fly() eat(food string) }

2.2 實現接口

Go沒有implements或extends關鍵字,類型都是隐式實現接口的。任何定義了接口中所有方法的類型都被稱為隐式地實現了該接口。

package main import "fmt" // 定義一個鳥類接口 type Birder interface { fly() eat(food string) } // 定義烏鴉結構體 type Crow struct { name string } // -------- 下面開始實現Bird接口 ------ func (c Crow) fly() { fmt.Printf("我是 %s,我會飛....\n", c.name) } func (c Crow) eat(food string) { fmt.Printf("我是 %s,我喜歡吃 %s \n", c.name,food) } // -------- 實現鳥類接口的所有方法,就代表實現了接口 ------ func main() { crow := Crow{"烏鴉"} crow.fly() crow.eat("谷子") } /** 輸出 我是 烏鴉,我會飛.... 我是 烏鴉,我喜歡吃 谷子 */

3. 模拟多态3.1 什麼是多态?

如果有幾個相似而不完全相同的對象,有時人們要求在向它們發出同一個消息時,它們的反應各不相同,分别執行不同的操作,這種情況就是多态現象。Go語言中的多态性是在接口的幫助下實現的——定義接口類型,創建實現該接口的結構體對象。

3.2 使用示例

定義接口類型的對象,可以保存實現該接口的任何類型的值。Go語言接口變量的這個特性實現了Go語言中的多态性。

實現: 寫一個函數,接收不同類型的結構體,并打印不同其方法。

package main import "fmt" // 定義一個飛行器接口 type Flying interface { getName() string } // 定義小鳥結構體 type bird struct { name string } // bird實現接口 func (b bird) getName() string { return b.name } // 定義飛機結構體 type aircraft struct { name string } // aircraft實現接口 func (a aircraft) getName() string { return a.name } // 定義ufo結構體 type ufo struct { name string } // ufo實現接口 func (u ufo) getName() string { return u.name } // 寫一個函數,接收不同類型的結構體,并打印不同其方法。 func print(flyList []Flying) { for _,v := range flyList { fmt.Printf("我是%s,我會飛.....\n",v.getName()) } } func main() { // 定義一個接口切片 flyList := make([]Flying,0,3) bird := bird{"小鳥"} aircraft := aircraft{"飛機"} ufo := ufo{"UFO"} flyList = append(flyList, bird,aircraft,ufo) fmt.Printf("len: %d cap:%d val: %v \n",len(flyList),cap(flyList),flyList) // 調用函數 print(flyList) } /** 輸出 len: 3 cap:3 val: [{小鳥} {飛機} {UFO}] 我是小鳥,我會飛..... 我是飛機,我會飛..... 我是UFO,我會飛..... */

4.空接口

空接口是接口類型的特殊形式,空接口沒有任何方法,因此任何類型都無須實現空接口。從實現的角度看,任何值都滿足這個接口的需求。因此空接口類型可以保存任何值,也可以從空接口中取出原值。

4.1 定義空接口

// 定義一個空接口 type A interface {}

4.2 保存任意類型

package main import "fmt" // 定義一個空接口 type A interface { } func main() { // 聲明變量 var a A // 保存整型 a = 10 fmt.Printf("保存整型: %v \n", a) // 保存字符串 a = "hello word" fmt.Printf("保存字符串: %v \n", a) // 保存數組 a = [3]float32{1.0, 2.0, 3.0} fmt.Printf("保存數組: %v \n", a) // 保存切片 a = []string{"您", "好"} fmt.Printf("保存切片: %v \n", a) // 保存Map a = map[string]int{ "張三": 22, "李四": 25, } fmt.Printf("保存map: %v \n", a) // 保存結構體 a = struct { name string age int }{"王麻子", 40} fmt.Printf("保存結構體: %v \n", a) // 聲明一個空接口切片 var aa []A // 保存任意類型數據到切片中 aa = append(aa, 23, []string{"php", "go"}, map[string]int{"a": 1, "b": 2}, struct { city,province string }{"合肥","安徽"}) fmt.Printf("空接口切片: %v \n", aa) } /** 輸出: 保存整型: 10 保存字符串: hello word 保存數組: [1 2 3] 保存切片: [您 好] 保存map: map[張三:22 李四:25] 保存結構體: {王麻子 40} 空接口切片: [23 [php go] map[a:1 b:2] {合肥 安徽}] */

4.3 從空接口中取值

保存到空接口的值,如果直接取出指定類型的值時,會發生編譯錯誤。

錯誤示例:

package main import "fmt" // 定義一個空接口 type I interface { } func main() { // 聲明變量num num := 10 // 把變量num存到空接口中 var i I = num fmt.Printf("輸出變量i: %v \n", i) // 從空接口中取出值,賦值給新的變量 var c int = i // (!!! 這裡會報錯) fmt.Printf("輸出變量c: %v \n", c) } /** 輸出 ./main.go:16:6: cannot use i (type I) as type int in assignment: need type assertion */

正确示例:

package main import "fmt" // 定義一個空接口 type I interface { } func main() { // 聲明變量num num := 10 // 把變量num存到空接口中 var i I = num fmt.Printf("輸出變量i: %v \n", i) // 從空接口中取出值,賦值給新的變量 var c int = i.(int) fmt.Printf("輸出變量c: %v \n", c) } /** 輸出變量i: 10 輸出變量c: 10 */

5. 接口對象轉換5.1 轉換語法

// 方式一 instance,ok := 接口對象.(實際類型) // 方式二 接口對象.(實際類型)

5.2 使用示例

package main import "fmt" // 定義一個空接口 type I interface { } func main() { // 聲明變量 var a I // 保存整型 a = 10 printType(a) printType2(a) // 保存字符串 a = "hello word" printType(a) printType2(a) // 保存數組 a = [3]float32{1.0, 2.0, 3.0} printType(a) printType2(a) // 保存切片 a = []string{"您", "好"} printType(a) printType2(a) // 保存Map a = map[string]string{ "張三": "男", "小麗": "女", } printType(a) printType2(a) // 保存結構體 a = people{"劉山", 32} printType(a) printType2(a) } // 定義結構體 type people struct { name string age int } // 方式一 func printType(i I) { if t, ok := i.(int); ok { echo(t) } else if t, ok := i.(string); ok { echo(t) } else if t, ok := i.(map[string]string); ok { echo(t) } else if t, ok := i.([]int); ok { echo(t) } else if t, ok := i.([3]string); ok { echo(t) } else if t, ok := i.(people); ok { echo(t) } } // 方式二 func printType2(i I) { switch i.(type) { case int: echo2(i) case string: echo2(i) case map[string]string: echo2(i) case []int: echo2(i) case [3]string: echo2(i) case people: echo2(i) } } func echo(i interface{}) { fmt.Printf("方式一 ---> 變量i類型: %T 值: %v \n", i, i) } func echo2(i interface{}) { fmt.Printf("方式二 ---> 變量i類型: %T 值: %v \n", i, i) } /**輸出 方式一 ---> 變量i類型: int 值: 10 方式二 ---> 變量i類型: int 值: 10 方式一 ---> 變量i類型: string 值: hello word 方式二 ---> 變量i類型: string 值: hello word 方式一 ---> 變量i類型: map[string]string 值: map[小麗:女 張三:男] 方式二 ---> 變量i類型: map[string]string 值: map[小麗:女 張三:男] 方式一 ---> 變量i類型: main.people 值: {劉山 32} 方式二 ---> 變量i類型: main.people 值: {劉山 32} */

6. 使用注意事項
  • 接口本身不能創建實例,但是可以指向一個實現了該接口的自定義類型的變量(實例)
  • 接口中所有的方法都沒有方法體,即都是沒有實現的方法。
  • 在 Go中,一個自定義類型需要将某個接口的所有方法都實現,我們說這個自定義類型實現 了該接口。
  • 一個自定義類型隻有實現了某個接口,才能将該自定義類型的實例(變量)賦給接口類型
  • 隻要是自定義數據類型,就可以實現接口,不僅僅是結構體類型
  • 一個自定義類型可以實現多個接口
  • Go接口中不能有任何變量
  • interface類型默認是一個指針(引用類型),如果沒有對interface初始化就使用,那麼會輸出nil
  • 空接口 interface{} 沒有任何方法,所以所有類型都實現了空接口, 即我們可以把任何一個變量 賦給空接口

微信搜索【猿碼記】,獲取最新文章信息。[機智]

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关圖文资讯推荐

热门圖文资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved