go中的面向對象

整體來看,go語言中的面向對象在使用方式上是靈活易用的,能夠說設計理念真的很先進,讓人有一種如沐春風的感受。c++

若是你在學生時代經歷了一個從c到c++的學習歷程,你是否還記得,老師會說c++是面向對象的,因此咱們沒必要再使用c中的結構體做爲數據結構。咱們只需定義的是c++中的類,由於類中不僅有成員屬性,也有成員函數。換句話說, class是能夠完美替代struct的,並且更強大。數據結構

回到go中,咱們的面向對象使用的就是struct,但時代不一樣了,此次咱們的struct也能夠有"成員函數"了。函數

定義一個典型的面向對象方式學習

package main
import "fmt"

type Human struct {
    height float32
    weight int
}

func (h Human) BMIindex() (index int){
    index = h.weight / int(h.height * h.height)
    return
}

func main() {
    person := Human{1.83, 75}
    fmt.Printf("this person's height is %.2f m\n", person.height)
    fmt.Printf("this person's weight is %d kg\n", person.weight)
    fmt.Printf("this person's BMI index is %d\n", person.BMIindex())
}

在main函數中咱們初始化了一個Human對象,並分別讀取了他們的屬性height和weight,最後調用了Human對象的成員函數BMIindex(),經過計算得到了這我的的"體質指數"。this

Receiver設計

上述例子中,一個Human對象的成員函數就是經過Receiver來定義的。咱們給一個普通的func添加了Receiver(就是上述示例中的h Human),就構成了一個methodBMIindex()。在這種狀況下,這個函數只能依賴於一個Human對象來起做用,而不能被獨立調用。其正確的調用方式就是上述的person.BMIindex()指針

下述又一個例子,咱們但願經過定義成員函數來改變對象的成員屬性。code

package main
import "fmt"

type Human struct {
    height float32
    weight int
}

func (h Human) BMIindex() (index int){
    index = h.weight / int(h.height * h.height)
    return
}

func (h Human) setHeight(height float32) {
    h.height = height
}

func main() {
    person := Human{1.83, 75}
    fmt.Printf("this person's height is %.2f m\n", person.height)
    fmt.Printf("this person's weight is %d kg\n", person.weight)
    fmt.Printf("this person's BMI index is %d\n", person.BMIindex())
    person.setHeight(1.90)
    fmt.Printf("this person's height is %.2f m\n", person.height)
}

輸出結果:
    this person's height is 1.83 m
    this person's weight is 75 kg
    this person's BMI index is 25
    this person's height is 1.83 m

能夠看出,咱們調用person.setHeight(1.90)以後,person的height屬性並無改變爲1.90。而爲了解決這個問題,咱們須要改變receiver。咱們將setHeight()函數定義爲下述形式便可。對象

func (h *Human) BMIindex() (index int){
    index = h.weight / int(h.height * h.height)
    return
}

緣由:咱們將對象的指針類型做爲receiver,才能改變其屬性的值。其本質爲,咱們能夠把receiver看做func的獨特的一個參數。若是傳遞的是一個對象類型,那麼函數中改變的其實是這個對象的副本;而若是傳遞一個指針類型,改變的纔是這個對象自己。繼承

關於receiver的選擇,能夠這樣理解,若是須要獲取對象屬性(get),則選用對象做爲receiver;若是須要改變對象屬性(set),則選取指針做爲receiver。

method的適用範圍

上述示例中,咱們定義的method都是對應於struct的,但實際上method的定義能夠依賴於全部的自定義類型。所謂自定義類型,就是經過type語句給一些內置類型起了個"別名"後所定義的新類型。

package main
import "fmt"


type Sex string

func (s *Sex) change(){
    if *s == Sex("女") {
        *s = Sex("男")
    }
}

func main() {
    sex := Sex("女")
    fmt.Println("previous sex is ", sex)
    sex.change()
    fmt.Println("current sex is ", sex)    
}

這裏,咱們新定義了一個類型Sex,而且爲其定義了一個method change()。

面向對象中的繼承

package main
import "fmt"

type Human struct {
    height float32
    weight int
}

type Woman struct {
    Human
    sex string
}

func (h Human) BMIindex() (index int){
    index = h.weight / int(h.height * h.height)
    return
}

func main() {
    woman := Woman{Human{1.65, 50}, "女"}
    fmt.Printf("this woman's height is %.2f m\n", woman.height)
    fmt.Printf("this woman's wight is %d kg\n", woman.weight)
    fmt.Printf("this woman's BMIindex is %d\n", woman.BMIindex())
}

這個例子展示了Woman對Human的繼承。在Woman結構體中包含了匿名字段Human,那麼Human中包含的屬性也是屬於一個Woman對象的屬性,Human對象的method一樣也能夠被Woman對象所使用。值得注意的是,這個method能夠被重寫。只須要再定義一個以Woman對象類型爲receiver的BMIindex(),那麼再次調用woman.BMIindex時,實際調用的函數是新定義的這個函數。這就是method的重寫。

訪問屬性

若是你對面向對象中的訪問屬性很熟悉的話,你必定知道public、private和protected做爲訪問修飾符的做用。而在go語言中,咱們使用大小寫來區分。

標識符首字母大寫,至關於public屬性。這樣的成員屬性或成員函數能夠被在包外部被調用。例如上述Woman、BMIindex。

標識符首字母小寫,至關於protected屬性。這樣的成員屬性或成員函數只能在包內部被使用。

相關文章
相關標籤/搜索