咱們在前面去定義一個結構體時候,實際上就是把一類事物的共有的 屬性( 字段)和 行爲( 方法)提取
出來,造成一個 物理模型(結構體)。這種研究問題的方法稱爲抽象
好比一個銀行帳戶:java
package main import ( "fmt" ) //定義一個結構體Account type Account struct { AccountNo string Pwd string Balance float64 } //方法 //1. 存款 func (account *Account) Deposite(money float64, pwd string) { //看下輸入的密碼是否正確 if pwd != account.Pwd { fmt.Println("你輸入的密碼不正確") return } //看看存款金額是否正確 if money <= 0 { fmt.Println("你輸入的金額不正確") return } account.Balance += money fmt.Println("存款成功~~") } //取款 func (account *Account) WithDraw(money float64, pwd string) { //看下輸入的密碼是否正確 if pwd != account.Pwd { fmt.Println("你輸入的密碼不正確") return } //看看取款金額是否正確 if money <= 0 || money > account.Balance { fmt.Println("你輸入的金額不正確") return } account.Balance -= money fmt.Println("取款成功~~") } //查詢餘額 func (account *Account) Query(pwd string) { //看下輸入的密碼是否正確 if pwd != account.Pwd { fmt.Println("你輸入的密碼不正確") return } fmt.Printf("你的帳號爲=%v 餘額=%v \n", account.AccountNo, account.Balance) } func main() { //測試一把 account := Account{ AccountNo : "gs1111111", Pwd : "666666", Balance : 100.0, } //這裏能夠作的更加靈活,就是讓用戶經過控制檯來輸入命令... //菜單.... account.Query("666666") account.Deposite(200.0, "666666") account.Query("666666") account.WithDraw(150.0, "666666") account.Query("666666") }
Golang 仍然有面向對象編程的繼承,封裝和多態的特性,只是實現的方式和其它 OOP 語言不一
樣,下面咱們一一爲同窗們進行詳細的講解 Golang 的三大特性是如何實現的。程序員
封裝(encapsulation)就是把抽象出的字段和對字段的操做封裝在一塊兒,數據被保護在內部,程序的其
它包只有經過被受權的操做(方法),才能對字段進行操做編程
1) 隱藏實現細節
2) 提升對 數據進行驗證,保證安全合理(Age)數組
1) 對結構體中的屬性進行封裝
2) 經過 方法,包 包 實現封裝安全
1) 將結構體、字段(屬性)的首字母小寫(不能導出了,其它包不能使用,相似 private)
2) 給結構體所在包提供一個工廠模式的函數,首字母大寫。相似一個構造函數
3) 提供一個首字母大寫的 Set 方法(相似其它語言的 public),用於對屬性判斷並賦值
func (var 結構體類型名) SetXxx(參數列表) (返回值列表) {
//加入數據驗證的業務邏輯
var.字段 = 參數
}
4) 提供一個首字母大寫的 Get 方法(相似其它語言的 public),用於獲取屬性的值
func (var 結構體類型名) GetXxx() {
return var.age;
}
特別說明:在 Golang 開發中並無特別強調封裝,這點並不像 Java. 因此提醒學過 java 的朋友,
不用老是用 java 的語法特性來看待 Golang, Golang 自己對面向對象的特性作了簡化的.app
請你們看一個程序(person.go),不能隨便查看 人的年齡, 工資等隱私,並對輸入的年齡進行合理的驗
證。設計: model 包(person.go) main 包(main.go 調用 Person 結構體)
main.go函數
package main import ( "fmt" "go_code/code/chapter11/encapsulate/model" ) func main() { p := model.NewPerson("smith") p.SetAge(18) p.SetSal(5000) fmt.Println(p) fmt.Println(p.Name, " age =", p.GetAge(), " sal = ", p.GetSal()) }
moudel學習
package model import "fmt" type person struct { Name string age int //其它包不能直接訪問.. sal float64 } //寫一個工廠模式的函數,至關於構造函數 func NewPerson(name string) *person { return &person{ Name : name, } } //爲了訪問age 和 sal 咱們編寫一對SetXxx的方法和GetXxx的方法 func (p *person) SetAge(age int) { if age >0 && age <150 { p.age = age } else { fmt.Println("年齡範圍不正確..") //給程序員給一個默認值 } } func (p *person) GetAge() int { return p.age } func (p *person) SetSal(sal float64) { if sal >= 3000 && sal <= 30000 { p.sal = sal } else { fmt.Println("薪水範圍不正確..") } } func (p *person) GetSal() float64 { return p.sal }
一個小問題,看個學生考試系統的程序 extends01.go,提出代碼複用的問題
1) Pupil 和 Graduate 兩個結構體的字段和方法幾乎,可是咱們卻寫了相同的代碼, 代碼複用性不
強
2) 出現代碼冗餘,並且代碼 不利於維護,同時 也不利於功能的擴展。
3) 解決方法-經過 繼承方式來解決測試
package main import ( "fmt" ) //編寫一個學生考試系統 type Student struct { Name string Age int Score int } //將Pupil 和 Graduate 共有的方法也綁定到 *Student func (stu *Student) ShowInfo() { fmt.Printf("學生名=%v 年齡=%v 成績=%v\n", stu.Name, stu.Age, stu.Score) } func (stu *Student) SetScore(score int) { //業務判斷 stu.Score = score } //給 *Student 增長一個方法,那麼 Pupil 和 Graduate均可以使用該方法 func (stu *Student) GetSum(n1 int, n2 int) int { return n1 + n2 } //小學生 type Pupil struct { Student //嵌入了Student匿名結構體 } //顯示他的成績 //這時Pupil結構體特有的方法,保留 func (p *Pupil) testing() { fmt.Println("小學生正在考試中.....") } //大學生, 研究生。。 //大學生 type Graduate struct { Student //嵌入了Student匿名結構體 } //顯示他的成績 //這時Graduate結構體特有的方法,保留 func (p *Graduate) testing() { fmt.Println("大學生正在考試中.....") } //代碼冗餘.. 高中生.... func main() { //當咱們對結構體嵌入了匿名結構體使用方法會發生變化 pupil := &Pupil{} pupil.Student.Name = "tom~" pupil.Student.Age = 8 pupil.testing() pupil.Student.SetScore(70) pupil.Student.ShowInfo() fmt.Println("res=", pupil.Student.GetSum(1, 2)) graduate := &Graduate{} graduate.Student.Name = "mary~" graduate.Student.Age = 28 graduate.testing() graduate.Student.SetScore(90) graduate.Student.ShowInfo() fmt.Println("res=", graduate.Student.GetSum(10, 20)) }
繼承能夠解決代碼複用,讓咱們的編程更加靠近人類思惟。
當多個結構體存在相同的屬性(字段)和方法時,能夠從這些結構體中抽象出結構體(好比剛纔的
Student),在該結構體中定義這些相同的屬性和方法。
其它的結構體不須要從新定義這些屬性(字段)和方法,只需嵌套一個 Student 匿名結構體便可
也就是說:在 Golang 中,若是一個 struct 嵌套了另外一個匿名結構體,那麼這個結構體能夠直接訪
問匿名結構體的字段和方法,從而實現了繼承特性。this
type Goods struct { Name string Price int } type Book struct { Goods //這裏就是嵌套匿名結構體 Goods Writer string }
1) 代碼的複用性提升了
2) 代碼的擴展性和維護性提升了
1) 結構體能夠 使用嵌套匿名結構體全部的字段和方法,即:首字母大寫或者小寫的字段、方法,
均可以使用。【舉例說明】
2) 匿名結構體字段訪問能夠簡化
package main import ( "fmt" ) type A struct { Name string age int } func (a *A) SayOk() { fmt.Println("A SayOk", a.Name) } func (a *A) hello() { fmt.Println("A hello", a.Name) } type B struct { A Name string } func (b *B) SayOk() { fmt.Println("B SayOk", b.Name) } func main() { // var b B // b.A.Name = "tom" // b.A.age = 19 // b.A.SayOk() // b.A.hello() // //上面的寫法能夠簡化 // b.Name = "smith" // b.age = 20 // b.SayOk() // b.hello() var b B b.Name = "jack" // ok b.A.Name = "scott" b.age = 100 //ok b.SayOk() // B SayOk jack b.A.SayOk() // A SayOk scott b.hello() // A hello ? "jack" 仍是 "scott" }
對上面的代碼小結
(1) 當咱們直接經過 b 訪問字段或方法時,其執行流程以下好比 b.Name
(2) 編譯器會先看 b 對應的類型有沒有 Name, 若是有,則直接調用 B 類型的 Name 字段
(3) 若是沒有就去看 B 中嵌入的匿名結構體 A 有沒有聲明 Name 字段,若是有就調用,若是沒有
繼續查找..若是都找不到就報錯.
3) 當 結構體和 匿名結構體有相同的字段或者方法時, 編譯器採用就近訪問原則訪問,如但願訪問
匿名結構體的字段和方法,能夠經過匿名結構體名來區分【舉例說明】
4) 結構體嵌入兩個(或多個)匿名結構體,如 兩個匿名結構體有相同的字段和方法( 同時結構體自己
沒有同名的字段和方法),在訪問時,就必須明確指定匿名結構體名字,不然編譯報錯。【舉例說明】
5) 若是一個 struct 嵌套了一個有名結構體,這種模式就是 組合,若是是組合關係,那麼在訪問組合
的結構體的字段或方法時,必須帶上結構體的名字
6) 嵌套匿名結構體後,也能夠在建立結構體變量(實例)時,直接指定各個 匿名結構體字段的值
說明
1) 若是一個結構體有 int 類型的匿名字段,就不能第二個。
2) 若是須要有多個 int 的字段,則必須給 int 字段指定名字
多重繼承說明
如 一個 struct 嵌套了多個匿名結構體,那麼該結構體能夠直接訪問嵌套的匿名結構體的字段和方
法, 從而實現了多重繼承。
多重繼承細節說明
1) 如嵌入的匿名結構體有相同的字段名或者方法名,則在訪問時,須要經過匿名結構體類型名來
區分。【案例演示】
2) 爲了保證代碼的簡潔性,建議你們儘可能不使用多重繼承
package main import ( "fmt" ) type A struct { Name string age int } type B struct { Name string Score float64 } type C struct { A B //Name string } type D struct { a A //有名結構體 } type Goods struct { Name string Price float64 } type Brand struct { Name string Address string } type TV struct { Goods Brand } type TV2 struct { *Goods *Brand } type Monster struct { Name string Age int } type E struct { Monster int n int } func main() { var c C //若是c 沒有Name字段,而A 和 B有Name, 這時就必須經過指定匿名結構體名字來區分 //因此 c.Name 就會包編譯錯誤, 這個規則對方法也是同樣的! c.A.Name = "tom" // error fmt.Println("c") //若是D 中是一個有名結構體,則訪問有名結構體的字段時,就必須帶上有名結構體的名字 //好比 d.a.Name var d D d.a.Name = "jack" //嵌套匿名結構體後,也能夠在建立結構體變量(實例)時,直接指定各個匿名結構體字段的值 tv := TV{ Goods{"電視機001", 5000.99}, Brand{"海爾", "山東"}, } //演示訪問Goods的Name fmt.Println(tv.Goods.Name) fmt.Println(tv.Price) tv2 := TV{ Goods{ Price : 5000.99, Name : "電視機002", }, Brand{ Name : "夏普", Address :"北京", }, } fmt.Println("tv", tv) fmt.Println("tv2", tv2) tv3 := TV2{ &Goods{"電視機003", 7000.99}, &Brand{"創維", "河南"}, } tv4 := TV2{ &Goods{ Name : "電視機004", Price : 9000.99, }, &Brand{ Name : "長虹", Address : "四川", }, } fmt.Println("tv3", *tv3.Goods, *tv3.Brand) fmt.Println("tv4", *tv4.Goods, *tv4.Brand) //演示一下匿名字段時基本數據類型的使用 var e E e.Name = "狐狸精" e.Age = 300 e.int = 20 e.n = 40 fmt.Println("e=", e) }
按順序,咱們應該學習多態,可是在學習多態前,咱們須要講解接口(interface),由於在 Golang 中 多態
特性主要是經過接口來體現的。
這樣的設計需求在 Golang 編程中也是會大量存在的,我曾經說過,一個程序就是一個世界,在現實世
界存在的狀況,在程序中也會出現。 咱們用程序來模擬一下前面的應用場景。
代碼實現
package main import ( "fmt" ) //聲明/定義一個接口 type Usb interface { //聲明瞭兩個沒有實現的方法 Start() Stop() } //聲明/定義一個接口 type Usb2 interface { //聲明瞭兩個沒有實現的方法 Start() Stop() Test() } type Phone struct { } //讓Phone 實現 Usb接口的方法 func (p Phone) Start() { fmt.Println("手機開始工做。。。") } func (p Phone) Stop() { fmt.Println("手機中止工做。。。") } type Camera struct { } //讓Camera 實現 Usb接口的方法 func (c Camera) Start() { fmt.Println("相機開始工做~~~。。。") } func (c Camera) Stop() { fmt.Println("相機中止工做。。。") } //計算機 type Computer struct { } //編寫一個方法Working 方法,接收一個Usb接口類型變量 //只要是實現了 Usb接口 (所謂實現Usb接口,就是指實現了 Usb接口聲明全部方法) func (c Computer) Working(usb Usb) { //經過usb接口變量來調用Start和Stop方法 usb.Start() usb.Stop() } func main() { //測試 //先建立結構體變量 computer := Computer{} phone := Phone{} camera := Camera{} //關鍵點 computer.Working(phone) computer.Working(camera) // }
interface 類型能夠定義一組方法,可是這些不須要實現。而且 interface 不能包含任何變量。到某個
自定義類型(好比結構體 Phone)要使用的時候,在根據具體狀況把這些方法寫出來(實現)。
說明
1) 接口裏的 全部方法都沒有方法體,即接口的方法都是沒有實現的方法。接口體現了程序設計的
多態和 高內聚低偶合的思想。
2) Golang 中的接口, 不須要 顯式的實現。只要一個變量,含有接口類型中的全部方法,那麼這個
變量就實現這個接口。所以,Golang 中 沒有 implement 這樣的關鍵字
注意事項和細節
1) 接口自己 不能建立實例,可是 能夠指向一個實現了該接口的自定義類型的變量(實例)
2) 接口中全部的方法都沒有方法體,即都是沒有實現的方法。
3) 在 Golang 中,一個自定義類型須要將某個接口的全部方法都實現,咱們說這個自定義類型實現了該接口。
4) 一個自定義類型只有實現了某個接口,才能將該自定義類型的實例(變量)賦給接口類型
5) 只要是自定義數據類型,就能夠實現接口,不只僅是結構體類型。
6) 一個自定義類型能夠實現多個接口
7) Golang 接口中不能有任何變量
8) 一個接口(好比 A 接口)能夠繼承多個別的接口(好比 B,C 接口),這時若是要實現 A 接口,也必須將 B,C 接口的方法也所有實現。
9) interface 類型默認是一個指針(引用類型),若是沒有對 interface 初始化就使用,那麼會輸出 nil
10) 空接口 interface{} 沒有任何方法, 因此全部類型都實現了空接 口, 即咱們能夠 把任何一個變量
賦給空接口。
package main import ( "fmt" ) type Stu struct { Name string } func (stu Stu) Say() { fmt.Println("Stu Say()") } type integer int func (i integer) Say() { fmt.Println("integer Say i =" ,i ) } type AInterface interface { Say() } type BInterface interface { Hello() } type Monster struct { } func (m Monster) Hello() { fmt.Println("Monster Hello()~~") } func (m Monster) Say() { fmt.Println("Monster Say()~~") } func main() { var stu Stu //結構體變量,實現了 Say() 實現了 AInterface var a AInterface = stu a.Say() var i integer = 10 var b AInterface = i b.Say() // integer Say i = 10 //Monster實現了AInterface 和 BInterface var monster Monster var a2 AInterface = monster var b2 BInterface = monster a2.Say() b2.Hello() }
package main import ( "fmt" ) type BInterface interface { test01() } type CInterface interface { test02() } type AInterface interface { BInterface CInterface test03() } //若是須要實現AInterface,就須要將BInterface CInterface的方法都實現 type Stu struct { } func (stu Stu) test01() { } func (stu Stu) test02() { } func (stu Stu) test03() { } type T interface{ } func main() { var stu Stu var a AInterface = stu a.test01() var t T = stu //ok fmt.Println(t) var t2 interface{} = stu var num1 float64 = 8.8 t2 = num1 t = num1 fmt.Println(t2, t) }
package main import "fmt" type Usb interface { Say() } type Stu struct { } func (this *Stu) Say() { fmt.Println("Say()") } func main() { var stu Stu = Stu{} // 錯誤! 會報 Stu類型沒有實現Usb接口 , // 若是但願經過編譯, var u Usb = &stu var u Usb = stu u.Say() fmt.Println("here", u) }
實現對 Hero 結構體切片的排序: sort.Sort(data Interface)
package main import ( "fmt" "sort" "math/rand" ) //1.聲明Hero結構體 type Hero struct{ Name string Age int } //2.聲明一個Hero結構體切片類型 type HeroSlice []Hero //3.實現Interface 接口 func (hs HeroSlice) Len() int { return len(hs) } //Less方法就是決定你使用什麼標準進行排序 //1. 按Hero的年齡從小到大排序!! func (hs HeroSlice) Less(i, j int) bool { return hs[i].Age < hs[j].Age //修改爲對Name排序 //return hs[i].Name < hs[j].Name } func (hs HeroSlice) Swap(i, j int) { //交換 // temp := hs[i] // hs[i] = hs[j] // hs[j] = temp //下面的一句話等價於三句話 hs[i], hs[j] = hs[j], hs[i] } //1.聲明Student結構體 type Student struct{ Name string Age int Score float64 } //將Student的切片,安Score從大到小排序!! func main() { //先定義一個數組/切片 var intSlice = []int{0, -1, 10, 7, 90} //要求對 intSlice切片進行排序 //1. 冒泡排序... //2. 也可使用系統提供的方法 sort.Ints(intSlice) fmt.Println(intSlice) //請你們對結構體切片進行排序 //1. 冒泡排序... //2. 也可使用系統提供的方法 //測試看看咱們是否能夠對結構體切片進行排序 var heroes HeroSlice for i := 0; i < 10 ; i++ { hero := Hero{ Name : fmt.Sprintf("英雄|%d", rand.Intn(100)), Age : rand.Intn(100), } //將 hero append到 heroes切片 heroes = append(heroes, hero) } //看看排序前的順序 for _ , v := range heroes { fmt.Println(v) } //調用sort.Sort sort.Sort(heroes) fmt.Println("-----------排序後------------") //看看排序後的順序 for _ , v := range heroes { fmt.Println(v) } i := 10 j := 20 i, j = j, i fmt.Println("i=", i, "j=", j) // i=20 j = 10 }
你們可能會對實現接口和繼承比較迷茫了, 那麼他們究竟有什麼區別呢
package main import ( "fmt" ) //Monkey結構體 type Monkey struct { Name string } //聲明接口 type BirdAble interface { Flying() } type FishAble interface { Swimming() } func (this *Monkey) climbing() { fmt.Println(this.Name, " 生來會爬樹..") } //LittleMonkey結構體 type LittleMonkey struct { Monkey //繼承 } //讓LittleMonkey實現BirdAble func (this *LittleMonkey) Flying() { fmt.Println(this.Name, " 經過學習,會飛翔...") } //讓LittleMonkey實現FishAble func (this *LittleMonkey) Swimming() { fmt.Println(this.Name, " 經過學習,會游泳..") } func main() { //建立一個LittleMonkey 實例 monkey := LittleMonkey{ Monkey { Name : "悟空", }, } monkey.climbing() monkey.Flying() monkey.Swimming() }
1) 當 A 結構體繼承了 B 結構體,那麼 A 結構就自動的繼承了 B 結構體的字段和方法,而且能夠直
接使用
2) 當 A 結構體須要擴展功能,同時不但願去破壞繼承關係,則能夠去實現某個接口便可,所以咱們能夠認爲:實現接口是對繼承機制的補充.實現接口能夠看做是對 繼承的一種補充
接口和繼承解決的解決的問題不一樣
繼承的價值主要在於:解決代碼的 複用性和 可維護性。
接口的價值主要在於: 設計,設計好各類規範(方法),讓其它自定義類型去實現這些方法。
接口比繼承更加靈活 Person Student BirdAble LittleMonkey
接口比繼承更加靈活,繼承是知足 is - a 的關係,而接口只需知足 like - a 的關係。
接口在必定程度上實現 代碼解耦
變量(實例)具備多種形態。面向對象的第三大特徵,在 Go 語言,多態特徵是經過接口實現的。能夠按照統一的接口來調用不一樣的實現。這時接口變量就呈現不一樣的形態。
快速入門
在前面的 Usb 接口案例,Usb usb ,既能夠接收手機變量,又能夠接收相機變量,就體現了 Usb 接口 多態特性。
在前面的 Usb 接口案例,Usb usb ,便可以接收手機變量,又能夠接收相機變量,就體現了 Usb 接多態。
多態數組
演示一個案例:給 Usb 數組中,存放 Phone 結構體 和 Camera 結構體變量
案例說明:
package main import ( "fmt" ) //聲明/定義一個接口 type Usb interface { //聲明瞭兩個沒有實現的方法 Start() Stop() } type Phone struct { name string } //讓Phone 實現 Usb接口的方法 func (p Phone) Start() { fmt.Println("手機開始工做。。。") } func (p Phone) Stop() { fmt.Println("手機中止工做。。。") } type Camera struct { name string } //讓Camera 實現 Usb接口的方法 func (c Camera) Start() { fmt.Println("相機開始工做。。。") } func (c Camera) Stop() { fmt.Println("相機中止工做。。。") } func main() { //定義一個Usb接口數組,能夠存放Phone和Camera的結構體變量 //這裏就體現出多態數組 var usbArr [3]Usb usbArr[0] = Phone{"vivo"} usbArr[1] = Phone{"小米"} usbArr[2] = Camera{"尼康"} fmt.Println(usbArr) }
由一個具體的須要,引出了類型斷言
基本介紹
類型斷言,因爲接口是通常類型,不知道具體類型,若是要轉成具體類型,就須要使用類型斷言,
具體的以下:
package main import ( "fmt" ) type Point struct { x int y int } func main() { var a interface{} var point Point = Point{1, 2} a = point //oK // 如何將 a 賦給一個Point變量? var b Point // b = a 不能夠 // b = a.(Point) // 能夠 b = a.(Point) fmt.Println(b) // //類型斷言的其它案例 // var x interface{} // var b2 float32 = 1.1 // x = b2 //空接口,能夠接收任意類型 // // x=>float32 [使用類型斷言] // y := x.(float32) // fmt.Printf("y 的類型是 %T 值是=%v", y, y) //類型斷言(帶檢測的) var x interface{} var b2 float32 = 2.1 x = b2 //空接口,能夠接收任意類型 // x=>float32 [使用類型斷言] //類型斷言(帶檢測的) if y, ok := x.(float32); ok { fmt.Println("convert success") fmt.Printf("y 的類型是 %T 值是=%v", y, y) } else { fmt.Println("convert fail") } fmt.Println("繼續執行...") }
對上面代碼的說明:
在進行類型斷言時,若是類型不匹配,就會報 panic, 所以進行類型斷言時,要確保原來的空接口
指向的就是斷言的類型.
如何在進行斷言時,帶上檢測機制,若是成功就 ok,不然也不要報 panic
在前面的 Usb 接口案例作改進:
給 Phone 結構體增長一個特有的方法 call(), 當 Usb 接口接收的是 Phone 變量時,還須要調用 call
方法, 走代碼:
package main import ( "fmt" ) //聲明/定義一個接口 type Usb interface { //聲明瞭兩個沒有實現的方法 Start() Stop() } type Phone struct { name string } //讓Phone 實現 Usb接口的方法 func (p Phone) Start() { fmt.Println("手機開始工做。。。") } func (p Phone) Stop() { fmt.Println("手機中止工做。。。") } func (p Phone) Call() { fmt.Println("手機 在打電話..") } type Camera struct { name string } //讓Camera 實現 Usb接口的方法 func (c Camera) Start() { fmt.Println("相機開始工做。。。") } func (c Camera) Stop() { fmt.Println("相機中止工做。。。") } type Computer struct { } func (computer Computer) Working(usb Usb) { usb.Start() //若是usb是指向Phone結構體變量,則還須要調用Call方法 //類型斷言..[注意體會!!!] if phone, ok := usb.(Phone); ok { phone.Call() } usb.Stop() } func main() { //定義一個Usb接口數組,能夠存放Phone和Camera的結構體變量 //這裏就體現出多態數組 var usbArr [3]Usb usbArr[0] = Phone{"vivo"} usbArr[1] = Phone{"小米"} usbArr[2] = Camera{"尼康"} //遍歷usbArr //Phone還有一個特有的方法call(),請遍歷Usb數組,若是是Phone變量, //除了調用Usb 接口聲明的方法外,還須要調用Phone 特有方法 call. =》類型斷言 var computer Computer for _, v := range usbArr{ computer.Working(v) fmt.Println() } //fmt.Println(usbArr) }
寫一函數,循環判斷傳入參數的類型:
package main import ( "fmt" ) //定義Student類型 type Student struct { } //編寫一個函數,能夠判斷輸入的參數是什麼類型 func TypeJudge(items... interface{}) { for index, x := range items { switch x.(type) { case bool : fmt.Printf("第%v個參數是 bool 類型,值是%v\n", index, x) case float32 : fmt.Printf("第%v個參數是 float32 類型,值是%v\n", index, x) case float64 : fmt.Printf("第%v個參數是 float64 類型,值是%v\n", index, x) case int, int32, int64 : fmt.Printf("第%v個參數是 整數 類型,值是%v\n", index, x) case string : fmt.Printf("第%v個參數是 string 類型,值是%v\n", index, x) case Student : fmt.Printf("第%v個參數是 Student 類型,值是%v\n", index, x) case *Student : fmt.Printf("第%v個參數是 *Student 類型,值是%v\n", index, x) default : fmt.Printf("第%v個參數是 類型 不肯定,值是%v\n", index, x) } } } func main() { var n1 float32 = 1.1 var n2 float64 = 2.3 var n3 int32 = 30 var name string = "tom" address := "北京" n4 := 300 stu1 := Student{} stu2 := &Student{} TypeJudge(n1, n2, n3, name, address, n4, stu1, stu2) }
go的面向對象終於完了(^▽^)!~~~~