一 、==========================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个元素指定,其它的元素值默认为"" 空字符串
里面索引为 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 作为参数时,直接复制指针。
有疑问加站长微信联系(非本文作者)