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补充例子

猜你喜欢

转载自blog.csdn.net/u011461385/article/details/106054479