日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【Go语言】面向对象扩展——接口

發(fā)布時(shí)間:2023/11/29 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Go语言】面向对象扩展——接口 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

簡(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)接口

type Integer intfunc (a Integer) Less(b Integer) bool {return a < b } func (a *Integer) Add(b Integer) {*a += b } 相應(yīng)地,我們定義接口LessAdder,如下: type LessAdder interface {Less(b Integer) boolAdd(b Integer) }現(xiàn)在有個(gè)問題:假設(shè)我們定義一個(gè)Integer類型的對(duì)象實(shí)例,怎么將其賦值給LessAdder接口呢? 應(yīng)該用下面的語句(1),還是語句(2)呢? var a Integer = 1 var b LessAdder = &a ... (1) var b LessAdder = a ... (2) 答案是應(yīng)該用語句(1)。原因在于,Go語言可以根據(jù)下面的函數(shù): func (a Integer) Less(b Integer) bool 即自動(dòng)生成一個(gè)新的Less()方法: func (a *Integer) Less(b Integer) bool {return (*a).Less(b) } 這樣,類型*Integer就既存在Less()方法,也存在Add()方法,滿足LessAdder接口。而從另一方面來說,根據(jù) func (a *Integer) Add(b Integer) 這個(gè)函數(shù)無法自動(dòng)生成以下這個(gè)成員方法: func (a Integer) Add(b Integer) {(&a).Add(b) } 因?yàn)?&a).Add()改變的只是函數(shù)參數(shù)a,對(duì)外部實(shí)際要操作的對(duì)象并無影響,這不符合用 戶的預(yù)期。所以,Go語言不會(huì)自動(dòng)為其生成該函數(shù)。 因此,類型Integer只存在Less()方法,缺少Add()方法,不滿足LessAdder接口,故此上面的語句(2)不能賦值。

?

接口賦值舉例:

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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。