當我第一次接觸到C語言時,就對結構體投入了極大的興趣,認爲這個東西之後大有做爲,後來接觸Java、C++,面向對象編程中的對象進入個人視線,通過了這麼多年的磨練,回過頭來再看結構體依舊是那麼親切;同時從另外一個角度上看結構體與面向對象中的成員對象是多麼的相像 :)
編程
1、結構體元素數組
結構體由關鍵字、結構體類型名稱和具體成員構成,以下:ide
2、結構體初步認識spa
下面經過對比數組(複合類型)來了解一下結構體:orm
一、從存儲類型來看對象
數組只能存儲相同的類型:blog
s := []string{"a", "b", "c", "d", "e"}內存
結構體能夠存儲不一樣的類型文檔
// 聲明結構體字符串 type employee struct { name,address string // 姓名、住址 age int // 年齡 height,weight float64 // 身高、體重 } |
二、從內存來看
它們都是在內存中佔據連續的內存空間,但對於數組來講,每個元素所佔用的內存大小是相同的,而結構體每個項所佔用的內存大小不必定相同
三、從類型組合角度來看
數組沒有組合的用法,例如一個一維數組,一旦數組類型肯定就不能夠再把另外一個一維數組設置爲元素值,例如
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 } |
咱們很天然地經過組合的方式,把一維擴展到二維,把二維擴展到三維,把三維擴展到四維,依次類推......
四、從操做角度上來看
數組元素的操做是經過下標來完成的:
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來獲取 |
五、從比較角度上來看
數組與結構體相似,若判斷兩個數組是否相同,須要看數組的存儲類型、數組長度、每個元素是否相等,一樣判斷兩個結構體是否相同,須要看結構體的類型是否相同,而後看項的順序、項的名稱、項的類型等等
3、結構體的初始化
關於數組的初始化可參見《【6】GO語言的數組》,相對數組結構體的初始化有點繁雜,下面一一道來:
一、空結構體
所謂空結構體,即結構體的成員爲空,以下:
// 聲明空結構體employee 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,因此打印出該結果。其實說白了這就是結構體成員的缺省值問題,具體以下圖:
二、結構體的初始化
結構體的成員初始化是經過操做成員對象來完成
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) |
這種初始化形式看起來更直觀。上面的執行結果以下:
讀者可能還會問,我只想對其中的某幾個成員賦值,而上面是對全部成員賦值,該如何辦呢?
emp2 := employee{address: "hangzhou", age: 20} fmt.Println(emp2) |
這樣只有被指定賦值的成員才能獲得真實的值,而未指定賦值的成員則被系統賦予缺省值,這種狀況也被稱爲採用字面值進行初始化
三、嵌套結構體
這個比較好理解,即結構體裏面嵌套結構體,咱們把「身高」、「體重」定義爲一個結構體,而「身高」、「體重」是一個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 |
即直接對其成員賦值,這種方式簡單直接,但會引入「成員可見性」的概念
四、結構體成員的可見性
任何語言在代碼面前都是蒼白的,敏捷有一個思想就是代碼賽過文檔,費話少說,用代碼來解釋什麼是「結構體成員的可見性」
// 生物會笑、會哭,因此有哭、笑成員 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的成員賦值
由於內層大括號是空的,爲何這樣呢?
能夠按剝洋蔥的思惟來理解,若最外層有此成員名(cry、laugh)則不用再向裏面剝了,若最外層沒有該成員名,則進一步向裏面剝,直到找到爲止;
這也就是說,若外層有成員名(cry、laugh),則內層的同名成員是不可見的,若外層沒有成員名(cry、laugh),內層的成員才變的可見
五、再談嵌套結構體的初始化
以上例來講,咱們能夠採用字面值的形式初始化:
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"}
此時就會拋出以下異常:
你若是夠仔細的話,就能發現嵌套結構體就只寫了一個結構體類型名,而沒有采用value valueType的形式,因此針對這種狀況,GO語言認爲內部嵌套結構體名稱和類型名是同一個