#### Go 面向對象之結構體
最近有四天沒更新公衆號,有一些事情耽誤了,生活就是這樣,總會一些事情讓人措不及防;
***山濃水淺,坐看流年***
1. Go 也支持面向對象編程(OOP) 可是它和傳統的面向對象編程仍是有一些區別,並非純粹的面向對象編程;
2. Go 中沒有類(class), Go 中struct 和其它編程語言中的類有同等地位,因此咱們能夠理解Go 是基於struct 來實現OOP;
3. Go 面向對象很簡潔,沒有傳統OOP 的繼承,方法重載,構造函數等等;
4. Go 面向對象仍有繼承,封裝,多態的特性,只是它的實現與傳統的OOP語言不一樣;
##### 結構體與結構體變量(實例/對象)的關係圖
---
說明:
1. 將一類事物的特性提取出來(好比貓類),造成一個新的數據類型就是一個結構體;
2. 經過這個結構體,能夠建立多個變量(實例/對象);
3. 事物能夠是貓類,也能夠是其它的類...;
案例:
package main import "fmt" // 定義一個結構體,相似於類 // 將Cat 的各個字段/屬性,放入到結構體中 type Cat struct { Name string Age uint Color string Hobby string } func main(){ // 聲明一個Cat 變量,也就是實例 var a1 Cat a1.Name = "小花" a1.Age = 2 a1.Color = "black" a1.Hobby = "老鼠" fmt.Println(a1) fmt.Printf("name=%s\n",a1.Name) fmt.Printf("age=%d\n",a1.Age) fmt.Printf("color=%s\n",a1.Color) fmt.Printf("hobby=%s\n",a1.Hobby) }
---
結構體與結構體變量(實例)的區別
1. 結構體是自定義的數據類型,表明一類事物;
2. 結構體變量是具體的,實際的,表明一個具體的變量;
---
##### 結構體變量在內存中的佈局
##### 如何聲明結構體
基本語法:
type 結構體名稱 struct {
field1 type
field2 type
...
}
例如:
typt Person struct {
Name string
Age int
Class string
}
##### 字段屬性
字段是結構體的組成部分,通常是基本數據類型,數組,同時也能夠是引用類型;
注意事項:
1. 字段聲明語法同變量同樣: 字段名 字段類型
2. 在建立一個結構體變量後,若是沒有給字段賦值,每一個字段都對應一個默認值,引用類型默認值爲nil;
3. 不一樣結構體變量的字段是獨立的,互不影響: 結構體是值類型;
package main import "fmt" // 若是結構體裏的字段是引用類型的: slice map channel; // 在使用前須要make分配內存才能使用; type Person struct { Name string Age int Hobby [3]string ptr *string slice []int Parents map[string]string } type Cat struct { Name string Age int } func main(){ var a1 Person fmt.Println(a1) //{0 [] nil [] map[]} if a1.ptr == nil { fmt.Println("ptr is nil") } if a1.slice == nil { fmt.Println("slice is nil") } if a1.Parents == nil { fmt.Println("parents is nil") } // 結構體字段是引用類型的話,使用前須要make a1.slice = make([]int,10) a1.slice[0] = 1 a1.slice[1] = 2 a1.slice[2] = 3 a1.Parents = make(map[string]string) a1.Parents["name"] = "aaaa" a1.Parents["friendly"] = "father" fmt.Println(a1) // { 0 [ ] <nil> [1 2 3 0 0 0 0 0 0 0] map[friendly:father name:aaaa]} // 不一樣結構體變量間互不影響 var c1 Cat var c2 Cat c1.Name = "c1" c2.Name = "c2" c1.Age = 1 c2.Age = 2 fmt.Println(c1,c2) //{c1 1} {c2 2} }
---
##### 建立結構變量和訪問結構體字段
package main import "fmt" type Cat struct { Name string Age int } func main(){ // 方式1: 先聲明,再賦值 var c1 Cat c1.Name = "c1" c1.Age = 1 fmt.Println(c1) //{c1 1} // 方式2: 字面量方式 var c2 Cat = Cat{"c2",2} fmt.Println(c2) //{c2 2} // 方式3: 類型推導方式 c3 := Cat{"c3",3} fmt.Println(c3) //{c3 3} // 方式4: new 方式 var c4 *Cat = new(Cat) c4.Name = "c4" c4.Age = 4 fmt.Println(*c4) // 方式5: &{} 方式 var c5 *Cat = &Cat{} c5.Name = "c5" c5.Age = 5 fmt.Println(*c5) // 方式4,方式5 返回的都是結構體的指針類型 }
1. 第4,5 種方式返回的是***結構體指針***;
2. 結構體指針訪問字段的標準方式應該是:(*結構體指針).字段名, 如:(*c4).Name = "c4";
3. Go 作了簡化,支持***結構體指針.字段名***,如:c4.Name = "c4",Go 編譯器底層自動處理了;
---
##### 結構體使用注意事項
1. 結構體中全部的字段在內存中是連續的;
2. 結構體是用戶自定義的類型,在和其它類型轉換時須要有徹底相同的字段(名稱,個數,類型);
3. 結構體進行type 定義,Go 認爲是新的數據類型,能夠和基本數據類型進行強轉;
4. 結構體每一個字段上能夠寫tag,tag 能夠經過反射機制獲取,經常使用的場景是序列化和反序列化;
package main import ( "encoding/json" "fmt" ) type Person struct { Name string Age int Hobby string } type Student struct { Name string Age int Hobby string } type Cat struct { Name string `json:"name"` Age int `json:"age"` } func main(){ var p1 Person p1.Name = "p1" p1.Age = 22 p1.Hobby = "run" // 結構體變量的地址 fmt.Printf("p1 address: %p\n",&p1) fmt.Printf("p1.Name address: %p\n",&p1.Name) // 0xc0000562d0 fmt.Printf("p1.Age address: %p\n",&p1.Age) // 0xc0000562e0 , 一個string 是16 字節 fmt.Printf("p1.Hobby address: %p\n",&p1.Hobby)//0xc0000562e8 , 一個int 在64 位系統中爲8字節 // 類型之間強轉 var s1 Student s1 = Student(p1) fmt.Println(s1) fmt.Printf("s1 type is %T\n",s1) // Student // struct tag var c1 Cat c1.Name = "小花" c1.Age = 12 jsonStr,err := json.Marshal(c1) if err != nil { fmt.Println(err) } // 輸出的是結構體中tag 定義的名稱 fmt.Println(string(jsonStr)) // {"name":"小花","age":12} }
我的微信公衆號上有最新內容,歡迎關注交流學習編程