04 Data Types - Aggregate Types
- arrays
- structs
記憶體管理方式:
- 連續的記憶體空間
- 固定長度
原文:
Arrays and structs are aggregate types; their values are concatenations of other values in memory. Arrays are homogeneous—their elements all have the same type—whereas structs are heterogeneous. Both arrays and structs are fixed size.book1
book1. from The Go Programming Language ↩
注意:
- pass by value, 會 copy 原本資料,因此要小心記憶體的問題。可改用 slice 及 pointer。
Arrays
Array Declaration
var a [3]int // [0,0,0] var q [3]int = [3]int{1, 2, 3} var r [3]int = [3]int{1, 2} fmt.Println(r[2]) // "0" q := [...]int{1, 2, 3} fmt.Printf("%T\n", q) // "[3]int" x := [...]int{99: -1} // value of 0 ~ 98th is "0", and 99th is "-1", length of array is 100
Array Travel
// Print the indices and elements. for i, v := range a { fmt.Printf("%d %d\n", i, v) } // Print the elements only. for _, v := range a { fmt.Printf("%d\n", v) }
itoa
type Currency int const ( USD Currency = iota EUR GBP RMB ) symbol := [...]string{USD: "$", EUR: "€", GBP: "£", RMB: "¥"} fmt.Println(RMB, symbol[RMB]) // "3 ¥"
Array Compare
If an array’s element type is comparable then the array type is comparable too, so we may directly compare two arrays of that type using the == operator, which reports whether all corresponding elements are equal. The != operator is its negation.
a := [2]int{1, 2} b := [...]int{1, 2} c := [2]int{1, 3} fmt.Println(a == b, a == c, b == c) // "true false false" d := [3]int{1, 2} fmt.Println(a == d) // compile error: cannot compare [2]int == [3]int
Struct
跟 C 的 struct 用法一樣。struct 可以組合多個不同型別的資料,每一個資料欄位,稱作 field.
Struct Declaration
type Employee struct { ID int Name string Address string DoB time.Time Position string Salary int ManagerID int } var dilbert Employee dilbert.Salary -= 5000 // demoted, for writing too few lines of code position := &dilbert.Position *position = "Senior " + *position // promoted, for outsourcing to Elbonia wally := Employee { ID: 1, Name: "Wally", }
與 C 不同的是,一個空白的 struct,會依照每一個 field 的資料型別,自動帶入該型別的 zero value。如:int 則為 0, string 則為 ""
Struct Pointer
與 C 一樣,struct 通常會撘配 pointer 來處理。與 C 不同是操作語法。在 C 中,如果是實例 (instance),則用
.
來操作, eg:x.A
,如果是指標 (pointer),則用->
, eg:x->A
。在 Go 則都用.
來操作,也因此要小心是在用 instance 還是 pointer。alice := &Employee { ID: 2, Name: "Alice", } func EmployeeByID(id int) *Employee { /* ... */ } fmt.Println(alice.ID)
Struct Compare
If all the fields of a struct are comparable, the struct itself is comparable, so two expressions of that type may be compared using == or !=. The == operation compares the corresponding fields of the two structs in order, so the two printed expressions below are equivalent:
type Point struct{ X, Y int } p := Point{1, 2} q := Point{2, 1} fmt.Println(p.X == q.X && p.Y == q.Y) // "false" fmt.Println(p == q) // "false"
Struct Embedding and Anonymous Fields
struct 裏還可以再包含 struct。在程式寫作上,會有點麻煩。如下:
type Point struct { X, Y int } type Circle struct { Center Point Radius int } type Wheel struct { Circle Circle Spokes int } var w Wheel w.Circle.Center.X = 8 w.Circle.Center.Y = 8 w.Circle.Radius = 5 w.Spokes = 20
可以修改成下面的寫法:
type Circle struct { Point Radius int } type Wheel struct { Circle Spokes int } var w Wheel w.X = 8 // equivalent to w.Circle.Point.X = 8 w.Y = 8 // equivalent to w.Circle.Point.Y = 8 w.Radius = 5 // equivalent to w.Circle.Radius = 5 w.Spokes = 20 w = Wheel{Circle{Point{8, 8}, 5}, 20} w = Wheel{ Circle: Circle{ Point: Point{X: 8, Y: 8}, Radius: 5, }, Spokes: 20, // NOTE: trailing comma necessary here (and at Radius) }
struct 可以透過 Anonymous Field 來達到 OO 繼承的效果。
JSON
Go 有內建處理 JSON 的套件 encoding/json
eg:
type Movie struct {
Title string
Year int `json:"released"`
Color bool `json:"color,omitempty"`
Actors []string
}
var movies = []Movie{
{Title: "Casablanca", Year: 1942, Color: false, Actors: []string{"Humphrey Bogart", "Ingrid Bergman"}},
{Title: "Cool Hand Luke", Year: 1967, Color: true, Actors: []string{"Paul Newman"}},
{Title: "Bullitt", Year: 1968, Color: true, Actors: []string{"Steve McQueen", "Jacqueline Bisset"}},
}
data, err := json.Marshal(movies)
if err != nil {
log.Fatalf("JSON marshaling failed: %s", err)
}
/*
[{"Title":"Casablanca","released":1942,"Actors":["Humphrey
Bogart","Ingr
id Bergman"]},{"Title":"Cool Hand
Luke","released":1967,"color":true,"Ac
tors":["Paul Newman"]},
{"Title":"Bullitt","released":1968,"color":true,"
Actors":["Steve McQueen","Jacqueline Bisset"]}]
*/
fmt.Printf("%s\n", data)
var titles []struct{ Title string }
if err := json.Unmarshal(data, &titles); err != nil {
log.Fatalf("JSON unmarshaling failed: %s", err)
}
fmt.Println(titles) // "[{Casablanca} {Cool Hand Luke} {Bullitt}]"
var movie1 Movie
err = json.Unmarshal([]byte(`{"Title":"Casablanca","released":1942,"Actors":["Humphrey Bogart","Ingrid Bergman"]}`), &movie1)
if err != nil {
log.Fatalf("JSON unmarshaling failed: %s", err)
}
fmt.Println("movie1", movie1)
- 在宣告 struct 時,加入 json 的 annotation. 如:
json:"color,omitempty"
,color
是指 json 的欄位名稱,omitempty
是指如果該欄位值是 zero value,則不輸出 json。 - 如果沒有寫 json 的 annotation, 則直接用變數名稱。建議還是都加 annotation 重新定義。
- 使用 json.Umarshal 來取得資料。
- 使用 json.Marshal 來輸出 json 資料。