標籤:go 結構體
當我第一次接觸到C語言時,就對結構體投入了極大的興趣,認為這個東西以後大有作為,後來接觸Java、C++,物件導向編程中的對象進入我的視線,經過了這麼多年的磨練,回過頭來再看結構體依舊是那麼親切;同時從另一個角度上看結構體與物件導向中的成員對象是多麼的相像 :)
一、結構體元素
結構體由關鍵字、結構體類型名稱和具體成員構成,如下:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/6F/61/wKiom1WaZv2RbnY3AAC_DN43xqI956.jpg" title="結構體定義.png" alt="wKiom1WaZv2RbnY3AAC_DN43xqI956.jpg" />
二、結構體初步認識
下面通過對比數組(複合類型)來瞭解一下結構體:
1、從儲存類型來看
數組只能儲存相同的類型:
s := []string{"a", "b", "c", "d", "e"}
結構體可以儲存不同的類型
type employee struct{
name, address string // 姓名、住址
age int // 年齡
height,weight float64 // 身高、體重
}
2、從記憶體來看
它們都是在記憶體中佔據連續的記憶體空間,但對於數組來說,每一個元素所佔用的記憶體大小是相同的,而結構體每一個項所佔用的記憶體大小不一定相同
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/6F/5F/wKioL1WacC7ARF99AAB2IrtGm7Q976.jpg" title="記憶體角度.png" alt="wKioL1WacC7ARF99AAB2IrtGm7Q976.jpg" />
3、從類型組合角度來看
數組沒有組合的用法,例如一個一維數組,一旦數群組類型確定就不可以再把另一個一維數組設定為元素值,例如
s := []string{"a", "b", "c", "d", "e"}
s[0] = []string{"f", "g"}
此時運行該程式會出現類似此提示:cannot use []string literal (type []string) as type string in assignment;
結構體支援組合,我們知道一維空間是一條線,二維空間是一個平面,三維空間是一個空間
type line struct {
x int
}
type plane struct {
line
y int
}
type space struct {
plane
z int
}
我們很自然地通過組合的方式,把一維擴充到二維,把二維擴充到三維,把三維擴充到四維,依次類推......
4、從操作角度上來看
數組元素的操作是通過下標來完成的:
s := []string{"a", "b", "c", "d", "e"}
for i := 0; i < len(s); i++ {
fmt.Println(s[i]) // 列印數組中每一個元素,通過s[i]下標的方式來擷取
}
而結構體是通過項名來完成的:
t := space{plane{line{3}, 5}, 7}
fmt.Println(t.x, t.y, t.z) // 通過操作結構體的項名t.x、t.y、t.z來擷取
5、從比較角度上來看
數組與結構體類似,若判斷兩個數組是否相同,需要看數組的儲存類型、數組長度、每一個元素是否相等,同樣判斷兩個結構體是否相同,需要看結構體的類型是否相同,然後看項的順序、項的名稱、項的類型等等
三、結構體的初始化
關於數組的初始化可參見《【6】GO語言的數組》,相對數組結構體的初始化有點繁雜,下面一一道來:
1、空結構體
所謂空結構體,即結構體的成員為空白,如下:
type employee struct {
}
func main(){
emp := employee{} // 結構體的初始化,直接使用結構體類型名稱後面跟一個大括弧
fmt.Println(emp)
}
其中employee{}就表示初始化一個結構體,然後賦值給emp,運行就會列印出結果{},因為該結構體成員為空白;可能有讀者想,若結構體有成員,同樣這樣初始化會有什麼結果呢?
type employee struct {
name, address string // 姓名、住址
age int // 年齡
height, weight float64 // 身高、體重
}
func main(){
emp := employee{} // 這樣有什麼結果呢?
fmt.Println(emp)
}
運行一下就會發現,結果是{ 0 0 0},因為字串的預設值為空白串,不會顯示出來,而int和float64的預設值為0,所以列印出該結果。其實說白了這就是結構體成員的預設值問題,具體如:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/6F/5F/wKioL1WafAnhdRBGAABTJEO04ow570.jpg" title="結構體預設值.png" alt="wKioL1WafAnhdRBGAABTJEO04ow570.jpg" />
2、結構體的初始化
結構體的成員初始化是通過操作成員對象來完成
func main() {
emp := employee{}
fmt.Println(emp)
emp.name = "駭客eagle"
emp.age = 38
fmt.Println(emp)
}
採用變數+"."+成員名=值的形式對結構體進行初始化,例如emp.age=38。這種初始化形式很類似C++、Java,那麼是否還有其它形式呢?當然,以前說過GO語言就是人的正常思維語言,只要你能想到,基本上就可以正常執行 :)
emp1 := employee{"keji", "hangzhou", 19, 175, 65}
fmt.Println(emp1)
這種初始化形式看起來更直觀。上面的執行結果如下:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/6F/5F/wKioL1WafuWiLtDKAABqafzO-4U073.jpg" title="結構體初始化.png" alt="wKioL1WafuWiLtDKAABqafzO-4U073.jpg" />
讀者可能還會問,我只想對其中的某幾個成員賦值,而上面是對所有成員賦值,該如何辦呢?
emp2 := employee{address: "hangzhou", age: 20}
fmt.Println(emp2)
這樣只有被指定賦值的成員才能得到真實的值,而未指定賦值的成員則被系統賦予預設值,這種情況也被稱為採用字面值進行初始化
3、嵌套結構體
這個比較好理解,即結構體裡面嵌套結構體,我們把“身高”、“體重”定義為一個結構體,而“身高”、“體重”是一個human(結構體)的成員,所以可以採用嵌套結構體:
// 體形
type figure struct {
height, weight float64
}
type human struct {
name, address string
figure
}
即human結構體中包含figure結構體,我們可以採用下面的初始化
man := human{}
fmt.Println(man)
執行結果為{ {0 0}}
結合上面講的結構體初始化,我們很容易通過字面值對name和address初始化
man.name = "siyu"
man.address = "tianjin"
但是怎麼對嵌套的結構體成員height、weight進行初始化呢?用過物件導向編程的人很容易想到,採用如下方式:
func main() {
man := human{}
man.name = "siyu"
man.address = "tianjin"
man.figure.height = 172.8
man.figure.weight = 175.3
fmt.Println(man)
}
即一層層向下找:先找man的成員figure,然後通過figure的成員height對身高進行賦值,這樣沒有問題,其實GO給我們提供了一種更便捷的賦值方式:
man.height = 172.8
man.weight = 175.3
即直接對其成員賦值,這種方式簡單直接,但會引入“成員可見度”的概念
4、結構體成員的可見度
任何語言在代碼面前都是蒼白的,敏捷有一個思想就是代碼勝過文檔,費話少說,用代碼來解釋什麼是“結構體成員的可見度”
// 生物會笑、會哭,所以有哭、笑成員
type biology struct {
cry, laugh string
}
// 人會笑、會哭,所以也有哭、笑成員;但同時人嵌套了生物結構體
type human struct {
biology
cry, laugh string
}
下面採用如下方式對結構體初始化
man := human{}
man.cry = "cry"
man.laugh = "laugh"
fmt.Println(man)
那麼這裡的man.cry,man.laugh是對human的成員賦值呢?還是對biology的成員賦值呢?運行一下結果便可以知道,這裡是對human的成員賦值
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/6F/5F/wKioL1WahjbCH1-XAABJlgjXV78216.jpg" title="嵌套結構體初始化.png" alt="wKioL1WahjbCH1-XAABJlgjXV78216.jpg" />
因為內層大括弧是空的,為什麼這樣呢?
可以按剝洋蔥的思維來理解,若最外層有此成員名(cry、laugh)則不用再向裡面剝了,若最外層沒有該成員名,則進一步向裡面剝,直到找到為止;
這也就是說,若外層有成員名(cry、laugh),則內層的同名成員是不可見的,若外層沒有成員名(cry、laugh),內層的成員才變的可見
5、再談嵌套結構體的初始化
以上例來說,我們可以採用字面值的形式初始化:
man := human{}
man.cry = "cry"
man.laugh = "laugh"
man.biology.cry = "biology cry"
man.biology.laugh = "biology laugh"
其實還可以採用如下形式:
woman := human{biology: biology{cry: "biology cry", laugh: "biology laugh"}, cry: "cry", laugh: "laugh"}
還可以簡化為:
woman := human{biology: biology{"biology cry", "biology laugh"}, cry: "cry", laugh: "laugh"}
是否還可以簡化為?
woman := human{{"biology cry", "biology laugh"}, "cry", "laugh"}
此時就會拋出如下異常:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/6F/62/wKiom1WaiYqAE2bqAACJITQRi6Y131.jpg" title="嵌套結構體初始化2.png" alt="wKiom1WaiYqAE2bqAACJITQRi6Y131.jpg" />
你如果夠仔細的話,就能發現嵌套結構體就唯寫了一個結構體類型名,而沒有採用value valueType的形式,所以針對這種情況,GO語言認為內部嵌套結構體名稱和類型名是同一個
本文出自 “青客” 部落格,請務必保留此出處http://qingkechina.blog.51cto.com/5552198/1671463
【Go語言】【12】GO語言的結構體