這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
一 、==========================array 數組===================================
索引只能是 int 整數型 所以不管幾維數組 索引都是 整數 slice 是動態數組 索引也是 整數型 map為key 所以 可以為 整數 也可以為 字串型
注意slice和數組在聲明時的區別:聲明數組時,方括弧內寫明了數組的長度或使用...自動計算長度,而聲明slice時,方括弧內沒有任何字元。
arr1 := [10]int{1,2,3,4} //數組,長度為10,只有4個元素指定,其它的元素值預設為0
arr2 := [...]string{"a","b","c"} //數組,長度自適應,這裡長度為3
s1 := []int{1,2,3,4} //slice,目前長度為4,可能通過append來動態添加元素個數
數組聲明 方式
arr1 := [10]int{1,2,3,4} //數組,長度為10,只有4個元素指定,其它的元素值預設為0
裡面索引為 0:1 1:2 2:3 3:4 4:0 5:0 ..... 9:0
arr1 := [10]string{"1","2","3","4"} //數組,長度為10,只有4個元素指定,其它的元素值預設為"" Null 字元串
裡面索引為 0:"1" 1:"2" 2:"3" 3:"4" 4:"0" 5:"" ..... 9:""
arr2 := [...]string{"a","b","c"} //數組,長度自適應,這裡長度為3
arr3 := make([]int, 10) // make 為建立記憶體 長度為10 元素都為 0
var arr4 [5]int
arr4[0] = 9
arr4=[5]int{5,5,5} // [5 5 5 0 0]
可以用 new() 建立數組,返回數組指標。
func test(a *[10]int) {
a[2] = 100 // 用指標直接操作沒有壓力。
}
func main() {
var a = new([10]int) // 返回指標。
test(a)
fmt.Println(a, len(a))
}
輸出結果:
&[0 0 100 0 0 0 0 0 0 0] 10
多維陣列
a := [2][2]int{ {1,2}, {3,4} }
b := [2][2]str{ {"1","2"}, {"3","4"} }
func main() {
var a = [3][2]int{ [...]int{1, 2}, [...]int{3, 4} }
var b = [3][2]int{ {1, 2}, {3, 4} }
c := [...][2]int{ {1, 2}, {3, 4}, {5, 6} } // 第二個維度不能用 "..." 。
c[1][1] = 100
fmt.Println(a, "\n", b, "\n", c, len(c), len(c[0]))
}
數組比較
println([1]string{"a"} == [1]string{"a"})
數組是實值型別,也就是說會拷貝整個數組記憶體進行值傳遞。可用 slice 或指標代替。
二 、 ==========================slice 切片===================================
切片就是數組取其中的部分就為切片為取出的數組數值的指標集合。
數組 索引只能是 int 整數型 所以不管幾維數組 索引都是 整數 slice 是動態數組 索引也是 整數型 map為key 所以 可以為 整數 也可以為 字串型
注意slice和數組在聲明時的區別:聲明數組時,方括弧內寫明了數組的長度或使用...自動計算長度,而聲明slice時,方括弧內沒有任何字元。
切片聲明
s := []int{ 0, 1, 2 }
不能使用 new(),而應該是 make([]T, len, cap)。因為除了分配記憶體,還需要設定相關的屬性。如
果忽略 cap 參數,則 cap = len 。
func main() {
s1 := make([]int, 10) // 相當於 [10]int{...}[:]
s1[1] = 100
fmt.Println(s1, len(s1), cap(s1))
s2 := make([]int, 5, 10)
s2[4] = 200
fmt.Println(s2, len(s2), cap(s2))
}
輸出:
[0 100 0 0 0 0 0 0 0 0] 10 10
[0 0 0 0 200] 5 10
可以用 append() 向 slice 尾部添加新元素,這些元素儲存到底層數組。append 並不會影響原 slice的屬性,它返回變更後新的 slice 對象。如果超出 cap 限制,則會重新分配底層數組。
==========================Maps 字典===================================
參考型別,類似 Python dict ,不保證 Key/Value 存放順序。Key 必須是支援比較子 (== 、!=)的類型。如 number 、string 、pointer、array、struct 、interface (介面實作類別型必須支援比較子),不能是 function、map、slice。
map 尋找操作比線性搜尋快很多,但比起用序號訪問 array、slice,大約慢 100x 左右。絕大多數時候,其操作效能要略好於 Python Dict 、C++ Map。
func test(d map[string]int) {
d["x"] = 100
}
func main() {
var d = map[string]int{ "a":1, "b":2 };
d2 := map[int]string{ 1:"a", 2:"b" };
test(d)
fmt.Println(d, d2)
d3 := make(map[string]string)
d3["name"] = "Jack"
fmt.Println(d3, len(d3))
}
輸出:
map[a:1 b:2 x:100] map[1:a 2:b]
map[name:Jack] 1
使 array/struct key 的例子。
type User struct {
Name string
}
func main() {
a := [2]int{ 0, 1}
b := [2]int{ 0, 1}
d := map[[2]int]string { a: "ssss" }
fmt.Println(d, d[b])
u := User{ "User1" }
u2 := u
d2 := map[User]string { u: "xxxx" }
fmt.Println(d2, d2[u2])
}
輸出:
map[[0 1]:ssss] ssss
map[{User1}:xxxx] xxxx
value 的類型就很自由了,完全可以用匿名結構或者空介面。
type User struct {
Name string
}
func main() {
i := 100
d := map[*int]struct{ x, y float64 } { &i: { 1.0, 2.0 } }
fmt.Println(d, d[&i], d[&i].y)
//d2 := map[interface{}]string { "a": "1", 1:"ssssss" }
d2 := map[string]interface{} { "a": 1, "b": User{ "user1" } }
fmt.Println(d2, d2["b"].(User).Name)
}
輸出:
map[0x42132018:{1 2}] {1 2} 2
map[a:1 b:{user1}] user1
使用 make() 建立 map 時,提供一個合理的初始容量有助於減少後續新增操作的記憶體配置次數。在需要時,map 會⾃動擴張容量。
常用的判斷和刪除操作:
func main() {
var d = map[string]int{ "a":1, "b":2 };
v, ok := d["b"] // key b 存在,v = ["b"], ok = true
fmt.Println(v, ok)
v = d["c"] // key c 不存在,v = 0 (default)
fmt.Println(v) // 要判斷 key 是否存在,建議用 ok idiom 模式。
d["c"] = 3 // 添加或修改
fmt.Println(d)
delete(d, "c") // 刪除。刪除不存在的 key,不會引發錯誤。
fmt.Println(d)
}
輸出:
2 true
0 false
map[a:1 c:3 b:2]
map[a:1 b:2]
迭代器用法:
The Go 1 .1 hashmap iteration starts at a random bucket. However, it stores up to 8 key/value pairs in a bucket.
And within a bucket, hashmap iteration always returns the values in the same order .
func main() {
d := map[string]int{ "a":1, "b":2 };
for k, v := range d { // 擷取 key, value
println(k, "=", v)
}
for k := range d { // 僅擷取 key
println(k, "=", d[k])
}
}
通過 map[key] 返回的只是一個 "臨時值拷貝",修改其自身狀態沒有任何意義,只能重新 value 賦值或改用指標修改所引用的記憶體。
type User struct {
Id int
Name string
}
func main() {
users := map[string]User{
"a": User{1, "user1"},
}
fmt.Println(users)
// Error: cannot assign to users["a"].Name
//users["a"].Name = "Jack"
// 重新 value 賦值
u := users["a"]
u.Name = "Jack"
users["a"] = u
fmt.Println(users["a"])
// 改⽤指標類型
users2 := map[string]*User{
"a2": &User{2, "user2"},
}
users2["a2"].Name = "Tom"
fmt.Println(users2["a2"])
}
輸出:
map[a:{1 user1}]
{1 Jack}
&{2 Tom}
可以在 for range 迭代時安全刪除和插入新的字典項。
func main() {
d := map[string]int { "b":2, "c":3, "e":5 }
for k, v := range d {
println(k, v)
if k == "b" { delete(d, k) }
if k == "c" { d["a"] = 1 }
}
fmt.Println(d)
}
輸出:
c 3
b 2
e 5
map[a:1 c:3 e:5]
註:map 作為參數時,直接複製指標。