<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
介面在物件導向程式設計中是經常使用的招式,也是體現多型很重要的手段。
是的。Golang中也有介面這玩意兒。
多數情況下,資料可能包含不同的型別,卻會有一個或者多個共同點,這些共同點就是抽象的基礎。前文講到的Golang繼承解決的是is-a的問題,單一繼承的關係。但是當不同的父類別具有相同的行為的時候,單一繼承就沒法解決了。
於是乎,介面出現了。介面可以理解為某一個方面的抽象,可以是多對一的(多個型別實現一個介面),這也是多型的體現。解決了上文一對一的問題。
是什麼
介面是一組僅包含方法名、引數、返回值的未具體實現的方法的集合。
如果實現了介面的所有方法,則認為實現了該介面,無需在該型別上顯示的新增宣告。
這個解釋下,加深印象,在php中介面是長這樣的:
//定義介面 interface base{ public function getName(); } //學生類 class student implements base{ public function getName(){ echo "咖啡色的羊駝"; } }
這裡有個關鍵字:implements。
這樣的宣告稱之為顯示的,而在Golang中介面是隱式地實現。(埋個伏筆看下文)
定義
type interfaceName interface { // 方法列表 GetName() string }
實際程式設計中呢,介面的命名大夥兒喜歡使用er結尾。當然這個看個人喜好。
上程式碼:
package main import ( "fmt" ) // 定義一個介面 type People interface { ReturnName() string } // 定義一個結構體 type Student struct { Name string } // 定義結構體的一個方法。 // 突然發現這個方法同介面People的所有方法(就一個),此時可直接認為結構體Student實現了介面People func (s Student) ReturnName() string { return s.Name } func main() { cbs := Student{Name:"咖啡色的羊駝"} var a People // 因為Students實現了介面所以直接賦值沒問題 // 如果沒實現會報錯:cannot use cbs (type Student) as type People in assignment:Student does not implement People (missing ReturnName method) a = cbs name := a.ReturnName() fmt.Println(name) // 輸出"咖啡色的羊駝" }
使用介面特有的斷言判斷來實現(下文還會再次提到,加深印象)。
語法:x.(T)
這樣的語法只適應於x是interface型別
接著上文例子,繼續上程式碼:
// 由於x.(T)只能是介面型別判斷,所以傳參時候,傳入的是介面型別 // 為何test的型別可以是一個空介面?埋伏筆下文便知。 func CheckPeople(test interface{}) { if _, ok := test.(People); ok { fmt.Printf("Student implements People") } } func main() { cbs := Student{Name:"咖啡色的羊駝"} CheckPeople(cbs) // Student implements People }
空介面
空介面就是不包含任何方法的介面。正因為如此,所有的型別都實現了空介面。
雖然空介面起不到任何作用,但是空介面在需要儲存任何型別數值的時候非常有用,這也回答了上文的問題,因為空介面可以儲存任意型別的資料。
// 定義cbs為空介面 var cbs interface{} var i int = 5 var s string = "Hello world" // cbs可以儲存任意型別的數值 cbs = i cbs = s
型別斷言
既然空介面可以儲存任意型別,那麼如何區分不同的型別?
常用的有兩種方法:Comma-ok斷言、switch判斷。
上程式碼:
package main import ( "fmt" ) // 定義一個結構體 type Student struct { Name string } // 型別斷言 func main() { Params := make([]interface{}, 3) Params[0] = 88 // 整型 Params[1] = "咖啡色的羊駝" // 字串 Params[2] = Student{Name: "cbs"} // 自定義結構體型別 // Comma-ok斷言 for index, v := range Params { if _, ok := v.(int); ok { fmt.Printf("Params[%d] 是int型別 n", index) } else if _, ok := v.(string); ok { fmt.Printf("Params[%d] 是字串型別n", index) } else if _, ok := v.(Student); ok { fmt.Printf("Params[%d] 是自定義結構體型別n", index) } else { fmt.Printf("list[%d] 未知型別n", index) } } // switch判斷 for index, v := range Params { switch value := v.(type) { case int: fmt.Printf("Params[%d] 是int型別, 值:%d n", index,value) case string: fmt.Printf("Params[%d] 是字串型別, 值:%sn", index,value) case Student: fmt.Printf("Params[%d] 是Person型別, 值:%sn", index,value) default: fmt.Printf("list[%d] 未知型別n", index) } } }
介面的零值是nil
package main import ( "fmt" ) type People interface { GetName() string } // 輸出 "cbs is nil 型別" func main() { var cbs People if cbs == nil { fmt.Println("cbs is nil 型別") } }
package main import ( "fmt" ) type People interface { ReturnName() string } type Role interface { ReturnRole() string } type Student struct { Name string } func (s Student) ReturnName() string { return s.Name } func (s Student) ReturnRole() string { return "學生" } func main() { cbs := Student{Name: "咖啡色的羊駝"} var a People // 定義a為People介面型別 var b Role // 定義b為Role介面型別 a = cbs // 由於Student實現了People所有方法,所以介面實現成功,可直接賦值 b = cbs // 由於Student實現了Role所有方法,所以介面實現成功,可直接賦值 name := a.ReturnName() fmt.Println(name) // 輸出"咖啡色的羊駝" role := b.ReturnRole() fmt.Println(role) // 輸出"學生" }
也說明一個東西:實現了某個介面的型別,還可以有其它的方法。只要是方法實現包含介面的即可。
package main import ( "fmt" ) type People interface { ReturnName() string } type Student struct { Name string } type Teacher struct { Name string } func (s Student) ReturnName() string { return s.Name } func (t *Teacher) ReturnName() string { return t.Name } func main() { cbs := Student{Name: "咖啡色的羊駝"} sss := Teacher{Name: "咖啡色的羊駝的老師"} // 值型別 var a People a = cbs name := a.ReturnName() fmt.Println(name) // 指標型別 // a = sss <- 這樣寫不行!!! a = &sss // 由於是指標型別,所以賦值的時候需要加上& name = a.ReturnName() fmt.Println(name) // 輸出"咖啡色的羊駝的老師" }
"a = sss"這樣寫會發生報錯:
cannot use sss (type Teacher) as type People in assignment:
Teacher does not implement People (ReturnName method has pointer receiver)
因為是Teacher的指標實現了ReturnName方法,Teacher本身沒實現。
類似於PHP的介面繼承,Golang也有它的介面巢狀。
package main import ( "fmt" ) type People interface { ReturnName() string } type Role interface { People // 介面巢狀 ReturnRole() string } type Student struct { Name string } func (s Student) ReturnName() string { return s.Name } func (s Student) ReturnRole() string { return "學生" } func main() { cbs := Student{Name: "咖啡色的羊駝"} var a Role a = cbs name := a.ReturnName() fmt.Println(name) role := a.ReturnRole() fmt.Println(role) }
到此這篇關於從零開始學Golang的介面的文章就介紹到這了,更多相關Golang 介面內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45