【Go语言】面向对象扩展——接口
簡(jiǎn)單地說 Interface是一組Method的組合,可以通過Interface來定義對(duì)象的一組行為。
如果某個(gè)對(duì)象實(shí)現(xiàn)了某個(gè)接口的所有方法,就表示它實(shí)現(xiàn)了該借口,無需顯式地在該類型上添加接口說明。
Interface是一個(gè)方法的集合,它里面沒有其他類型變量,而且Method只用定義原型 不用實(shí)現(xiàn)
①接口定義
1.命名時(shí)習(xí)慣以"er"結(jié)尾,如Printer Reader Writer
2.一個(gè)Interface的Method不宜過多,一般0~3個(gè)
3.一個(gè)Interface可以被任意的對(duì)象事項(xiàng);相應(yīng)地,一個(gè)對(duì)象也可以實(shí)現(xiàn)多個(gè)Interface
示例:
type People struct{Name string } type Student struct{PeopleSchool string } type Teacher struct{PeopleDepartment string } func (p People) SayHi(){} func (s Student) SayHi(){} func (t Teacher) SayHi(){} func (s Student) Study(){}//根據(jù)struct的方法提取接口 從而使struct自動(dòng)實(shí)現(xiàn)了該接口 type Speaker interface{SayHi() } type Learner interface{SayHi()Study() }?
上面的例子中,Speaker接口被對(duì)象People,Teacher,Student實(shí)現(xiàn);而Student同時(shí)實(shí)現(xiàn)了接口Speaker和Learner。
接口組合:
type SpeakLearner interface {SpeakerLearner }//組合后使得SpeakLearner具有Speaker和Learner的功能?
空接口:
任何類型都實(shí)現(xiàn)了空接口,相當(dāng)于Java中的Object類
func test(a interface{}){}//該方法可以接受任意類型(int rune float32 struct...)的參數(shù)?
②接口執(zhí)行機(jī)制和接口賦值
首先介紹一種Go語言帶接收者(Receiver)的函數(shù)機(jī)制(下面的兩種情況執(zhí)行結(jié)果一樣,涉及到struct成員值改變時(shí)仍然一樣)
情況1:
package mainimport ("fmt" )type People struct {Name string }func (p People) SayHi(){ //此處的Receiver是strcutfmt.Println("hello, this is", p.Name) } func (p *People) Study(){//此處的Receiver是****structfmt.Printf("%s is studying\n", p.Name) } type SpeakLearner interface {SayHi()Study() } func main() {people := People{"zhangsan"}//這里的people為People類型 people.SayHi()people.Study() }?
情況2:
func main() {people := &People{"zhangsan"}//這里的people為**People類型,即指針 people.SayHi()people.Study() }?
通過上面的例子可以看出Receiver為People和*People的函數(shù)均可被People或者*People兩種類型調(diào)用,接下來借可能有在調(diào)用過程中People與*People之間的轉(zhuǎn)換問題
看下面的例子:
package mainimport ("fmt" ) type Example struct{Integer1 intInteger2 int } func (e Example) Assign(num1 int, num2 int) {e.Integer1, e.Integer2 = num1, num2 } func (e *Example) Add(num1 int, num2 int) {e.Integer1 +=num1e.Integer2 +=num2 } func main(){var e1 Example = Example{3,4}e1.Assign(1,1)fmt.Println(e1)e1.Add(1,1)fmt.Println(e1)var e2 *Example = &Example{3,4}e2.Assign(1,1)fmt.Println(e2)e2.Add(1,1)fmt.Println(e2) }?
以上程序的執(zhí)行結(jié)果為:
{3,4} {4,5} &{3,4} &{4,5}?
可以看出實(shí)際執(zhí)行的過程按函數(shù)定義前的Receiver類型執(zhí)行。
對(duì)于接口的執(zhí)行機(jī)制:
1.T僅擁有屬于T類型的方法集,而*T則同時(shí)擁有(T+*T)方法集
2.基于T實(shí)現(xiàn)方法,表示同時(shí)實(shí)現(xiàn)了interface和interface(*T)接口
3.基于*T實(shí)現(xiàn)方法,那就只能是對(duì)interface(*T)實(shí)現(xiàn)接口
?
接口賦值舉例:
package main import("fmt" ) //定義對(duì)象People、Teacher和Student type People struct {Name string } type Teacher struct{PeopleDepartment string } type Student struct{PeopleSchool string } //對(duì)象方法實(shí)現(xiàn) func (p People) SayHi() {fmt.Printf("Hi, I'm %s. Nice to meet you!\n",p.Name) } func (t Teacher) SayHi(){fmt.Printf("Hi, my name is %s. I'm working in %s .\n", t.Name, t.Department) } func (s Student) SayHi() {fmt.Printf("Hi, my name is %s. I'm studying in %s.\n", s.Name, s.School) } func (s Student) Study() {fmt.Printf("I'm learning Golang in %s.\n", s.School) } //定義接口Speaker和Learner type Speaker interface{SayHi() } type Learner interface{SayHi()Study() } func main() {people := People{"張三"}teacher := Teacher{People{"鄭智"}, "Computer Science"}student := Student{People{"李明"}, "Yale University"}var is Speaker //定義Speaker接口類型的變量is = people //is能存儲(chǔ)Peopleis.SayHi()is = teacher //is能存儲(chǔ)Teacheris.SayHi()is = studentis.SayHi() //is能存儲(chǔ)Studentvar il Learneril = student //Learner類型接口的變量能存儲(chǔ)Student il.Study() }?
執(zhí)行結(jié)果為:
Hi, I'm 張三. Nice to meet you! Hi, my name is 鄭智. I'm working in Computer Science . Hi, my name is 李明. I'm studying in Yale University. I'm learning Golang in Yale University.?
通過這個(gè)例子可以 看到(如同Java等語言)接口機(jī)制在多態(tài)和創(chuàng)建可擴(kuò)展可重用的代碼時(shí)的重要作用
③匿名字段和接口轉(zhuǎn)換
若果接口類型S內(nèi)部嵌入了接口類型T(匿名),則接口匿名字段方法集規(guī)則如下:
1.如果S嵌入匿名類型T,則S方法集包含T方法集。
2.如果S嵌入匿名類型*T,則S方法集包含*T方法集(包括Riceiver為T和*T的方法)。
3.如果S嵌入匿名類型T或*T,則*S方法集包含*T方法集(包括Riceiver為T和*T的方法)。(重要)
例如:
package main import("fmt" )type People struct {Name string } type S1 struct{People //S1類型嵌入匿名PeopleDepartment string } type S2 struct{*People //S2類型嵌入匿名*PeopleDepartment string } func (p People) Say1() {fmt.Printf("Hi, I'm %s. Say1111\n",p.Name) } func (p *People) Say2() {fmt.Printf("Hi, I'm %s. Say2222\n",p.Name) } type Speaker interface{Say1()Say2() }func main() {people := People{"張三"}s1 := S1{People{"鄭智"}, "Computer Science"}s2 := S2{&People{"李明"}, "Math"}var is Speaker is = &people //*People實(shí)現(xiàn)了Speaker接口is.Say1()is.Say2()//is = s1 //S1類型嵌入匿名People 不存在Say2()方法 因而未實(shí)現(xiàn)Speaker接口//錯(cuò)誤提示: cannot use s1 (type S1) as type Speaker in assignment://S1 does not implement Speaker (Say2 method has pointer receiver)is = s2 //S2類型嵌入匿名*People 因而(p People) Say1()和(p *People) Say2()方法都有 實(shí)現(xiàn)了Speaker接口is.Say1()is.Say2()is = &s1 //S1類型嵌入匿名People *S1 實(shí)現(xiàn)了Speaker接口is.Say1()is.Say2()is = &s2 //S2類型嵌入匿名*People *S2 實(shí)現(xiàn)了Speaker接口is.Say1()is.Say2()}?
?執(zhí)行結(jié)果為:
Hi, I'm 張三. Say1111 Hi, I'm 張三. Say2222 Hi, I'm 李明. Say1111 Hi, I'm 李明. Say2222 Hi, I'm 鄭智. Say1111 Hi, I'm 鄭智. Say2222 Hi, I'm 李明. Say1111 Hi, I'm 李明. Say2222?
從而證明了匿名字段方法集的3條規(guī)則。
接口轉(zhuǎn)換類似于說是接口繼承規(guī)則 可認(rèn)為是實(shí)現(xiàn)復(fù)雜接口(方法多)向簡(jiǎn)單接口(方法少)轉(zhuǎn)換,其中簡(jiǎn)單接口中的方法在復(fù)雜接口中均有聲明 。例如:
package main import("fmt" ) type People struct {Name string } type Student struct{PeopleSchool string } func (p People) GetPeopleInfo() {fmt.Println(p) } func (s Student) GetStudentInfo() {fmt.Println(s) } type PeopleInfo interface{GetPeopleInfo() } type StudentInfo interface{GetPeopleInfo()GetStudentInfo() } func main() {var is StudentInfo = Student{People{"李明"}, "Yele University"}is.GetStudentInfo()is.GetPeopleInfo()var ip PeopleInfo = isip.GetPeopleInfo()///ip.GetStudentInfo() note:ip.GetStudentInfo undefined }?
④接口類型推斷:Comma-ok斷言和Switch測(cè)試
?利用接口類型推斷可以 反向知道接口類型變量里面實(shí)際保存的是哪一種類型的對(duì)象。
Go語言中,常用兩種方法可以進(jìn)行接口類型推斷,即Comma-ok斷言和Switch測(cè)試
Comma-ok斷言使用格式如下
value,ok = element.(T)?
用法示例:
//利用Comma-ok斷言進(jìn)行接口類型推斷 package main import("fmt" )type People struct{Name stringAge int }//定義空接口用于存儲(chǔ)任意類型數(shù)據(jù)類型 type Object interface{}func main() {people := People{"張三", 20}objs := make([]Object, 4)objs[0], objs[1], objs[2], objs[3] = 1, true, "Hello", peoplefor index, element := range objs{if value, ok := element.(int); ok{fmt.Printf("objs[%d]類型是int,value=%d\n", index, value)}else if value, ok := element.(bool); ok{fmt.Printf("objs[%d]類型是bool,value=%v\n", index, value)}else if value, ok := element.(string); ok{fmt.Printf("objs[%d]類型是string,value=%s\n", index, value)}else if value, ok := element.(People); ok{fmt.Printf("objs[%d]類型是Peole,value=%v\n", index, value)}else{fmt.Printf("objs[%d]類型未知\n", index)}} }?
結(jié)果是這樣的:
objs[0]類型是int,value=1 objs[1]類型是bool,value=true objs[2]類型是string,value=Hello objs[3]類型是Peole,value={張三 20}?
使用Switch測(cè)試判斷接口類型,程序結(jié)構(gòu)更加簡(jiǎn)潔,示例如下(只修改了示例中的main函數(shù)):
func main() {people := People{"張三", 20}objs := make([]Object, 4)objs[0], objs[1], objs[2], objs[3] = 1, true, "Hello", peoplefor index, element := range objs{switch value := element.(type){case int:fmt.Printf("objs[%d]類型是int,value=%d\n", index, value)case bool:fmt.Printf("objs[%d]類型是bool,value=%v\n", index, value)case string:fmt.Printf("objs[%d]類型是string,value=%s\n", index, value)case People:fmt.Printf("objs[%d]類型是Peole,value=%v\n", index, value)default:fmt.Printf("objs[%d]類型未知\n", index)}} }?
執(zhí)行結(jié)果Comma-ok方法相同,但是程序簡(jiǎn)潔了許多。
轉(zhuǎn)載于:https://www.cnblogs.com/Mike-zh/p/3787679.html
總結(jié)
以上是生活随笔為你收集整理的【Go语言】面向对象扩展——接口的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 孕妇梦到发洪水什么预兆
- 下一篇: 18款 非常实用 jquery幻灯片图片