面向對象 接口?雖然Go語言沒有繼承和多态,但是Go語言可以通過匿名字段實現繼承,通過接口實現多态,我來為大家科普一下關于面向對象 接口?以下内容希望對你有幫助!
雖然Go語言沒有繼承和多态,但是Go語言可以通過匿名字段實現繼承,通過接口實現多态。
1.介紹1.1 概念在Go語言中,接口是一組方法簽名。接口指定了類型應該具有的方法,類型決定了如何實現這些方法。當某個類型為接口中的所有方法提供了具體的實現細節時,這個類型就被稱為實現了該接口。接口定義了一組方法,如果某個對象實現了該接口的所有方法,則此對象就實現了該接口。
1.2 聲明語法
type 接口名稱 interface {
Method1([參數列表]) [返回值列表]
Method2([參數列表]) [返回值列表]
...
}
示例
// 定義一個接口
type Bird interface {
fly() // 無參數無返回值方法
eat(string2 string) // 有參數無返回值方法
walk(string2 string) string // 有參數有返回值方法
}
// 定義一個鳥類接口
type Birder interface {
fly()
eat(food string)
}
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("谷子")
}
/** 輸出
我是 烏鴉,我會飛....
我是 烏鴉,我喜歡吃 谷子
*/
如果有幾個相似而不完全相同的對象,有時人們要求在向它們發出同一個消息時,它們的反應各不相同,分别執行不同的操作,這種情況就是多态現象。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.1 定義空接口
// 定義一個空接口
type A interface {}
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] {合肥 安徽}]
*/
保存到空接口的值,如果直接取出指定類型的值時,會發生編譯錯誤。
錯誤示例:
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
*/
// 方式一
instance,ok := 接口對象.(實際類型)
// 方式二
接口對象.(實際類型)
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}
*/
微信搜索【猿碼記】,獲取最新文章信息。[機智]
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!