21天從Java轉向Go之第五天——水滴石穿(複合資料型別)
阿新 • • 發佈:2021-11-28
複合資料型別
-
複合資料型別是由基本資料型別以各種方式組合而構成的。這章重點講解四種複合資料型別。分別是陣列、slice、map和結構體。
-
陣列和結構體都是聚合型別。它們的值由記憶體中的一組變數構成。陣列的元素具有相同的型別。而結構體中的元素資料型別則可以不同。陣列和結構體的長度是固定的。而slice和map都是動態資料結構,它們的長度在元素新增到結構中時可以動態增長。
陣列
package main import ( "fmt" "reflect" ) var array [3]int type currency int const ( RMB currency = iota EUR USD ) func main() { array[0] = 22 array[1] = 33 array[2] = 44 fmt.Println(array) //[22 33 44] for i, v := range array { fmt.Println(i, v) //0 22 //1 33 //2 44 } for _, v := range array { fmt.Println(v) //22 33 44 } //slice arr2:= []int{1,2,3} fmt.Println(reflect.TypeOf(arr2)) fmt.Printf("arr2型別:%T\n",arr2) arr3:= [3]int{1,2,3} fmt.Println(reflect.TypeOf(arr3)) fmt.Println(arr3) arr4:= [...]int{1,2,3} fmt.Println(reflect.TypeOf(arr4)) fmt.Println(arr3 == arr4) //true 陣列型別,長度相同才能比較 fmt.Println(&arr3 == &arr4) //false money := [...]currency{RMB:8,USD:9,EUR:10} fmt.Println(money) for i, c := range money { fmt.Println(i,c) } //可以指定索引位置的元素值,其他位置是零值 arr5:= [...]string{"11",10:"ssss","22"} fmt.Println(arr5) b:= [...]byte{1,2,3} zeroClear2(&b) fmt.Println("After zeroClear:",b) } func zeroClear(p *[3]byte) { for i := range p { p[i] = 0 } } func zeroClear2(p *[3]byte) { *p = [3]byte{} }
slice
-
slice表示一個擁有相同型別元素的可變長度的序列。slice通常寫作[]T,看上去像沒有指定長度的陣列。
-
slice是一種輕量級的資料結構,可以用來訪問陣列的部分或全部的元素,而這個陣列被稱為slice的底層陣列。
-
slice有三個屬性:指標、長度和容量。指標指向陣列的第一個可以從slice訪問的元素,這個元素並不一定是陣列的第一個元素。長度是指slice中元素的個數,不能超過slice的容量。容量的大小通常是從slice的起始元素到底層陣列的最後一個元素間元素的個數。
-
Go的內建函式len和cap用來返回slice的長度和容量。
-
因為slice包含了指向陣列的指標,因此在函式傳遞引數時,函式內做的修改會影響到slice指向的底層陣列。
-
對一個切片再次slice[m:n]運算時,是對slice的指向的底層陣列再計算(再切片運算)。slice[i]訪問slice切片的第i個位置的元素,slice[:n] 如果n大於slice指向底層陣列的容量cap,會導致程式宕機。如果大於len(slice)小於cap(slice),則會擴容slice
package main import ( "fmt" ) var arr = [...]int{1,2,3,4,5,6,7,8,9} func main() { slice1 := arr[1:4] fmt.Println("slice1的len和cap分別是",len(slice1),cap(slice1)) //slice1的len和cap分別是 3 8 fmt.Println("slice1:",slice1) //slice1: [2 3 4] slice2 := arr[2:8] fmt.Println("slice1的len和cap分別是",len(slice2),cap(slice2)) //slice1的len和cap分別是 6 7 fmt.Println("slice2:",slice2) //slice2: [3 4 5 6 7 8] slice2[1] = 1//slice陣列修改影響其他共用的底層陣列 fmt.Println("slice2:",slice2) //slice2: [3 1 5 6 7 8] fmt.Println("slice1:",slice1) //[2 3 1] //slice指向底層陣列切片 slice2 = slice2[:3] fmt.Println(slice2) //[3 1 5] 縮容 slice2 = slice2[:7] fmt.Println(slice2) //[3 1 5 6 7 8 9] 擴容 //slice2 = slice2[:8] //panic: runtime error: slice bounds out of range [:8] with capacity 7 fmt.Println(slice2) //[3 1 5] //make函式 //指定長度 容量不指定預設和長度相同 ints := make([]int, 2) //分別指定len和cap ints2 := make([]int, 2,5) fmt.Println(ints) //[0 0] fmt.Println("ints","len:",len(ints),",cap:",cap(ints)) //ints len: 2 ,cap: 2 fmt.Println("ints2","len:",len(ints2),",cap:",cap(ints2)) //ints2 len: 2 ,cap: 5 //append函式 自動擴容 ints = append(ints, 1) fmt.Println(ints) //[0 0 1] fmt.Println(len(ints), cap(ints)) // 3 4 ints = append(ints, 1) fmt.Println(ints) //[0 0 1 1] fmt.Println(len(ints), cap(ints)) // 4 4 ints = append(ints, 1) fmt.Println(ints)//[0 0 1 1 1] fmt.Println(len(ints), cap(ints)) //5 8 //coupy函式 src複製到dst切片 i := copy(ints, arr[0:4]) fmt.Println("copy length:",i) fmt.Println("ints:",ints) }
map
-
map[K]V K是和V是字典鍵和值對應的資料型別,鍵的型別必須是通過==可以判斷的資料型別(切片不可以)。
-
內建函式make可以用來初始化一個map
package main
import (
"fmt"
"sort"
)
var hashmap = make(map[int]string)
func main() {
hashmap[1] = "1"
hashmap[2] = "2"
hashmap[3] = "3"
hashmap[4] = "4"
hashmap[5] = "5"
fmt.Println(hashmap)
//使用字面量初始化map
m := map[int]string{1: "22", 2: "222", 3: "2222"}
fmt.Println(m)
//移除元素delete
delete(hashmap, 12)
fmt.Println(hashmap)
//賦值
hashmap[1] += "呢哇 1"
fmt.Println(hashmap)
//無法獲取map某元素的地址值 因為map是動態的 獲取到的地址可能已經變成其他元素了
//s := &hashmap[1]
m2 := &hashmap
fmt.Println(m2)
//遍歷
for k, v := range hashmap {
fmt.Println(k, v)
}
//按k的順序遍歷map
keys := make([]int, 0, len(hashmap))
for k := range hashmap {
keys = append(keys, k)
}
sort.Ints(keys)
for _, key := range keys {
v := hashmap[key]
fmt.Println("按k的順序排序:v=", v)
}
newMap := make(map[string]string)
newMap["sss"] = "sss"
fmt.Println(newMap)
//panic: assignment to entry in nil map
//var newMap2 map[string]string
//newMap2["sss"] = "ssss"
//fmt.Println(newMap2)
if _, ok := newMap["ssss"]; !ok {
fmt.Println("not exist ele","ssss")
}
}
結構體
package main
import (
"encoding/json"
"fmt"
)
type Man struct {
h Human
sex, gender int
Human
Hello string `json:"Hello"`
}
type Human struct {
Age int
height float32
}
func main() {
v := new(Man)
v.sex = 1
v.h.height = 177.11
v.h.Age = 28
v.Age = 30
v.height = 188
v.gender = 1
fmt.Println(*v)
man := Man{h: Human{Age: 28, height: 177.11}, sex: 1, gender: 1, Human: Human{Age: 100, height: 100.00}}
fmt.Println(man)
//結構體的比較 成員變數都可比較才能比較
fmt.Println(man == *v)
man = *v
fmt.Println(man)
marshal, err := json.Marshal(*v)
fmt.Println(err)
fmt.Printf("%s\n", marshal)
x := "{\"Hello\":\"111\"}"
v2 := new(Man)
json.Unmarshal([]byte(x), v2)
fmt.Printf("%#v",v2)
}