您好,登錄后才能下訂單哦!
本篇內容主要講解“Golang中的Struct怎么定義和使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Golang中的Struct怎么定義和使用”吧!
Go語言中提供了對struct的支持;struct
,中文翻譯稱為結構體
,與數組一樣,屬于復合類型,并非引用類型。Go語言的struct,與C語言中的struct或其他面向對象編程語言中的類(class)類似,可以定義字段(屬性)和方法,但也有很不同的地方,需要深入學習,才能區分他們之間的區別。
注意復合類型與引用類型之間的區別,這應該也是值傳遞和引用傳遞的區別吧。
使用struct關鍵字可以定義一個結構體,結構體中的成員,稱為結構體的字段或屬性。
上面的代碼中,我們定義了一個包含5個字段的結構體,可以看到,相同類型 當然,結構體也可以不包含任何字段,稱為type Member struct {
id int
name, email string
gender, age int
}
name
和email
、gender
和age
在同一行中定義,但比較好的編程習慣是每一行只定義一個字段,如:type Member struct {
id int
name string
email string
gender int
age int
}
空結構體
,struct{}表示一個空的結構體,注意,直接定義一個空的結構體并沒有意義,但在并發編程中,channel之間的通訊,可以使用一個struct{}作為信號量。ch := make(chan struct{})
ch <- struct{}{}
上面的例子中,我們定義了Member結構體類型,接下就可以這個自定義的類型創建變量了。
直接定義變量,這個使用方式并沒有為字段賦初始值,因此所有字段都會被自動賦予自已類型的零值,比如
name
的值為空字符串"",age的值為0。
var m1 Member//所有字段均為空值
使用字面量創建變量,這種使用方式,可以在大括號中為結構體的成員賦初始值,有兩種賦初始值的方式,一種是按字段在結構體中的順序賦值,下面代碼中
m2
就是使用這種方式,這種方式要求所有的字段都必須賦值,因此如果字段太多,每個字段都要賦值,會很繁瑣,另一種則使用字段名為指定字段賦值,如下面代碼中變量m3
的創建,使用這種方式,對于其他沒有指定的字段,則使用該字段類型的零值作為初始化值。
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":"小紅"}
通過變量名,使用逗號(.)
,可以訪問結構體類型中的字段,或為字段賦值,也可以對字段進行取址(&)操作。
fmt.Println(m2.name)//輸出:小明
m3.name = "小花"
fmt.Println(m3.name)//輸出:小花
age := &m3.age
*age = 20
fmt.Println(m3.age)//20
結構體與數組一樣,都是值傳遞,比如當把數組或結構體作為實參傳給函數的形參時,會復制一個副本,所以為了提高性能,一般不會把數組直接傳遞給函數,而是使用切片(引用類型)代替,而把結構體傳給函數時,可以使用指針結構體
。
指針結構體,即一個指向結構體的指針,聲明結構體變量時,在結構體類型前加*號,便聲明一個指向結構體的指針,如:
注意,指針類型為引用類型,聲明結構體指針時,如果未初始化,則初始值為nil,只有初始化后,才能訪問字段或為字段賦值。
另外,使用Go內置new()函數,可以分配內存來初始化結構休,并返回分配的內存指針,因為已經初始化了,所以可以直接訪問字段。var m1 *Member
m1.name = "小明"//錯誤用法,未初始化,m1為nil
m1 = &Member{}
m1.name = "小明"//初始化后,結構體指針指向某個結構體地址,才能訪問字段,為字段賦值。
var m2 = new(Member)
m2.name = "小紅"
我們知道,如果將結構體轉給函數,只是復制結構體的副本,如果在函數內修改結構體字段值,外面的結構體并不會受影響,而如果將結構體指針傳給函數,則在函數中使用指針對結構體所做的修改,都會影響到指針指向的結構體。
func main() {
m1 := Member{}
m2 := new(Member)
Change(m1,m2)
fmt.Println(m1,m2)
}
func Change(m1 Member,m2 *Member){
m1.Name = "小明"
m2.Name = "小紅"
}
上面的例子中,我們定義結構體字段名首字母是小寫的,這意味著這些字段在包外不可見
,因而無法在其他包中被訪問,只允許包內訪問。
下面的例子中,我們將Member聲明在member包中,而后在main包中創建一個變量,但由于結構體的字段包外不可見,因此無法為字段賦初始值,無法按字段還是按索引賦值,都會引發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}//會引發panic錯誤
}
因此,如果想在一個包中訪問另一個包中結構體的字段,則必須是大寫字母開頭的變量,即可導出的變量,如:
type Member struct {
Id int
Name string
Email string
Gender int
Age int
}
在定義結構體字段時,除字段名稱和數據類型外,還可以使用反引號為結構體字段聲明元信息,這種元信息稱為Tag,用于編譯階段關聯到字段當中,如我們將上面例子中的結構體修改為:
上面例子演示的是使用encoding/json包編碼或解碼結構體時使用的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"`
下面總結幾點結構體的相關特性:
結構體與數組一樣,是復合類型,無論是作為實參傳遞給函數時,還是賦值給其他變量,都是值傳遞,即復一個副本。
Go語言是支持面向對象編程的,但卻沒有繼承的概念,在結構體中,可以通過組合其他結構體來構建更復雜的結構體。
一個結構體,并沒有包含自身,比如Member中的字段不能是Member類型,但卻可能是*Member。
在Go語言中,將函數綁定到具體的類型中,則稱該函數是該類型的方法,其定義的方式是在func與函數名稱之間加上具體類型變量,這個類型變量稱為方法接收器
,如:
注意,并不是只有結構體才能綁定方法,任何類型都可以綁定方法,只是我們這里介紹將方法綁定到結構體中。
從上面的例子中,我們可以看出,通過func setName(m Member,name string){//普通函數
m.Name = name
}
func (m Member)setName(name string){//綁定到Member結構體的方法
m.Name = name
}
方法接收器
可以訪問結構體的字段,這類似其他編程語言中的this關鍵詞,但在Go語言中,只是一個變量名而已,我們可以任意命名方法接收器
。
調用結構體的方法,與調用字段一樣:
上面的代碼中,我們會很奇怪,不是調用setName()方法設置了字段Name的值了嗎?為什么還是輸出為空呢?m := Member{}
m.setName("小明")
fmt.Println(m.Name)//輸出為空
這是因為,結構體是值傳遞,當我們調用setName時,方法接收器接收到是只是結構體變量的一個副本,通過副本對值進行修復,并不會影響調用者,因此,我們可以將方法接收器定義為指針變量,就可達到修改結構體的目的了。
方法和字段一樣,如果首字母為小寫,則只允許在包內可見,在其他包中是無法訪問的,因此,如果要在其他包中訪問func (m *Member)setName(name string){/將Member改為*Member
m.Name = name
}
m := Member{}
m.setName("小明")
fmt.Println(m.Name)//小明
setName
,則應該將方法名改為SetName
。
我們知道,結構體中并沒有繼承的概念,其實,在Go語言中也沒有繼承的概念,Go語言的編程哲學里,推薦使用組合
的方式來達到代碼復用效果。
組合,可以理解為定義一個結構體中,其字段可以是其他的結構體,這樣,不同的結構體就可以共用相同的字段。
注意,在記得我們前面提過的,結構體不能包含自身,但可能包含指向自身的結構體指針。
例如,我們定義了一個名為Animal表示動物,如果我們想定義一個結構體表示貓,如:
可以看到,我們定義Cat結構體時,可以把Animal結構體作為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結構體作為Cat的字段時,其變量名為a,所以我們訪問Animal的方法時,語法為c.a.Run()
,這種通過葉子屬性訪問某個字段類型所帶的方法和字段用法非常繁瑣。
Go語言支持直接將類型作為結構體的字段,而不需要取變量名,這種字段叫匿名字段
,如:
type Lion struct {
Animal //匿名字段
}
func main(){
var lion = Lion{
Animal{
Name: "小獅子",
Color: "灰色",
},
}
lion.Run()
fmt.Println(lion.Name)
}
通過上面例子,可以看到,通過匿名字段組合其他類型,而后訪問匿名字段類型所帶的方法和字段時,不需要使用葉子屬性,非常方便。
到此,相信大家對“Golang中的Struct怎么定義和使用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。