【Go语言】面向对象扩展——接口
簡單地說 Interface是一組Method的組合,可以通過Interface來定義對象的一組行為。
如果某個對象實現了某個接口的所有方法,就表示它實現了該借口,無需顯式地在該類型上添加接口說明。
Interface是一個方法的集合,它里面沒有其他類型變量,而且Method只用定義原型 不用實現
①接口定義
1.命名時習慣以"er"結尾,如Printer Reader Writer
2.一個Interface的Method不宜過多,一般0~3個
3.一個Interface可以被任意的對象事項;相應地,一個對象也可以實現多個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(){}//根據struct的方法提取接口 從而使struct自動實現了該接口 type Speaker interface{SayHi() } type Learner interface{SayHi()Study() }?
上面的例子中,Speaker接口被對象People,Teacher,Student實現;而Student同時實現了接口Speaker和Learner。
接口組合:
type SpeakLearner interface {SpeakerLearner }//組合后使得SpeakLearner具有Speaker和Learner的功能?
空接口:
任何類型都實現了空接口,相當于Java中的Object類
func test(a interface{}){}//該方法可以接受任意類型(int rune float32 struct...)的參數?
②接口執行機制和接口賦值
首先介紹一種Go語言帶接收者(Receiver)的函數機制(下面的兩種情況執行結果一樣,涉及到struct成員值改變時仍然一樣)
情況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的函數均可被People或者*People兩種類型調用,接下來借可能有在調用過程中People與*People之間的轉換問題
看下面的例子:
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) }?
以上程序的執行結果為:
{3,4} {4,5} &{3,4} &{4,5}?
可以看出實際執行的過程按函數定義前的Receiver類型執行。
對于接口的執行機制:
1.T僅擁有屬于T類型的方法集,而*T則同時擁有(T+*T)方法集
2.基于T實現方法,表示同時實現了interface和interface(*T)接口
3.基于*T實現方法,那就只能是對interface(*T)實現接口
?
接口賦值舉例:
package main import("fmt" ) //定義對象People、Teacher和Student type People struct {Name string } type Teacher struct{PeopleDepartment string } type Student struct{PeopleSchool string } //對象方法實現 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能存儲Peopleis.SayHi()is = teacher //is能存儲Teacheris.SayHi()is = studentis.SayHi() //is能存儲Studentvar il Learneril = student //Learner類型接口的變量能存儲Student il.Study() }?
執行結果為:
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.?
通過這個例子可以 看到(如同Java等語言)接口機制在多態和創建可擴展可重用的代碼時的重要作用
③匿名字段和接口轉換
若果接口類型S內部嵌入了接口類型T(匿名),則接口匿名字段方法集規則如下:
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實現了Speaker接口is.Say1()is.Say2()//is = s1 //S1類型嵌入匿名People 不存在Say2()方法 因而未實現Speaker接口//錯誤提示: 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()方法都有 實現了Speaker接口is.Say1()is.Say2()is = &s1 //S1類型嵌入匿名People *S1 實現了Speaker接口is.Say1()is.Say2()is = &s2 //S2類型嵌入匿名*People *S2 實現了Speaker接口is.Say1()is.Say2()}?
?執行結果為:
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條規則。
接口轉換類似于說是接口繼承規則 可認為是實現復雜接口(方法多)向簡單接口(方法少)轉換,其中簡單接口中的方法在復雜接口中均有聲明 。例如:
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測試
?利用接口類型推斷可以 反向知道接口類型變量里面實際保存的是哪一種類型的對象。
Go語言中,常用兩種方法可以進行接口類型推斷,即Comma-ok斷言和Switch測試
Comma-ok斷言使用格式如下
value,ok = element.(T)?
用法示例:
//利用Comma-ok斷言進行接口類型推斷 package main import("fmt" )type People struct{Name stringAge int }//定義空接口用于存儲任意類型數據類型 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)}} }?
結果是這樣的:
objs[0]類型是int,value=1 objs[1]類型是bool,value=true objs[2]類型是string,value=Hello objs[3]類型是Peole,value={張三 20}?
使用Switch測試判斷接口類型,程序結構更加簡潔,示例如下(只修改了示例中的main函數):
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)}} }?
執行結果Comma-ok方法相同,但是程序簡潔了許多。
轉載于:https://www.cnblogs.com/Mike-zh/p/3787679.html
總結
以上是生活随笔為你收集整理的【Go语言】面向对象扩展——接口的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 孕妇梦到发洪水什么预兆
- 下一篇: 18款 非常实用 jquery幻灯片图片