以下内容都来源于Go语言101: 数组、切片和映射 -Go语言101
容器类型和容器值概述
每个容器(值)用来表示和存储一个元素(element)序列或集合。一个容器中的所有元素的类型是相同的。
我认为以上说的就是Go语言中的map和Java中的map是一样的,key和value都可以是任意值,比如Java中的对象。
一个数组或者切片的所有元素紧挨着存放在一块连续的内存中。一个数组中的所有元素均存放在此数组值的直接部分,一个切片中的所有元素均存放在此切片值的间接部分。一个映射中的所有元素也均存放在一块连续的内存中,但是映射中的元素并不一定紧挨着存放。
查看容器值的长度和容量
- 数组的容量和它的长度是相等的,一个非零映射值的容量可以是无限的。
- 可以调用内置函数
len
来获取长度,调用cap
来获取容量。 - 数组的长度和容量是不可变的,切片的长度和容量是动态改变的,可以认为是动态数组
读取和修改容器的元素
package main
import "fmt"
func main() {
a := [3]int{-1, 0, 1}
s := []bool{true, false}
m := map[string]int{"abc": 123, "xyz": 789}
fmt.Println (a[2], s[1], m["abc"]) // 读取
a[2], s[1], m["abc"] = 999, true, 567 // 修改
fmt.Println (a[2], s[1], m["abc"]) // 读取
n, present := m["hello"]
fmt.Println(n, present, m["hello"]) // 0 false 0
n, present = m["abc"]
fmt.Println(n, present, m["abc"]) // 567 true 567
m = nil
fmt.Println(m["abc"]) // 0
// 下面这两行编译不通过。
/*
_ = a[3] // 下标越界
_ = s[-1] // 下标越界
*/
// 下面这几行每行都会造成一个恐慌。
_ = a[n] // panic: 下标越界
_ = s[n] // panic: 下标越界
m["hello"] = 555 // panic: m为一个零值映射
}
容器赋值
当一个映射赋值语句执行完毕之后,目标映射值和源映射值将共享底层的元素。 向其中一个映射中添加(或从中删除)元素将体现在另一个映射中。
和映射一样,当一个切片赋值给另一个切片后,它们将共享底层的元素。它们的长度和容量也相等。 但是和映射不同,如果以后其中一个切片改变了长度或者容量,此变化不会体现到另一个切片中。
当一个数组被赋值给另一个数组,所有的元素都将被从源数组复制到目标数组。赋值完成之后,这两个数组不共享任何元素。
package main
import "fmt"
func main() {
// 映射
m0 := map[int]int{0:7, 1:8, 2:9}
m1 := m0
m1[0] = 2
fmt.Println(m0, m1) // map[0:2 1:8 2:9] map[0:2 1:8 2:9]
// 切片
s0 := []int{7, 8, 9}
s1 := s0
s1[0] = 2
fmt.Println(s0, s1) // [2 8 9] [2 8 9]
// 数组
a0 := [...]int{7, 8, 9}
a1 := a0
a1[0] = 2
fmt.Println(a0, a1) // [7 8 9] [2 8 9]
}
添加修改删除
如果没有就是添加,如果有就是修改
m[k] = e
如果有这个key就是删除,如果没有就是一个空操作,不会有任何影响
delete(m, k)
数组
一个数组中的元素个数总是恒定的,我们无法向其中添加元素,也无法从其中删除元素。但是可寻址的数组值中的元素是可以被修改的。
我们可以通过调用内置append函数,以一个切片为基础,来添加不定数量的元素并返回一个新的切片。 此新的结果切片包含着基础切片中所有的元素和所有被添加的元素。 注意,基础切片并未被此append函数调用所修改。
请注意,当一个append函数调用需要为结果切片开辟内存时,结果切片的容量取决于具体编译器实现。 在这种情况下,对于官方标准编译器,如果基础切片的容量较小,则结果切片的容量至少为基础切片的两倍。 这样做的目的是使结果切片有足够多的冗余元素槽位,以防止此结果切片被用做后续其它append函数调用的基础切片时再次开辟内存。
package main
import "fmt"
func main() {
var s = append([]string(nil), "array", "slice")
fmt.Println(s) // [array slice]
fmt.Println(cap(s)) // 2
s = append(s, "map")
fmt.Println(s) // [array slice map]
fmt.Println(cap(s)) // 4
s = append(s, "channel")
fmt.Println(s) // [array slice map channel]
fmt.Println(cap(s)) // 4
}
使用内置make函数来创建切片和映射
除了使用组合字面量来创建映射和切片,我们还可以使用内置make函数来创建映射和切片。 数组不能使用内置make函数来创建。
package main
import "fmt"
func main() {
// 创建映射。
fmt.Println(make(map[string]int)) // map[]
m := make(map[string]int, 3)
fmt.Println(m, len(m)) // map[] 0
m["C"] = 1972
m["Go"] = 2009
fmt.Println(m, len(m)) // map[C:1972 Go:2009] 2
// 创建切片。
s := make([]int, 3, 5)
fmt.Println(s, len(s), cap(s)) // [0 0 0] 3 5
s = make([]int, 2)
fmt.Println(s, len(s), cap(s)) // [0 0] 2 2
}
插入一条不相关的demo
package main
import "fmt"
func main() {
ma := map[int][5]int{} // 创建一个key为int value为长度为5的整数数组
ma[1] = [5]int{1: 789} // key为1,value数组索引1为789,其他索引为默认值
fmt.Print(ma)
}
// 输出结果为:map[1:[0 789 0 0 0]]
使用内置clear函数来清空映射条目或者重置切片元素
package main
import "fmt"
func main() {
s := []int{1, 2, 3}
clear(s)
fmt.Println(s) // [0 0 0]
a := [4]int{5, 6, 7, 8}
clear(a[1:3])
fmt.Println(a) // [5 0 0 8]
m := map[float64]float64{}
x := 0.0
m[x] = x
x /= x // x变成了NaN
m[x] = x
fmt.Println(len(m)) // 2
for k := range m {
delete(m, k)
}
fmt.Println(len(m)) // 1
clear(m)
fmt.Println(len(m)) // 0
}