【Go語言】【13】再談GO語言的結構體

本文從以下四個方面再領着你們認識結構體
編程

  • 匿名結構體和匿名成員的結構體ide

  • 值傳遞和引用傳遞性能

  • 再談嵌套結構體學習

  • 面向對象測試

一、匿名結構體和匿名成員的結構體編碼

如上篇所述,一個結構體須要先聲明,再初始化,最後把初始化後的結構體賦值給其它變量,例如:spa

/*聲明結構體*/指針

type employee struct{orm

        name,address string對象

        height,weight float64

}


/*初始化結構體,並賦給變量emp*/

emp := employee{name:"eagle",  address:"guangdong",  height:172.0,  weight:75.3,}

試想一下,若結構體聲明時不指定名稱會怎麼呢?

struct{  

        name,address  string

        height,weight  float64

}

那接下來如何對該結構體初始化呢?這就涉及到匿名結構體的概念。

所謂匿名結構體顧名思義:就是結構體聲明時沒有指定名稱,既然沒有名稱,那麼結構體的初始化和聲明必須合併,不能拆分開

emp := struct{

        name, address   string

        height, weight   float64

}{

        name:"eagle",  address:"guangdong",  height:172.0,  weight:75.3

}

// 備註:這裏的最後一個逗號(,)必需要有,不然會報錯


匿名成員的結構體:指結構體中的成員沒有名稱,例如

/*聲明結構體*/

type employee struct{

        string     // 沒有爲成員指定名稱

        float64   // 沒有爲成員指定

}


/*初始化結構體,並賦給變量emp*/

emp := employee{"eagle", 172.0}

這裏有一個限制,即成員類型不能相同,好比:

/*聲明結構體*/

type employee struct{

        string

        string

        float64

}


/*初始化結構體,並賦給變量emp*/

emp := employee{"eagle", 「guangdong", 172.0}

此時會拋出「duplicate field string」異常信息,GO語言系統不會聰明地認爲第一個成員和第二個成員都是string類型,第三個成員是float64類型。


我我的建議在具體編碼過程當中不要這樣寫,由於這會影響代碼的可讀性,哪一個讀者會明白成員表明什麼意思呢?過N久以後,恐怕連代碼原做者也忘記是什麼意思了吧 :)


二、值傳遞和引用傳遞

不管學習哪門語言,都基本會大談特談「值傳遞」和「引用傳遞」的問題,GO語言也免不了俗氣一把,在GO語言中除了切片(slice)、集合(map)、通道(channel)和接口(interface)以外,其它的都是值傳遞,看下面的例子:

/*聲明一個結構體*/

type employee struct {

name, address  string  // 姓名、住址

height, weight float64 // 身高、體重

}


/*定義方法,該方法入參爲結構體,經過該方法修改結構體成員name的值*/

func modifyAttribute(emp employee) {

emp.name = "newer"

fmt.Println(emp)

}


/*測試方法*/

func main() {

// 初始化結構體並賦給emp

emp := employee{name: "eagle", address: "guangdong", height: 172.0, weight: 75.3}

// 修改以前打印結果

fmt.Println(emp)

// 調用方法修改name值並打印

modifyAttribute(emp)

// 修改以後打印結果

fmt.Println(emp)

}

執行並打印出結果

wKioL1Wb3Cmwd9VBAAB58z1DdBQ218.jpg

從結果上能夠看出雖然在方法modifyAttribute中修改了name,但對於main方法中定義的emp並無形成影響,因此這是一個值傳遞。

C語言之因此通過這麼久的風風雨雨而經久不衰,其緣由之一在於它對內存的操做,對內存的操做就意味着性能的提高,由於對結構體內存地址的操做效率遠高於結構體的複製(別緊張,這裏不講指針,呵呵

接下來咱們把入參由結構體修改成結構體指針

/*把入參由結構體修改成結構體指針*/

func modifyAttribute(emp *employee) {

emp.name = "newer"

fmt.Println(emp)

}


/*測試方法*/

func main() {

// 初始化結構體並賦給emp

emp := employee{name: "eagle", address: "guangdong", height: 172.0, weight: 75.3}

// 修改以前打印結果

fmt.Println(emp)

// 調用方法修改name值並打印

modifyAttribute(&emp)

// 修改以後打印結果

fmt.Println(emp)

}

執行並打印出結果

wKiom1Wb28GRsPUjAAB_ZbO1xxA408.jpg

從結果上能夠看出方法的修改影響到了main方法中emp的值,這再也不是值傳遞,而是引用傳遞了 :)


三、再談嵌套結構體

因爲結構體的嵌套在具體編碼中常常出現,上節寫的過於倉促,怕沒有解釋清楚,這裏再談一談關於結構體的嵌套問題

/*聲明figure結構體*/

type figure struct {

height, weight float64

}


/*聲明human結構體,裏面嵌套figure結構體*/

type human struct {

name, address string

figure

}

正如上章所說,結構體在使用以前先進行初始化,比較好理解的初始化方式是:字面值初始化

man := human{}  // 初始化human結構體,但不對成員賦值

// 採用字面值進行賦值

man.name = "eagle"

man.address = "guangdong"

man.height = 172   // 或者man.figure.height = 172

man.weight = 75.3  // 或者man.figure.weight = 75.3

這種賦值方式更面向對象化一些,從Java或者C++轉型過來的讀者可能更喜歡一些,但真正編碼過程當中,咱們會常常讀其餘人寫的代碼,他們可能更習慣初始化和賦值一塊進行:

man := human{name:"eagle", address:"guangdong", figure:figure{height:172, weight:75.3}}


請各位稍休息一下,而後重點考慮下面的話:

在human結構體嵌套中,您會發現成員變量name有指定名稱和類型,一樣address也是,但有一個奇葩figure,它究竟是成員名稱?仍是結構體類型呢?

答案是:figure既是成員名稱又是類型,因此在初始化時才採用figure:figure{}的形式初始化。

若您理解了這句話,能夠接着向下看了,不然須要重讀幾遍,再不清楚的話能夠留言給我 :)


四、面向對象

在《【4】GO語言類型和爲類型增長方法》中講到爲類型增長方法,你們融會貫通一下:

// 爲int類型起一個別名Integer

type Integer int


// 爲類型Integer增長一個新方法LessThan

func (a Integer) LessThan (b Integer) bool{

        return a < b

}


// 而後就能夠面向對象編程了

var a Integer = 5 // 定義一個對象a ,其類型爲Integer

a.LessThan(8)      // 調用對象a的方法LessThan()

再看一下結構體的聲明

// 爲struct類型起一個別名employee

type employee struct{

        name, address string

}


// 用方法模擬一個構造器

func newEmployee(name, address string) employee{

        return employee{name, address}

}


// 定義一個修改employee住址的方法

func ModifyAddress(emp *employee){

        emp.address = "shenzhen"

}


// 爲類型employee增長一個比較方法:只要名稱和地址相同,則認爲兩個對象相同

func (src employee) IsEqual(dest employee) bool{

       return src.name == dest.name && src.address == dest.address

}


// 採用面向對象編程的方式使用結構體

// 初始化對象src和dest,且二者賦予相同的值

var src = newEmployee("eagle", "guangdong")

var dest = newEmployee("eagle", "guangdong")

fmt.Println(src.IsEqual(dest))  // 打印結果爲true


// 修改目標的住址

ModifyAddress(&dest)

fmt.Println(src.IsEqual(dest))  // 打印結果爲false


好了,到此結構體基本上已介紹完,但還有一些更細節的東西沒有介紹,例如:

  • 採用new的方式初始化結構體

  • 結構體是一種複合類型,因此它能夠和指針結合,本文都沒有深刻涉及

等等,這些內容能夠在具體編碼時遇到問題問百度或者谷歌,在實踐中學習語言才能真正提高,這裏只是給了您一根魚杆和釣魚的基本方法,如何釣到大魚還須要您經過實際寫代碼來獲取 :)

相關文章
相關標籤/搜索