您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“Go基礎(chǔ)編程之什么是結(jié)構(gòu)體”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“Go基礎(chǔ)編程之什么是結(jié)構(gòu)體”吧!
結(jié)構(gòu)體(struct)是自定義方式形成新的數(shù)據(jù)類(lèi)型,結(jié)構(gòu)體是類(lèi)型中帶有成員的復(fù)合類(lèi)型。Go 語(yǔ)言結(jié)構(gòu)體是一種聚合的數(shù)據(jù)類(lèi)型,是由零個(gè)或多個(gè)任意類(lèi)型的值聚合成的實(shí)體。每個(gè)值稱(chēng)為結(jié)構(gòu)體的成員。來(lái)描述真實(shí)世界的實(shí)體和實(shí)體對(duì)應(yīng)的各種屬性。
結(jié)構(gòu)體屬性也叫 字段 或 成員 ,每個(gè)字段都有名稱(chēng)和類(lèi)型,每個(gè)名稱(chēng)是唯一的。可以是任何類(lèi)型,如普通類(lèi)型、復(fù)合類(lèi)型、函數(shù)、map、interface、struct等,所以我們可以理解為go語(yǔ)言中的“類(lèi)”。
定義
結(jié)構(gòu)體定義方式如下:
type name struct{ fieldName1 type1 fieldName2 type2 ... }
如下,定義User 結(jié)構(gòu)體:
type User struct { Name string age int }
實(shí)例化
上面定義只是類(lèi)型,就想是一個(gè) int 一樣,需要定義一個(gè)類(lèi)型變量才可以使用,類(lèi)似Java的類(lèi)。
直接定義變量使用
package main import ( "fmt" ) type User struct { Name string age int } func main() { var user1 User //定義User 類(lèi)型變量user var user2 *User //類(lèi)型指針,未分配內(nèi)存,不能直接使用 fmt.Println(user1, user2) //{ 0} <nil> }
定義默認(rèn)成員變量
var user1 = User{Name: "abc"} fmt.Println(user1) func NewUser() *User { return &User{Name:"abc",age:20} }
使用內(nèi)建函數(shù) new() 分配內(nèi)存返回類(lèi)型變量指針
var user = new(User) fmt.Println(user) //&{ 0}
訪問(wèn)成員
使用 . 來(lái)訪問(wèn)
var user User user.Name = "abc" user.age = 20 fmt.Println(user) //{abc 20}
首字母大小寫(xiě)問(wèn)題,成員大寫(xiě)表示包外可見(jiàn)(即面向?qū)ο蟮墓袑傩?,小寫(xiě)包外不可見(jiàn)
零值:結(jié)構(gòu)體的零值是 nil
初始值:結(jié)構(gòu)體的初始值是非 nil 時(shí),各成員對(duì)應(yīng)類(lèi)型的初始值
空結(jié)構(gòu)體:空結(jié)構(gòu)體就是沒(méi)有字段的結(jié)構(gòu)體,空結(jié)構(gòu)體不占內(nèi)存
package main import ( "fmt" "unsafe" ) func main() { user1 := struct{}{} user2 := struct{}{} fmt.Printf("%p,%dn", &user1, unsafe.Sizeof(user1)) //0x585218,0 fmt.Printf("%p,%dn", &user2, unsafe.Sizeof(user2)) //0x585218,0 }
從上面可以看出空結(jié)構(gòu)體內(nèi)存地址和大小都是一樣的。根據(jù)這個(gè)特性,使用空結(jié)構(gòu)體可以作為信號(hào)量,起到信號(hào)作用但不占內(nèi)存。如空結(jié)構(gòu)體類(lèi)型的 chan
匿名結(jié)構(gòu)體
匿名結(jié)構(gòu)體沒(méi)有類(lèi)型名稱(chēng),無(wú)須通過(guò) type 關(guān)鍵字定義就可以直接使用。
user := struct { Name string }{Name: "abc"} fmt.Println(user) //{abc}
比較
如果結(jié)構(gòu)體的全部成員都是 可以比較 的,且成員的 順序 、 類(lèi)型 、 數(shù)量 完全一樣才可以比較,兩個(gè)結(jié)構(gòu)體將可以使用==或!=運(yùn)算符進(jìn)行比較。
package main import ( "fmt" ) func main() { user1 := struct { Name string }{Name: "abc"} user2 := struct { Name string }{Name: "abc"} fmt.Println(user1 == user2) //true }
成員名稱(chēng)不一樣
package main import ( "fmt" ) func main() { user1 := struct { Name string }{Name: "abc"} user2 := struct { name string }{name: "abc"} fmt.Println(user1 == user2) //invalid operation: user1 == user2 (mismatched types struct { Name string } and struct { name string }) }
成員數(shù)量不一樣
package main import ( "fmt" ) func main() { user1 := struct { Name string }{Name: "abc"} user2 := struct { Name string age int }{Name: "abc"} fmt.Println(user1 == user2) //invalid operation: user1 == user2 (mismatched types struct { Name string } and struct { Name string; age int }) }
成員類(lèi)型不能比較
package main import ( "fmt" ) func main() { user1 := struct { Name string m map[int]int }{Name: "abc"} user2 := struct { Name string m map[int]int }{Name: "abc"} fmt.Println(user1 == user2) //invalid operation: user1 == user2 (struct containing map[int]int cannot be compared) }
順序不一樣
package main import ( "fmt" ) func main() { user1 := struct { Name string age int }{Name: "abc"} user2 := struct { age int Name string }{Name: "abc"} fmt.Println(user1 == user2) //invalid operation: user1 == user2 (mismatched types struct { Name string; age int } and struct { age int; Name string }) }
其實(shí)整個(gè)結(jié)構(gòu)體就是一個(gè)類(lèi)型(如int),成員順序、類(lèi)型這些不一樣,整體的結(jié)構(gòu)體就不一樣,故對(duì)于強(qiáng)類(lèi)型語(yǔ)言來(lái)說(shuō)就是不能比較的,對(duì)應(yīng)類(lèi)型完全一樣還需要注意成員是否是可以比較,如slice、map等
Go語(yǔ)言沒(méi)有面向?qū)ο筮@個(gè)概念,但可以把結(jié)構(gòu)體看做是一個(gè)類(lèi),可以實(shí)現(xiàn)面向?qū)ο蟮奶匦?,如通過(guò)組合和嵌入實(shí)現(xiàn)繼承
匿名字段
匿名字段是結(jié)構(gòu)體沒(méi)有顯示的名字,是結(jié)構(gòu)體嵌入一個(gè)或多個(gè)結(jié)構(gòu)體,如下面
B直接嵌入A ,B是匿名字段
package main import ( "fmt" ) type A struct { Name string B } type B struct { Age int Name string }
訪問(wèn)成員變量
func main() { var a = A{Name:"a",B:B{Name:"b",Age:20}} fmt.Printf("%#vn", a) //main.A{Name:"", B:main.B{Age:0}} fmt.Println(a.Name) //a fmt.Println(a.B.Name) //b fmt.Println(a.Age) //20 }
只有一個(gè)成員名稱(chēng)的情況下,Go語(yǔ)法糖可以省略嵌入結(jié)構(gòu)體
fmt.Println(a.B.Age) //20 fmt.Println(a.Age) //20
對(duì)應(yīng)有多個(gè)相同名稱(chēng)的成員,不能省略,因?yàn)榫幾g器不知道是哪個(gè)
type C struct { A B } func main() { var c = C{A:A{Name:"a"},B:B{Name:"b",Age:20}} fmt.Println(c.Name) //ambiguous selector c.Name }
正確做法是
func main() { var c = C{A:A{Name:"a"},B:B{Name:"b",Age:20}} fmt.Println(c.A.Name) //a fmt.Println(c.B.Name) //b }
組合
上面是沒(méi)有名字的嵌入結(jié)構(gòu)體,還可以給嵌入結(jié)構(gòu)體命名,訪問(wèn)必須要帶上具體的字段,不能省略。
package main import ( "fmt" ) type A struct { Btype B } type B struct { Age int Name string } func main() { var a = A{Btype:B{Name:"b",Age:20}} fmt.Println(a.Name) //.Name undefined (type A has no field or method Name) }
標(biāo)簽
如下面在字段后面用 `` 包起來(lái)的是標(biāo)簽,主要是通過(guò)反射來(lái)序列化和反序列化,具體由反射章節(jié)來(lái)講。
type User struct { Id int `json:"id"` Account string `json:"account" form:"account"` Nickname string `gorm:"nickname" json:"nickname" form:"nickname"` }
方法
方法一般都是面向?qū)ο缶幊?OOP)的一個(gè)特性,Go語(yǔ)言的方法其實(shí)與一個(gè)值或變量關(guān)聯(lián)的特殊的函數(shù)。這個(gè)值或變量叫做 接收者
func ([typeName] 接收者) name (param) [return]{}
接收者是自定義的類(lèi)型
package main import ( "fmt" ) type A struct {} //結(jié)構(gòu)體 type B int //int func (a A) show() { fmt.Println("a............") } func (b B) show() { fmt.Println("b............") } func main() { var a A var b B a.show() b.show() }
接收者不能直接用內(nèi)置類(lèi)型
func (c int) show() { //cannot define new methods on non-local type int fmt.Println("b............") }
接收者 值 可以是值類(lèi)型或指針類(lèi)型
package main import ( "fmt" ) type A struct {} type B struct {} func (a A) show() { //值類(lèi)型 fmt.Println("a............") } func (b *B) show() { //指針類(lèi)型 fmt.Println("b............") } func main() { var a A var b B a.show() b.show() }
對(duì)與 B 來(lái)說(shuō),下面兩種調(diào)用方式是等價(jià)的,本質(zhì)上他們都是一樣的, b.show() 的寫(xiě)法是省略了 (&b) ,只不過(guò)由語(yǔ)法糖來(lái)補(bǔ)全
func main() { var b B b.show() (&b).show() }
方法可以訪問(wèn)接收者自身的信息,如下
package main import ( "fmt" ) type User struct { Id int Account string Nickname string } func (u User)show() { fmt.Println(u.Nickname) } func main() { var a = User{Nickname:"測(cè)試"} a.show() //測(cè)試 }
值類(lèi)型接收者拷貝類(lèi)型的全部,修改 不會(huì) 影響原數(shù)據(jù);指針拷貝的是地址,修改 會(huì) 影響原數(shù)據(jù)
package main import ( "fmt" ) type User struct { Id int Account string Nickname string } func (u User)show() { fmt.Println(u) } func (u User)setName1() { u.Nickname="值類(lèi)型" } func (u *User)setName2() { u.Nickname="指針類(lèi)型" } func main() { var a = User{Nickname:"測(cè)試"} a.setName1() a.show() a.setName2() a.show() }
接受者 類(lèi)型 本身不能為指針
package main import ( "fmt" ) type A int type B *int //變量類(lèi)型為指針 func (a A) show() { fmt.Println("a............") } func (b B) show() { //invalid receiver type B (B is a pointer type) fmt.Println("b............") }
到此,相信大家對(duì)“Go基礎(chǔ)編程之什么是結(jié)構(gòu)體”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。