Go語言入門-常用數據結構-映射-map
定義
概述
A map is an unordered group of elements of one type, called the element type, indexed by a set of unique keys of another type, called the key type. The value of an uninitialized map is nil.–字典是一種類型的無序元素組,稱爲元素類型,由唯一鍵(稱爲鍵類型)索引關聯其他類型組成。 未初始化映射的值爲nil。引用類型。
1.key必須是支持相等運算符 ("=="、"!=") 類型, 如 number、string、 pointer、array、struct,以及對應的 interface。值可以是任意類型,沒有限制。
2. map類型的變量默認初始值爲nil,需要使用make()函數來分配內存。或者使用初始化表達式,進行初始化。否則會發生panic(map類型的變量默認初始值爲nil,需要使用make()函數來分配內存)
3. map是 not addressable不能直接修改value的值
4. 創建時準備足夠內存,能夠減少擴張的內存分配和重複哈希的動作。
5. map是併發不安全的。
map定義語法
var mapVal map[Type]Type //聲明map
var mapVal map[Type]Type = map[Type]Type { //表達式初始化
"key1" : value1,
...
"keyN" : valueN,
}
var mapVal map[Type]Type = make(map[Type]Type) //make 不指定容量cpa
var mapVal map[Type]Type = make(map[Type]Type, cap) //make 指定容量
map定義示例
- 示例1
普通map的聲明,實際引用的都是nil
func main() {
//普通map聲明,不初始化
var map1 map[int]string
var map2 map[interface{}]string
//實際都是引用nil
fmt.Printf("%#v\n", map1)
//實際值都是引用nil
fmt.Printf("%#v\n", map2)
}
/**
output:
map[int]string(nil)
*/
- 示例2
map使用初始化表達式進行初始化。
func main() {
//聲明
var map1 map[int]string
//表達式初始化
map1 = map[int]string{
1 : "hello",
2 : "hello1",
3 : "hello2",
}
fmt.Printf("%#v\n", map1)
//interface空接口可以映射int
//聲明+表達式初始化
var map2 map[interface{}]int = map[interface{}]int{
1 : 1,
2 : 2,
3 : 3,
}
fmt.Printf("%#v\n", map2)
}
/**
output:
map[int]string{1:"hello", 2:"hello1", 3:"hello2"}
map[interface {}]int{1:1, 2:2, 3:3}
*/
- 示例3
通過make定義map不帶容量 - TODO 不帶容量的map初始map是多少?
func main() {
//make定義了一個map,該map初始沒有值。
map1 := make(map[string]int)
fmt.Printf("%#v\n", map1)
map1["sdff"] = 1
map1["sdff2"] = 2
map1["sdff2"] = 3 //相同值會覆蓋
fmt.Printf("%#v\n", map1)
}
/**
output:
map[string]int{}
map[string]int{"sdff":1, "sdff2":3}
*/
- 示例3
通過make定義map帶容量
func main() {
//make定義了一個map,該map初始沒有值,默認容量爲10
map1 := make(map[string]int, 10)
fmt.Printf("%#v\n", map1)
map1["sdff"] = 1
map1["sdff2"] = 2
map1["sdff2"] = 3 //相同值會覆蓋
fmt.Printf("%#v\n", map1)
}
/**
output:
map[string]int{}
map[string]int{"sdff":1, "sdff2":3}
*/
- 示例4
通過new創建map
func main() {
//只是創建了map的一個指針,返回一個指針,但是沒有初始底層存儲結構 因此new出來的map是不能直接用
var map1 = new(map[int]string)
fmt.Printf("%#v\n", map1)
//因爲map1是指針因此需要使用*
//(*map1)[1] = "333" //panic: assignment to entry in nil map
//讓map1指向map[int]string{} 就可以使用map1
map1 = &map[int]string{}
//因爲map1是指針因此需要使用*
(*map1)[1] = "111"
fmt.Printf("%#v\n", map1)
}
/**
output:
&map[int]string(nil)
&map[int]string{1:"111"}
*/
new()出的map只是一個指針,沒有給底層存儲接口分配值,因此可以理解new返回一個沒有初始化的map的地址,沒有實際作用
使用
map添加key-value
- 示例1
func main() {
var map1 = make(map[string]string, 10)
fmt.Printf("%#v\n", map1)
//添加鍵值 "123"--> "ABC"
map1["123"] = "ABC"
//添加鍵值 "124"--> "ABC"
map1["124"] = "ABC"
//添加鍵值 "125"--> "ABCbbb"
map1["125"] = "ABCbbb"
//重複添加鍵值 "125"--> "ABCbbbNEW" 但是value和上次不一致
map1["125"] = "ABCbbbNEW"
//輸出接口中key"125"只保留最後一次的value
fmt.Printf("%#v\n", map1)
}
/**
output:
map[string]string{}
map[string]string{"123":"ABC", "124":"ABC", "125":"ABCbbbNEW"}
*/
添加相同的鍵,原來的鍵值value會被覆蓋。
只能添加相同類型的元素
map查找key-value
- 示例1
func main() {
var map1 = make(map[string]string, 10)
fmt.Printf("%#v\n", map1)
//添加鍵值 "123"--> "ABC"
map1["123"] = "ABC"
//添加鍵值 "124"--> "ABC"
map1["124"] = "ABC"
//添加鍵值 "125"--> "ABCbbb"
map1["125"] = "ABCbbb"
//重複添加鍵值 "125"--> "ABCbbbNEW" 但是value和上次不一致
map1["125"] = "ABCbbbNEW"
//輸出接口中key"125"只保留最後一次的value
fmt.Printf("%#v\n", map1)
//查找
key := "125"
v, ok := map1[key]
if ok {
fmt.Println("key:", key, "get value :", v)
} else {
fmt.Printf("%#v ", v)
fmt.Println("key:", key, "not found")
}
//沒有查到到
key = "21333"
v, ok = map1[key]
if ok {
fmt.Println("key:", key, "get value :", v)
} else {
//如果沒有查找到,返回value的類型的默認值。因此也可以不用ok進行判斷
fmt.Printf("%#v ", v)
fmt.Println("key:", key, "not found")
}
}
/**
output:
map[string]string{}
map[string]string{"123":"ABC", "124":"ABC", "125":"ABCbbbNEW"}
key: 125 get value : ABCbbbNEW
"" key: 21333 not found
*/
可以通過衛述語句進行判斷是否獲取到值
也可以通過value類型的值默認進行判斷,但是這麼判斷前提是-默認值並能做元素值,否則會有二義性。
map刪除key-value
map使用內建函數delete()來刪除key-value關係,函數定義如下
func delete(m map[Type]Type1, key Type)
- 示例1
func main() {
var map1 = make(map[string]string, 10)
fmt.Printf("%#v\n", map1)
//添加鍵值 "123"--> "ABC"
map1["123"] = "ABC"
//添加鍵值 "124"--> "ABC"
map1["124"] = "ABC"
//添加鍵值 "125"--> "ABCbbb"
map1["125"] = "ABCbbb"
//重複添加鍵值 "125"--> "ABCbbbNEW" 但是value和上次不一致
map1["125"] = "ABCbbbNEW"
//輸出接口中key"125"只保留最後一次的value
fmt.Printf("%#v\n", map1)
//刪除一個不存在值
delete(map1, "rerr")
//不會報錯正常打印元素值
fmt.Printf("%#v\n", map1)
//刪除一個存在的值
delete(map1, "123")
//刪除成功
fmt.Printf("%#v\n", map1)
}
/**
output:
map[string]string{}
map[string]string{"123":"ABC", "124":"ABC", "125":"ABCbbbNEW"}
map[string]string{"123":"ABC", "124":"ABC", "125":"ABCbbbNEW"}
map[string]string{"124":"ABC", "125":"ABCbbbNEW"}
*/
刪除一個不存在的元素鍵值也會成功。
map修改key-value
map的修改參考map添加key-value
- 示例1
func main() {
var map1 = make(map[string]string, 10)
fmt.Printf("%#v\n", map1)
//添加鍵值 "123"--> "ABC"
map1["123"] = "ABC"
//添加鍵值 "124"--> "ABC"
map1["124"] = "ABC"
//添加鍵值 "125"--> "ABCbbb"
map1["125"] = "ABCbbb"
//重複添加鍵值 "125"--> "ABCbbbNEW" 但是value和上次不一致
//也可以理解修改key爲"125"的鍵值
map1["125"] = "ABCbbbNEW"
//輸出接口中key"125"只保留最後一次的value
fmt.Printf("%#v\n", map1)
}
/**
output:
map[string]string{}
map[string]string{"123":"ABC", "124":"ABC", "125":"ABCbbbNEW"}
*/
map遍歷key-value
fori 遍歷
發現並不支持fori。。。。。。
~~func main() {
var map1 = make(map[string]string, 10)
fmt.Printf("%#v\n", map1)
//添加鍵值 "123"--> "ABC"
map1["123"] = "ABC"
//添加鍵值 "124"--> "ABC"
map1["124"] = "ABC"
//添加鍵值 "125"--> "ABCbbb"
for i := 0; i < len(map1); i++ {
//不知怎麼寫了
//寫到這裏發現並不支持
}
}~~
for…range遍歷
- 示例1
func main() {
var map1 = make(map[string]string, 10)
fmt.Printf("%#v\n", map1)
//添加鍵值 "123"--> "ABC"
map1["123"] = "ABC"
//添加鍵值 "124"--> "ABC"
map1["124"] = "ABC"
map1["1266"] = "ABC"
//添加鍵值 "125"--> "ABCbbb"
map1["125"] = "ABCbbb"
for k, v := range map1 {
fmt.Printf("key:%#v value:%#v\n", k, v)
}
}
/**
output:
//輸出結果是無序的
map[string]string{}
key:"1266" value:"ABC"
key:"125" value:"ABCbbb"
key:"123" value:"ABC"
key:"124" value:"ABC"
*/
for range循環遍歷的map是無序的,因爲map底層結構不是順序存放的
for range獲取的到值是值傳遞。map又不支持fori因此 map是 not addressable的
map 排序key-value
因爲map是無序的,那麼如何排序map呢?方法是獲取到key的切片,然後通過遍歷keys去獲取value。
- 示例1
//排序
func main() {
var cap = 100
var map1 = make(map[int]string)
var tmpValue = 0
for i := 0; i < cap; i++ {
tmpValue = rand.Intn(100)
map1[tmpValue] = strconv.Itoa(tmpValue)
}
i := 0
//簡單演示遍歷的值是無需的
for k, v := range map1 {
if i < 3 {
fmt.Printf("key:%#v value:%#v\n", k, v)
}
i++
}
//遍歷key把key存放到切片中
//此處 一定是 len=0 不然會有存在0的情況
keys := make([]int, 0, cap)
for k := range map1 {
keys = append(keys, k)
}
fmt.Println(keys)
//對keys排序
sort.Ints(keys)
fmt.Println("排序後:")
fmt.Println(keys)
//按照排序後key進行遍歷。
for _, key := range keys {
fmt.Printf("%#v(%#v) ", key, map1[key])
}
fmt.Println()
}
/**
output:
key:51 value:"51"
key:96 value:"96"
key:6 value:"6"
[51 96 6 26 83 81 85 45 90 63 33 38 7 47 25 99 59 15 29 87 37 41 3 61 91 62 74 78 20 13 76 77 23 58 31 5 28 8 11 88 24 55 18 94 53 52 0 95 21 98 2 40 89 43 36 56 46 10 66 57]
排序後:
[0 2 3 5 6 7 8 10 11 13 15 18 20 21 23 24 25 26 28 29 31 33 36 37 38 40 41 43 45 46 47 51 52 53 55 56 57 58 59 61 62 63 66 74 76 77 78 81 83 85 87 88 89 90 91 94 95 96 98 99]
0("0") 2("2") 3("3") 5("5") 6("6") 7("7") 8("8") 10("10") 11("11") 13("13") 15("15") 18("18") 20("20") 21("21") 23("23") 24("24") 25("25") 26("26") 28("28") 29("29") 31("31") 33("33") 36("36") 37("37") 38("38") 40("40") 41("41") 43("43") 45("45") 46("46") 47("47") 51("51") 52("52") 53("53") 55("55") 56("56") 57("57") 58("58") 59("59") 61("61") 62("62") 63("63") 66("66") 74("74") 76("76") 77("77") 78("78") 81("81") 83("83") 85("85") 87("87") 88("88") 89("89") 90("90") 91("91") 94("94") 95("95") 96("96") 98("98") 99("99")
*/
map 併發
map可以再迭代的時候刪除元素,新增元素
- 示例1
func main() {
var cap = 6
var map1 = make(map[int]string)
var tmpValue = 0
for i := 0; i < cap; i++ {
tmpValue = rand.Intn(100)
map1[tmpValue] = strconv.Itoa(tmpValue)
}
i := 0
for k, _ := range map1 {
fmt.Println("beg ==", map1)
i++
if i % 2 == 0 {
map1[i+k] = strconv.Itoa(i)
}
fmt.Println("end ==", map1)
}
fmt.Println("fin ==", map1)
}
/**
output:
beg == map[18:18 47:47 59:59 81:81 87:87]
end == map[18:18 47:47 59:59 81:81 87:87]
beg == map[18:18 47:47 59:59 81:81 87:87]
end == map[18:18 47:47 59:59 81:81 87:87 89:2]
beg == map[18:18 47:47 59:59 81:81 87:87 89:2]
end == map[18:18 47:47 59:59 81:81 87:87 89:2]
beg == map[18:18 47:47 59:59 81:81 87:87 89:2]
end == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2]
beg == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2]
end == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2]
beg == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2]
end == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2 95:6]
beg == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2 95:6]
end == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2 95:6]
beg == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2 95:6]
end == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2 95:6 103:8]
fin == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2 95:6 103:8]
*/
當map存在寫操作時,不能併發的進行讀寫刪除,否則進程崩潰,解決辦法是使用sync.Map
- TODO補充例子