Go 語言基礎之結構體(秋日篇)
前言
Hey,大家好呀,碼農我是星期八,咱們接着上次繼續說, 看一下結構體還有什麼其他操作。沒來得及上車的小夥伴請戳:Go 語言基礎之結構體(春日篇)、Go 語言基礎之結構體(夏日篇)。
匿名字段結構體
如果以後再遇到匿名這個詞,就把他當作沒有名字的意思。
匿名加字段結構體代碼。
package main
import "fmt"
type Student struct {
string
int
//string //error:duplicate field string
//int //error:duplicate field string
}
func main() {
var s1 = Student{
"666",
0,
}
fmt.Println(s1)
}
第 8 行和第 9 行代碼,如果去掉註釋會報錯。
這就說明了個問題,如果是匿名字段結構體,匿名字段類型是不能重複的,如上述代碼所示。
結構體嵌套
結構體嵌套,就如名字一樣,一個結構體,嵌套了另外一個結構體。
假設
一個學生的信息,假設有姓名,年齡,性別,這三個字段。
這個學生必定要歸屬一個班級的,假設這個班級的信息有年級,幾班,班主任姓名。
創建結構體
根據上述敘述,我們知道一定是有兩個結構體的,至少一個是學生,一個是班級。
班級結構體
type Classes struct {
Grade int //年級
Class int //班級
TeacherName string //班主任姓名
}
學生結構體
type Student struct {
Name string //姓名
Age int //年齡
Gender string //性別
class Classes //所屬班級
}
可以看到第 5 行代碼,結構體的字段類型直接是一個結構體,這就是結構體嵌套、
當一個結構體不能完整描述一個對象時,或者說本來就是獨立的對象有關聯時,就需要結構體嵌套。
嵌套結構體賦值
方式一,直接賦值嵌套結構體
func main() {
var s1 = Student{
Name: "張三",
Age: 18,
Gender: "男",
class: Classes{
Grade: 2020,
Class: 1,
TeacherName: "張三的老師",
},
}
fmt.Println(s1)
}
方式二,分開賦值
func main() {
var c1 = Classes{
Grade: 2020,
Class: 1,
TeacherName: "張三的老師",
}
var s2 = Student{
Name: "張三",
Age: 18,
Gender: "男",
class: c1,
}
fmt.Println(s2)
}
兩次執行結果
其實方式一和方式二的本質是一樣的,只不過是方式二將嵌套的結構體單獨賦值了而已。
匿名嵌套字段
上述我們的Student
結構體是這樣寫的。
type Student struct {
Name string //姓名
Age int //年齡
Gender string //性別
class Classes //所屬班級
}
但是其實第 5 行代碼的字段是可以省略的,就像這樣。
type Student struct {
Name string //姓名
Age int //年齡
Gender string //性別
Classes //所屬班級
}
但是在賦值時,就要注意了,因爲Student
結構體已經沒有字段名了,所以就不能使用上述的方式賦值了
需要這種。
func main() {
var s1 = Student{
Name: "張三",
Age: 18,
Gender: "男",
Classes: Classes{
Grade: 2020,
Class: 1,
TeacherName: "張三的老師",
},
}
}
沒錯,第 5 行的字段名是Classes
結構體名。
執行結果還是一樣的。
補充
上述是直接通過定義變量時就直接賦值了。
其實不管是結構體,還是嵌套結構體,都還有一種方法,就是通過.
的方式賦值,代碼如下。
結構體嵌套
默認的結構體嵌套,結構體還是有字段名的。
type Student struct {
Name string //姓名
Age int //年齡
Gender string //性別
class Classes //所屬班級
}
所以賦值代碼如下。
func main() {
var s1 Student
s1.Name = "張三"
s1.Age = 18
s1.Gender = "男"
s1.class.Grade = 2020
s1.class.Class = 1
s1.class.TeacherName = "張三的老師"
fmt.Println(s1)
}
第 6 行代碼開始,通過 s1 找到 class 這個字段,再根據 class 找到 class 具體對應的值進行賦值。
匿名嵌套字段
匿名嵌套字段是沒有字段名的,是有一個字段類型。
type Student struct {
Name string //姓名
Age int //年齡
Gender string //性別
Classes //所屬班級
}
所以賦值跟上述也不太一樣,是這樣的。
func main() {
var s1 Student
s1.Name = "張三"
s1.Age = 18
s1.Gender = "男"
s1.Classes.Grade = 2020
s1.Classes.Class = 1
s1.Classes.TeacherName = "張三的老師"
fmt.Println(s1)
}
通過 s1 直接找到 Classes 這個結構體,再根據這個結構體找到裏面具體的值,進行賦值。
其實跟定義變量時賦值相似。
但是終究執行結果,還是一樣的,只是賦值形式不同。
結論
根據嵌套結構體和匿名嵌套結構體再賦值時可以發現。
如果嵌套結構體有字段名,通過字段名找具體的字段,進行賦值。
如果是嵌套結構體匿名字段,通過嵌套結構體的名字,找具體字段,進行賦值。
嵌套結構體字段衝突
這個衝突的問題,其實還是比較少見的,這個問題通常情況下,只會出現在匿名嵌套場景中。
還是上述的結構體,但是賦值可以是這樣操作的。
func main() {
var s1 Student
s1.Name = "張三"
s1.Age = 18
s1.Gender = "男"
s1.Classes.Grade = 2020
s1.Classes.Class = 1
s1.Classes.TeacherName = "張三的老師"
//######### 分割 ##########
s1.Grade = 2020 //省去了Classes
s1.Class = 1 //省去了Classes
s1.TeacherName = "張三的老師" //省去了Classes
fmt.Println(s1)
}
第 10 行,直接通過s1.Grade
賦值,其實是省去了一個Classes
,但是這種操作,只有在匿名嵌套結構體中可以使用。
但是如果我將結構體改成這樣子。
//班級
type Classes struct {
Grade int //年級
Class int //班級
TeacherName string //班主任姓名
}
//課程
type Course struct {
CourseName string //課程名字
TeacherName string //任課老師姓名
}
//學生
type Student struct {
Name string //姓名
Age int //年齡
Gender string //性別
Classes //所屬班級
Course //任課老師
}
Student
結構體有兩個匿名嵌套結構體,一個是Classes
,一個是Course
。
但是有一個字段,是衝突的,就是TeacherName
,如果還是通過懶的方式賦值,會發生什麼呢?
func main() {
var s1 Student
s1.Name = "張三"
s1.Age = 18
s1.Gender = "男"
s1.Grade = 2020
s1.Class = 1
s1.TeacherName = "張三的老師"
fmt.Println(s1)
}
第 8 行,直接找TeacherName
字段,這時候就會出問題了。
意思很簡單,就是不知道是Classes
的TeacherName
還是Course
的TeacherName
。
這時候,就必須要指定了。
s1.Classes.TeacherName = "張三的班主任"
s1.Course.TeacherName = "張三的任課老師"
總結
個人建議,還是儘量不要使用匿名嵌套結構體。
如果使用了匿名嵌套結構體,儘可能的採用標準方式賦值,不要採用懶得方式。
如果採用了懶的方式,一定要注意有沒有字段衝突。
最後的總結
上述我們學習了 Go 基礎之結構體的匿名字段結構體,結構體嵌套,匿名結構體嵌套,匿名嵌套結構體字段衝突。
各位小夥伴一定要實踐一下,親手打一下代碼,堅持就是勝利,奧裏給!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/sHJG6OqYupiGhRWXsJD9uQ