Golang - 面對"對象"


Golang - 面對"對象"

 

Golang - 面對"對象"

1. 簡介

  • go語言對於面向對象的設計非常簡潔而優雅
  • 沒有封裝、繼承、多態這些概念,但同樣通過別的方式實現這些特性
  • 封裝:通過方法實現
  • 繼承:通過匿名字段實現
  • 多態:通過接口實現

2. 匿名字段

go支持只提供類型而不寫字段名的方式,也就是匿名字段,也稱為嵌入字段

//package 聲明開頭表示代碼所屬包 package main import "fmt" //定義人的結構體 type Person struct { name string sex string age int } //學生 type Student struct { //匿名字段 //默認Student包含了Person所有字段 Person id int addr string } func main() { s2 := Student{Person:Person{"約漢","female",10},id:2} fmt.Println(s2) } //{{約漢 female 10} 2 }

同名字段的情況

//package 聲明開頭表示代碼所屬包 package main import "fmt" //定義人的結構體 type Person struct { name string sex string age int } //學生 type Student struct { //匿名字段 //默認Student包含了Person所有字段 Person id int addr string //同名字段 name string } func main() { var s Student //就近賦值 s.name = "約漢" fmt.Println(s) //若給外面賦值 s.Person.name = "接客" fmt.Println(s) } //{{ 0} 0 約漢} //{{接客 0} 0 約漢}

所有的內置類型和自定義類型都是可以作為匿名字段去使用

package main import "fmt" //定義人的結構體 type Person struct { name string sex string age int } //自定義類型 type mystr string //學生 type Student struct { //匿名字段 //默認Student包含了Person所有字段 Person //內置 int mystr } func main() { //初始化 s1 := Student{Person{"約漢","male",18},1,"bj"} fmt.Println(s1) fmt.Println(s1.name) }

指針類型匿名字段

//package 聲明開頭表示代碼所屬包 package main import "fmt" //定義人的結構體 type Person struct { name string sex string age int } //學生 type Student struct { //匿名字段 //默認Student包含了Person所有字段 *Person //內置 id int addr string } func main() { s1 := Student{&Person{"約漢","male",18},1,"bj"} fmt.Println(s1) fmt.Println(s1.name) } //{0xc0420661e0 1 bj} //約漢

3. 方法

4. 包和封裝

5. 接口

  • 在面向對象編程中,一個對象其實也就是一個簡單的值或者一個變量,在這個對象中會包含一些函數
  • 這種帶有接收者的函數,我們稱為方法,本質上,一個方法則是一個和特殊類型關聯的函數
  • 方法的語法如下
  • func (接收參數名 接收類型) 方法名(參數列表)(返回值)
  • 可以給任意自定義類型(包括內置類型,但不包括指針類型)添加相應的方法
  • 接收類型可以是指針或非指針類型
  • 為類型添加方法(為基礎類型添加方法和為結構體類型添加方法)
    • 基礎類型

        //package 聲明開頭表示代碼所屬包 package main import "fmt" //任務:定義方法實現2個數相加 type MyInt int //傳統定義方式,面向過程 func Add(a, b MyInt) MyInt { return a + b } //面向對象 func (a MyInt) Add(b MyInt) MyInt { return a + b } func main() { var a MyInt = 1 var b MyInt = 1 fmt.Println("Add(a,b)=", Add(a, b)) //調用面向對象的方法 fmt.Println("a.Add(b)=",a.Add(b)) } //Add(a,b)= 2 //a.Add(b)= 2
    • 結構體類型

        //package 聲明開頭表示代碼所屬包 package main import "fmt" type Person struct { name string sex string age int } //為Person添加方法 func (p Person) PrintInfo() { fmt.Println(p.name, p.sex, p.age) } func main() { p := Person{"接客", "male", 18} p.PrintInfo() }
    • 值語義和引用語義

        //package 聲明開頭表示代碼所屬包 package main import "fmt" type Person struct { name string sex string age int } //設置指針作為接收者的方法,引用語義 func (p *Person) SetInfoPointer() { (*p).name = "接客" p.sex = "female" p.age = 22 } //值作為接收者,值語義 func (p Person) SetInfoValue() { p.name = "約漢" p.sex = "male" p.age = 20 } func main() { //指針作為接收者的效果 p1 := Person{"擼死", "male", 19} fmt.Println("函數調用前=", p1) (&p1).SetInfoPointer() fmt.Println("函數調用后=", p1) fmt.Println("================寂寞的分割線=================") //值作為接收者的效果 p2 := Person{"約漢", "male", 18} fmt.Println("函數調用前=", p2) p2.SetInfoValue() fmt.Println("函數調用后=", p2) } //函數調用前= {擼死 male 19} //函數調用后= {接客 female 22} //================寂寞的分割線================= //函數調用前= {約漢 male 18} //函數調用后= {約漢 male 18}
    • 方法的繼承

        package main import "fmt" type Person struct { name string sex string age int } //為Person定義方法 func (p *Person) PrintInfo() { fmt.Printf("%s,%s,%d\n",p.name,p.sex,p.age) } type Student struct { Person id int addr string } func main() { p :=Person{"接客","male",18} p.PrintInfo() //學生也去調,方法繼承 s := Student{Person{"接客","male",18},2,"bj"} s.PrintInfo() }
    • 方法的重寫

        package main import "fmt" type Person struct { name string sex string age int } //為Person定義方法 func (p *Person) PrintInfo() { fmt.Printf("%s,%s,%d\n", p.name, p.sex, p.age) } type Student struct { Person id int addr string } //Student定義方法,實際上就相當於方法重寫 func (s *Student) PrintInfo() { fmt.Printf("Student:%s,%s,%d\n", s.name, s.sex, s.age) } func main() { p := Person{"接客", "male", 18} p.PrintInfo() //學生也去調,方法繼承 s := Student{Person{"接客", "male", 18}, 2, "bj"} s.PrintInfo() //顯式調用 s.Person.PrintInfo() }
    • 方法值和方法表達式

        package main import "fmt" type Person struct { name string sex string age int } func (p *Person) PrintInfoPointer() { //%p是地址,%v是值 fmt.Printf("%p,%v\n", p, p) } func main() { p := Person{"接客", "male", 18} //傳統的調用方法的方式 p.PrintInfoPointer() //使用go方法值特性調用 pFunc1 := p.PrintInfoPointer pFunc1() //使用go方法表達式調用 pFunc2 := (*Person).PrintInfoPointer pFunc2(&p) }

練習:創建屬性的getter和setter方法並進行調用

    package main import "fmt" type Dog struct { name string //1公 0母 sex int } //封裝dog的方法 //setter func (d *Dog) SetName(name string) { d.name = name } //getter func (d *Dog) GetName() string { return d.name } //咬人 func (d *Dog) bite() { fmt.Printf("讓本汪%s 來給你上課...", d.name) } func main() { d := Dog{"二哈", 1} d.bite() }

4. 包和封裝

  • 方法首字母大寫:public
  • 方法首字母小寫:private
  • 為結構體定義的方法必須放在同一個包內,可以是不同的文件
  • 上面代碼復制到test包中,在test02包中進行調用,需要調用的方法名首字母大寫

5. 接口

  • go語言中,接口(interface)是一個自定義類型,描述了一系列方法的集合
  • 接口不能被實例化
  • 接口定義語法如下
  • type 接口名 interface{}
  • PS:接口命名習慣以er結尾
  • 接口定義與實現

      package main import "fmt" //定義人的接口 type Humaner interface { //說話 Say() } //學生結構體 type Student struct { name string score int } //Student實現Say()方法 func (s *Student) Say() { fmt.Printf("Student[%s,%d] 瞌睡不斷\n", s.name, s.score) } type Teacher struct { name string group string } //老師實現接口 func (t *Teacher) Say() { fmt.Printf("Teacher[%s,%s] 毀人不倦\n", t.name, t.group) } //自定義類型 type MyStr string //自定義類型實現方法 func (str MyStr) Say() { fmt.Printf("MyStr[%s] 同志醒醒,還有個bug\n", str) } func WhoSay(i Humaner) { i.Say() } func main() { s := &Student{"約漢", 88} t := &Teacher{"擼死", "Go語言"} var tmp MyStr = "接客" s.Say() t.Say() tmp.Say() //go的多態,調用同一個接口,不同表現 WhoSay(s) WhoSay(t) WhoSay(tmp) //make()創建 x := make([]Humaner, 3) x[0], x[1], x[2] = s, t, tmp for _, value := range x { value.Say() } }
    • 接口繼承

        package main import "fmt" //定義人的接口 type Humaner interface { //說話 Say() } type Personer interface { //等價於寫了Say() Humaner Sing(lyrics string) } //學生結構體 type Student struct { name string score int } //Student實現Say()方法 func (s *Student) Say() { fmt.Printf("Student[%s,%d] 瞌睡不斷\n", s.name, s.score) } func (s *Student) Sing(lyrics string) { fmt.Printf("Student sing[%s]!!\n", lyrics) } func main() { s := &Student{"約漢", 88} var p Personer p = s p.Say() p.Sing("互擼娃") }
    • 空接口:空interface{}不包含任何方法,空接客可以存儲任意類型的值
    • 類型查詢
      • comma-ok斷言

          package main import "fmt" //空接口 type Element interface{} type Person struct { name string age int } func main() { //切片 list := make([]Element, 3) //int list[0] = 1 list[1] = "Hello" list[2] = Person{"luhan", 18} //遍歷 for index, element := range list { //類型斷言:value ,ok = element.(T) //value 是變量的值,ok是返回的布爾值,element是接口變量,T是斷言類型 if value, ok := element.(int); ok { fmt.Printf("list[%d]是int類型,值是%d\n", index, value) } else if value, ok := element.(int); ok { fmt.Printf("list[%d]是int類型,值是%d\n", index, value) } else if value, ok := element.(Person); ok { fmt.Printf("list[%d]是Person類型,值是[%s,%d]\n", index, value.name, value.age) } else { fmt.Printf("list[%d]是其他類型\n", index) } } }
      • switch測試

        package main import "fmt" //空接口 type Element interface{} type Person struct { name string age int } func main() { //切片 list := make([]Element, 3) //int list[0] = 1 list[1] = "Hello" list[2] = Person{"luhan", 18} //遍歷 for index, element := range list { switch value := element.(type) { case int: fmt.Printf("list[%d]是int類型,值是%d\n", index, value) case string: fmt.Printf("list[%d]是string類型,值是%s\n", index, value) default: fmt.Printf("list[%d]是其他類型\n", index) } } }
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM