當(dāng)我第一次接觸到C語(yǔ)言時(shí),就對(duì)結(jié)構(gòu)體投入了極大的興趣辽装,認(rèn)為這個(gè)東西以后大有作為帮碰,后來(lái)接觸Java、C++拾积,面向?qū)ο缶幊讨械膶?duì)象進(jìn)入我的視線收毫,經(jīng)過(guò)了這么多年的磨練,回過(guò)頭來(lái)再看結(jié)構(gòu)體依舊是那么親切殷勘;同時(shí)從另一個(gè)角度上看結(jié)構(gòu)體與面向?qū)ο笾械某蓡T對(duì)象是多么的相像 :)
一、結(jié)構(gòu)體元素
結(jié)構(gòu)體由關(guān)鍵字昔搂、結(jié)構(gòu)體類型名稱和具體成員構(gòu)成玲销,如下:
[圖片上傳失敗...(image-c76190-1613615699239)]
二、結(jié)構(gòu)體初步認(rèn)識(shí)
下面通過(guò)對(duì)比數(shù)組(復(fù)合類型)來(lái)了解一下結(jié)構(gòu)體:
1摘符、從存儲(chǔ)類型來(lái)看
數(shù)組只能存儲(chǔ)相同的類型:
s := []string{"a", "b", "c", "d", "e"}
結(jié)構(gòu)體可以存儲(chǔ)不同的類型
|
// 聲明結(jié)構(gòu)體
type employee struct {
name,address string // 姓名贤斜、住址
age int // 年齡
height,weight float64 // 身高策吠、體重
}
|
2、從內(nèi)存來(lái)看
它們都是在內(nèi)存中占據(jù)連續(xù)的內(nèi)存空間瘩绒,但對(duì)于數(shù)組來(lái)說(shuō)猴抹,每一個(gè)元素所占用的內(nèi)存大小是相同的,而結(jié)構(gòu)體每一個(gè)項(xiàng)所占用的內(nèi)存大小不一定相同
[圖片上傳失敗...(image-9b180d-1613615699239)]
3锁荔、從類型組合角度來(lái)看
數(shù)組沒(méi)有組合的用法蟀给,例如一個(gè)一維數(shù)組,一旦數(shù)組類型確定就不可以再把另一個(gè)一維數(shù)組設(shè)置為元素值阳堕,例如
s := []string{"a", "b", "c", "d", "e"}
s[0] = []string{"f", "g"}
此時(shí)運(yùn)行該程序會(huì)出現(xiàn)類似此提示:cannot use []string literal (type []string) as type string in assignment;
結(jié)構(gòu)體支持組合顽悼,我們知道一維空間是一條線爪幻,二維空間是一個(gè)平面,三維空間是一個(gè)空間
|
type line struct {
x int
}
type plane struct {
line
y int
}
type space struct {
plane
z int
}
|
我們很自然地通過(guò)組合的方式,把一維擴(kuò)展到二維抛人,把二維擴(kuò)展到三維,把三維擴(kuò)展到四維乙各,依次類推......
4爬骤、從操作角度上來(lái)看
數(shù)組元素的操作是通過(guò)下標(biāo)來(lái)完成的:
|
s := []string{"a", "b", "c", "d", "e"}
for i := 0; i < len(s); i++ {
fmt.Println(s[i]) // 打印數(shù)組中每一個(gè)元素,通過(guò)s[i]下標(biāo)的方式來(lái)獲取
}
|
而結(jié)構(gòu)體是通過(guò)項(xiàng)名來(lái)完成的:
|
t := space{plane{line{3}, 5}, 7}
fmt.Println(t.x, t.y, t.z) // 通過(guò)操作結(jié)構(gòu)體的項(xiàng)名t.x贱纠、t.y峻厚、t.z來(lái)獲取
|
5、從比較角度上來(lái)看
數(shù)組與結(jié)構(gòu)體類似并巍,若判斷兩個(gè)數(shù)組是否相同目木,需要看數(shù)組的存儲(chǔ)類型、數(shù)組長(zhǎng)度懊渡、每一個(gè)元素是否相等刽射,同樣判斷兩個(gè)結(jié)構(gòu)體是否相同,需要看結(jié)構(gòu)體的類型是否相同剃执,然后看項(xiàng)的順序誓禁、項(xiàng)的名稱、項(xiàng)的類型等等
三肾档、結(jié)構(gòu)體的初始化
關(guān)于數(shù)組的初始化可參見(jiàn)《【6】GO語(yǔ)言的數(shù)組》摹恰,相對(duì)數(shù)組結(jié)構(gòu)體的初始化有點(diǎn)繁雜,下面一一道來(lái):
1怒见、空結(jié)構(gòu)體
所謂空結(jié)構(gòu)體俗慈,即結(jié)構(gòu)體的成員為空,如下:
|
// 聲明空結(jié)構(gòu)體employee
type employee struct {
}
func main(){
emp := employee{} // 結(jié)構(gòu)體的初始化遣耍,直接使用結(jié)構(gòu)體類型名稱后面跟一個(gè)大括號(hào)
fmt.Println(emp)
}
|
其中employee{}就表示初始化一個(gè)結(jié)構(gòu)體闺阱,然后賦值給emp,運(yùn)行就會(huì)打印出結(jié)果{}舵变,因?yàn)樵摻Y(jié)構(gòu)體成員為空酣溃;可能有讀者想瘦穆,若結(jié)構(gòu)體有成員,同樣這樣初始化會(huì)有什么結(jié)果呢赊豌?
|
type employee struct {
name, address string // 姓名扛或、住址
age int // 年齡
height, weight float64 // 身高、體重
}
func main(){
emp := employee{} // 這樣有什么結(jié)果呢碘饼?
fmt.Println(emp)
}
|
運(yùn)行一下就會(huì)發(fā)現(xiàn)熙兔,結(jié)果是{ 0 0 0},因?yàn)樽址娜笔≈禐榭沾擅粒粫?huì)顯示出來(lái)黔姜,而int和float64的缺省值為0,所以打印出該結(jié)果蒂萎。其實(shí)說(shuō)白了這就是結(jié)構(gòu)體成員的缺省值問(wèn)題秆吵,具體如下圖:
[圖片上傳失敗...(image-5b184e-1613615699239)]
2、結(jié)構(gòu)體的初始化
結(jié)構(gòu)體的成員初始化是通過(guò)操作成員對(duì)象來(lái)完成
|
func main() {
emp := employee{}
fmt.Println(emp)
emp.name = "黑客eagle"
emp.age = 38
fmt.Println(emp)
}
|
采用<u>變量+"."+成員名=值</u>的形式對(duì)結(jié)構(gòu)體進(jìn)行初始化五慈,例如emp.age=38纳寂。這種初始化形式很類似C++、Java泻拦,那么是否還有其它形式呢毙芜?當(dāng)然,以前說(shuō)過(guò)GO語(yǔ)言就是人的正常思維語(yǔ)言争拐,只要你能想到腋粥,基本上就可以正常執(zhí)行 :)
|
emp1 := employee{"keji", "hangzhou", 19, 175, 65}
fmt.Println(emp1)
|
這種初始化形式看起來(lái)更直觀。上面的執(zhí)行結(jié)果如下:
[圖片上傳失敗...(image-dc6061-1613615699239)]
讀者可能還會(huì)問(wèn)架曹,我只想對(duì)其中的某幾個(gè)成員賦值隘冲,而上面是對(duì)所有成員賦值,該如何辦呢绑雄?
|
emp2 := employee{address: "hangzhou", age: 20}
fmt.Println(emp2)
|
這樣只有被指定賦值的成員才能得到真實(shí)的值展辞,而未指定賦值的成員則被系統(tǒng)賦予缺省值,這種情況也被稱為采用字面值進(jìn)行初始化
3万牺、嵌套結(jié)構(gòu)體
這個(gè)比較好理解罗珍,即結(jié)構(gòu)體里面嵌套結(jié)構(gòu)體,我們把“身高”脚粟、“體重”定義為一個(gè)結(jié)構(gòu)體覆旱,而“身高”、“體重”是一個(gè)human(結(jié)構(gòu)體)的成員核无,所以可以采用嵌套結(jié)構(gòu)體:
|
// 體形
type figure struct {
height, weight float64
}
type human struct {
name, address string
figure
}
|
即human結(jié)構(gòu)體中包含figure結(jié)構(gòu)體扣唱,我們可以采用下面的初始化
man := human{}
fmt.Println(man)
執(zhí)行結(jié)果為{ {0 0}}
結(jié)合上面講的結(jié)構(gòu)體初始化,我們很容易通過(guò)字面值對(duì)name和address初始化
man.name = "siyu"
man.address = "tianjin"
但是怎么對(duì)嵌套的結(jié)構(gòu)體成員height、weight進(jìn)行初始化呢画舌?用過(guò)面向?qū)ο缶幊痰娜撕苋菀紫氲剑捎萌缦路绞剑?/p>
|
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已慢,然后通過(guò)figure的成員height對(duì)身高進(jìn)行賦值曲聂,這樣沒(méi)有問(wèn)題,其實(shí)GO給我們提供了一種更便捷的賦值方式:
|
man.height = 172.8
man.weight = 175.3
|
即直接對(duì)其成員賦值佑惠,這種方式簡(jiǎn)單直接朋腋,但會(huì)引入“成員可見(jiàn)性”的概念
4、結(jié)構(gòu)體成員的可見(jiàn)性
任何語(yǔ)言在代碼面前都是蒼白的膜楷,敏捷有一個(gè)思想就是代碼勝過(guò)文檔旭咽,<typo id="typo-3408" data-origin="費(fèi)話" ignoretag="true">費(fèi)話</typo>少說(shuō),用代碼來(lái)解釋什么是“結(jié)構(gòu)體成員的可見(jiàn)性”
|
// 生物會(huì)笑赌厅、會(huì)哭穷绵,所以有哭、笑成員
type biology struct {
cry, laugh string
}
// 人會(huì)笑特愿、會(huì)哭仲墨,所以也有哭、笑成員揍障;但同時(shí)人嵌套了生物結(jié)構(gòu)體
type human struct {
biology
cry, laugh string
}
|
下面采用如下方式對(duì)結(jié)構(gòu)體初始化
man := human{}
man.cry = "cry"
man.laugh = "laugh"
fmt.Println(man)
那么這里的man.cry目养,man.laugh是對(duì)human的成員賦值呢?還是對(duì)biology的成員賦值呢毒嫡?運(yùn)行一下結(jié)果便可以知道癌蚁,這里是對(duì)human的成員賦值
[圖片上傳失敗...(image-25a543-1613615699239)]
因?yàn)閮?nèi)層大括號(hào)是空的,為什么這樣呢兜畸?
可以按剝洋蔥的思維來(lái)理解努释,若最外層有此成員名(cry、laugh)則不用再向里面剝了膳叨,若最外層沒(méi)有該成員名洽洁,則進(jìn)一步向里面剝,直到找到為止菲嘴;
這也就是說(shuō)饿自,若外層有成員名(cry、laugh)龄坪,則內(nèi)層的同名成員是不可見(jiàn)的昭雌,若外層沒(méi)有成員名(cry、laugh)健田,內(nèi)層的成員才變的可見(jiàn)
5烛卧、再談嵌套結(jié)構(gòu)體的初始化
以上例來(lái)說(shuō),我們可以采用字面值的形式初始化:
man := human{}
man.cry = "cry"
man.laugh = "laugh"
man.biology.cry = "biology cry"
man.biology.laugh = "biology laugh"
其實(shí)還可以采用如下形式:
woman := human{biology: biology{cry: "biology cry", laugh: "biology laugh"}, cry: "cry", laugh: "laugh"}
還可以簡(jiǎn)化為:
woman := human{biology: biology{"biology cry", "biology laugh"}, cry: "cry", laugh: "laugh"}
是否還可以簡(jiǎn)化為?
woman := human{{"biology cry", "biology laugh"}, "cry", "laugh"}
此時(shí)就會(huì)拋出如下異常:
[圖片上傳失敗...(image-e04b87-1613615699238)]
你如果夠仔細(xì)的話总放,就能發(fā)現(xiàn)嵌套結(jié)構(gòu)體就只寫了一個(gè)結(jié)構(gòu)體類型名呈宇,而沒(méi)有采用value valueType的形式,所以針對(duì)這種情況局雄,GO語(yǔ)言認(rèn)為內(nèi)部嵌套結(jié)構(gòu)體名稱和類型名是同一個(gè)