一、概述:
這里主要討論四種類型———數組、slice、map和結構體
數組和結構體是聚合類型;它們的值都是由很多個元素或者成員字段的值組成。數組是有同構元素組成——每個數組的元素的類型相同;結構體為異構元素組成——每個結構體不一定是同類型元素構成;數組和結構體都是有固定內存大小的數據結構;
slice和map則是動態的數據結構,它們需要動態增長;
需要注意的是函數中傳遞數組:一般而言,當調用函數時,函數的每個調用參數將會被賦值給函數內部的形式參數,所以函數參數接收的是一個復制的副本,而不是原始調用的變量。因此函數參數傳遞的機制導致了傳遞大數組將十分低效,並且對數組參數的任何修改都將發生在復制的數組上,而並不能直接修改調用時原始的數組變量。與其他語言的做法(隱式地作為引用或者指針對象傳入)不同,golang可以顯示傳入一個數組指針:
1 func zero(ptr *[3]int) { 2 for i := range ptr { 3 ptr[i] = 0 4 } 5 fmt.Println(ptr) 6 } 7 myarray := [...]int{10, 20, 30} 8 for _, v := range myarray { 9 fmt.Println(v) 10 } 11 zero(&myarray) // 注意 &
即便如此,數組依然很少用作函數參數,我們一般使用slice來替代數組;
二、slice
slice(切片)代表變長的序列,序列的元素是同類型的;slice是輕量級的數據結構,提供了訪問數組子序列(或者全部)元素的功能;
slice由三部分構成:指針、長度、容量
1 func reverse(s []int) { 2 for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { 3 s[i], s[j] = s[j], s[i] 4 } 5 } 6 7 myarray := [...]int{10, 20, 30} 8 for _, v := range myarray { 9 fmt.Println(v) 10 } 11 //zero(&myarray) 12 reverse(myarray[:]) //傳slice
warning:slice之間不能進行比較,因此不用用==來判斷兩個slice是否含有相同的元素,如果需要比較slice則需要通過標准庫提供的高度優化的bytes.Equel來判別兩個slice是否相同([]byte), 但是對於其他類型的slice, 必須展開每個元素進行比較:
func equal(x, y [] string) bool { if len(x) != len(y) { return false } for i := range x{ if x[i] != y[i] { return false } } return true }
唯一合法的slice比較操作是和nil比較:
if summer == nil { /* ... */}
三、map
1 ages := make(map[string]int) 2 或ages := map[string]int { 3 "allen": 32, 4 "pual": 34, 5 }
map中的元素並不是一個變量,因此不能對map的元素進行取址操作:
_ = &ages["bob"] //compile error: cannot take address of map element
禁止對map元素取址的原因是map可能隨着元素數量增長而重新分配更大的內存空間,從而可能對之前的地址失效;
map遍歷:map的迭代順序是不確定的,並且不通的哈希函數實現可能導致不同的遍歷順序,在實踐中,遍歷的順序是隨機的,每一次遍歷的順序都不同的,這是故意的,每次都是使用隨機的遍歷順序可以強制要求程序不會依賴具體的哈希函數實現,如果要按順序遍歷key/value對,必須顯示對key進行排序,可以使用sort包對Strings函數對字符串slice進行排序。