Go語言入門-常用數據結構之字典-map

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補充例子
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章