本篇內(nèi)容主要講解“Golang中的Struct怎么定義和使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Golang中的Struct怎么定義和使用”吧!
十年的上杭網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。成都營銷網(wǎng)站建設(shè)的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整上杭建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。創(chuàng)新互聯(lián)公司從事“上杭網(wǎng)站設(shè)計”,“上杭網(wǎng)站推廣”以來,每個客戶項目都認(rèn)真落實執(zhí)行。
Go語言中提供了對struct的支持;struct
,中文翻譯稱為結(jié)構(gòu)體
,與數(shù)組一樣,屬于復(fù)合類型,并非引用類型。Go語言的struct,與C語言中的struct或其他面向?qū)ο缶幊陶Z言中的類(class)類似,可以定義字段(屬性)和方法,但也有很不同的地方,需要深入學(xué)習(xí),才能區(qū)分他們之間的區(qū)別。
注意復(fù)合類型與引用類型之間的區(qū)別,這應(yīng)該也是值傳遞和引用傳遞的區(qū)別吧。
使用struct關(guān)鍵字可以定義一個結(jié)構(gòu)體,結(jié)構(gòu)體中的成員,稱為結(jié)構(gòu)體的字段或?qū)傩浴?/p>
上面的代碼中,我們定義了一個包含5個字段的結(jié)構(gòu)體,可以看到,相同類型 當(dāng)然,結(jié)構(gòu)體也可以不包含任何字段,稱為type Member struct {
id int
name, email string
gender, age int
}
name
和email
、gender
和age
在同一行中定義,但比較好的編程習(xí)慣是每一行只定義一個字段,如:type Member struct {
id int
name string
email string
gender int
age int
}
空結(jié)構(gòu)體
,struct{}表示一個空的結(jié)構(gòu)體,注意,直接定義一個空的結(jié)構(gòu)體并沒有意義,但在并發(fā)編程中,channel之間的通訊,可以使用一個struct{}作為信號量。ch := make(chan struct{})
ch <- struct{}{}
上面的例子中,我們定義了Member結(jié)構(gòu)體類型,接下就可以這個自定義的類型創(chuàng)建變量了。
直接定義變量,這個使用方式并沒有為字段賦初始值,因此所有字段都會被自動賦予自已類型的零值,比如
name
的值為空字符串"",age的值為0。
var m1 Member//所有字段均為空值
使用字面量創(chuàng)建變量,這種使用方式,可以在大括號中為結(jié)構(gòu)體的成員賦初始值,有兩種賦初始值的方式,一種是按字段在結(jié)構(gòu)體中的順序賦值,下面代碼中
m2
就是使用這種方式,這種方式要求所有的字段都必須賦值,因此如果字段太多,每個字段都要賦值,會很繁瑣,另一種則使用字段名為指定字段賦值,如下面代碼中變量m3
的創(chuàng)建,使用這種方式,對于其他沒有指定的字段,則使用該字段類型的零值作為初始化值。
var m2 = Member{1,"小明","xiaoming@163.com",1,18} // 簡短變量聲明方式:m2 := Member{1,"小明","xiaoming@163.com",1,18}
var m3 = Member{id:2,"name":"小紅"}// 簡短變量聲明方式:m3 := Member{id:2,"name":"小紅"}
通過變量名,使用逗號(.)
,可以訪問結(jié)構(gòu)體類型中的字段,或為字段賦值,也可以對字段進(jìn)行取址(&)操作。
fmt.Println(m2.name)//輸出:小明
m3.name = "小花"
fmt.Println(m3.name)//輸出:小花
age := &m3.age
*age = 20
fmt.Println(m3.age)//20
結(jié)構(gòu)體與數(shù)組一樣,都是值傳遞,比如當(dāng)把數(shù)組或結(jié)構(gòu)體作為實參傳給函數(shù)的形參時,會復(fù)制一個副本,所以為了提高性能,一般不會把數(shù)組直接傳遞給函數(shù),而是使用切片(引用類型)代替,而把結(jié)構(gòu)體傳給函數(shù)時,可以使用指針結(jié)構(gòu)體
。
指針結(jié)構(gòu)體,即一個指向結(jié)構(gòu)體的指針,聲明結(jié)構(gòu)體變量時,在結(jié)構(gòu)體類型前加*號,便聲明一個指向結(jié)構(gòu)體的指針,如:
注意,指針類型為引用類型,聲明結(jié)構(gòu)體指針時,如果未初始化,則初始值為nil,只有初始化后,才能訪問字段或為字段賦值。
另外,使用Go內(nèi)置new()函數(shù),可以分配內(nèi)存來初始化結(jié)構(gòu)休,并返回分配的內(nèi)存指針,因為已經(jīng)初始化了,所以可以直接訪問字段。var m1 *Member
m1.name = "小明"//錯誤用法,未初始化,m1為nil
m1 = &Member{}
m1.name = "小明"//初始化后,結(jié)構(gòu)體指針指向某個結(jié)構(gòu)體地址,才能訪問字段,為字段賦值。
var m2 = new(Member)
m2.name = "小紅"
我們知道,如果將結(jié)構(gòu)體轉(zhuǎn)給函數(shù),只是復(fù)制結(jié)構(gòu)體的副本,如果在函數(shù)內(nèi)修改結(jié)構(gòu)體字段值,外面的結(jié)構(gòu)體并不會受影響,而如果將結(jié)構(gòu)體指針傳給函數(shù),則在函數(shù)中使用指針對結(jié)構(gòu)體所做的修改,都會影響到指針指向的結(jié)構(gòu)體。
func main() {
m1 := Member{}
m2 := new(Member)
Change(m1,m2)
fmt.Println(m1,m2)
}
func Change(m1 Member,m2 *Member){
m1.Name = "小明"
m2.Name = "小紅"
}
上面的例子中,我們定義結(jié)構(gòu)體字段名首字母是小寫的,這意味著這些字段在包外不可見
,因而無法在其他包中被訪問,只允許包內(nèi)訪問。
下面的例子中,我們將Member聲明在member包中,而后在main包中創(chuàng)建一個變量,但由于結(jié)構(gòu)體的字段包外不可見,因此無法為字段賦初始值,無法按字段還是按索引賦值,都會引發(fā)panic錯誤。
package member
type Member struct {
id int
name string
email string
gender int
age int
}
package main
fun main(){
var m = member.Member{1,"小明","xiaoming@163.com",1,18}//會引發(fā)panic錯誤
}
因此,如果想在一個包中訪問另一個包中結(jié)構(gòu)體的字段,則必須是大寫字母開頭的變量,即可導(dǎo)出的變量,如:
type Member struct {
Id int
Name string
Email string
Gender int
Age int
}
在定義結(jié)構(gòu)體字段時,除字段名稱和數(shù)據(jù)類型外,還可以使用反引號為結(jié)構(gòu)體字段聲明元信息,這種元信息稱為Tag,用于編譯階段關(guān)聯(lián)到字段當(dāng)中,如我們將上面例子中的結(jié)構(gòu)體修改為:
上面例子演示的是使用encoding/json包編碼或解碼結(jié)構(gòu)體時使用的Tag信息。type Member struct {
Id int `json:"id,-"`
Name string `json:"name"`
Email string `json:"email"`
Gender int `json:"gender,"`
Age int `json:"age"`
}
Tag由反引號括起來的一系列用空格分隔的key:"value"鍵值對組成,如:
Id int `json:"id" gorm:"AUTO_INCREMENT"`
下面總結(jié)幾點(diǎn)結(jié)構(gòu)體的相關(guān)特性:
結(jié)構(gòu)體與數(shù)組一樣,是復(fù)合類型,無論是作為實參傳遞給函數(shù)時,還是賦值給其他變量,都是值傳遞,即復(fù)一個副本。
Go語言是支持面向?qū)ο缶幊痰?,但卻沒有繼承的概念,在結(jié)構(gòu)體中,可以通過組合其他結(jié)構(gòu)體來構(gòu)建更復(fù)雜的結(jié)構(gòu)體。
一個結(jié)構(gòu)體,并沒有包含自身,比如Member中的字段不能是Member類型,但卻可能是*Member。
在Go語言中,將函數(shù)綁定到具體的類型中,則稱該函數(shù)是該類型的方法,其定義的方式是在func與函數(shù)名稱之間加上具體類型變量,這個類型變量稱為方法接收器
,如:
注意,并不是只有結(jié)構(gòu)體才能綁定方法,任何類型都可以綁定方法,只是我們這里介紹將方法綁定到結(jié)構(gòu)體中。
從上面的例子中,我們可以看出,通過func setName(m Member,name string){//普通函數(shù)
m.Name = name
}
func (m Member)setName(name string){//綁定到Member結(jié)構(gòu)體的方法
m.Name = name
}
方法接收器
可以訪問結(jié)構(gòu)體的字段,這類似其他編程語言中的this關(guān)鍵詞,但在Go語言中,只是一個變量名而已,我們可以任意命名方法接收器
。
調(diào)用結(jié)構(gòu)體的方法,與調(diào)用字段一樣:
上面的代碼中,我們會很奇怪,不是調(diào)用setName()方法設(shè)置了字段Name的值了嗎?為什么還是輸出為空呢?m := Member{}
m.setName("小明")
fmt.Println(m.Name)//輸出為空
這是因為,結(jié)構(gòu)體是值傳遞,當(dāng)我們調(diào)用setName時,方法接收器接收到是只是結(jié)構(gòu)體變量的一個副本,通過副本對值進(jìn)行修復(fù),并不會影響調(diào)用者,因此,我們可以將方法接收器定義為指針變量,就可達(dá)到修改結(jié)構(gòu)體的目的了。
方法和字段一樣,如果首字母為小寫,則只允許在包內(nèi)可見,在其他包中是無法訪問的,因此,如果要在其他包中訪問func (m *Member)setName(name string){/將Member改為*Member
m.Name = name
}
m := Member{}
m.setName("小明")
fmt.Println(m.Name)//小明
setName
,則應(yīng)該將方法名改為SetName
。
我們知道,結(jié)構(gòu)體中并沒有繼承的概念,其實,在Go語言中也沒有繼承的概念,Go語言的編程哲學(xué)里,推薦使用組合
的方式來達(dá)到代碼復(fù)用效果。
組合,可以理解為定義一個結(jié)構(gòu)體中,其字段可以是其他的結(jié)構(gòu)體,這樣,不同的結(jié)構(gòu)體就可以共用相同的字段。
注意,在記得我們前面提過的,結(jié)構(gòu)體不能包含自身,但可能包含指向自身的結(jié)構(gòu)體指針。
例如,我們定義了一個名為Animal表示動物,如果我們想定義一個結(jié)構(gòu)體表示貓,如:
可以看到,我們定義Cat結(jié)構(gòu)體時,可以把Animal結(jié)構(gòu)體作為Cat的字段。type Animal struct {
Name string //名稱
Color string //顏色
Height float32 //身高
Weight float32 //體重
Age int //年齡
}
//奔跑
func (a Animal)Run() {
fmt.Println(a.Name + "is running")
}
//吃東西
func (a Animal)Eat() {
fmt.Println(a.Name + "is eating")
}
type Cat struct {
a Animal
}
func main() {
var c = Cat{
a: Animal{
Name: "貓貓",
Color: "橙色",
Weight: 10,
Height: 30,
Age: 5,
},
}
fmt.Println(c.a.Name)
c.a.Run()
}
上面的例子,我們看到,把Animal結(jié)構(gòu)體作為Cat的字段時,其變量名為a,所以我們訪問Animal的方法時,語法為c.a.Run()
,這種通過葉子屬性訪問某個字段類型所帶的方法和字段用法非常繁瑣。
Go語言支持直接將類型作為結(jié)構(gòu)體的字段,而不需要取變量名,這種字段叫匿名字段
,如:
type Lion struct {
Animal //匿名字段
}
func main(){
var lion = Lion{
Animal{
Name: "小獅子",
Color: "灰色",
},
}
lion.Run()
fmt.Println(lion.Name)
}
通過上面例子,可以看到,通過匿名字段組合其他類型,而后訪問匿名字段類型所帶的方法和字段時,不需要使用葉子屬性,非常方便。
到此,相信大家對“Golang中的Struct怎么定義和使用”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
分享名稱:Golang中的Struct怎么定義和使用
轉(zhuǎn)載來源:http://chinadenli.net/article38/podosp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)、App設(shè)計、定制開發(fā)、虛擬主機(jī)、網(wǎng)站導(dǎo)航、營銷型網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)