golang map_golang map长度 - CSDN
精华内容
参与话题
  • golangmap详解

    2019-10-14 10:10:58
    待更新

    map初探

    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    func main() {
    	var mv map[string]string
    	fmt.Printf("首次声明map值是否为空:%v \n", mv == nil)
    	fmt.Printf("首次声明时map的值:%v \n", mv)
    	fmt.Printf("首次声明时map类型:%v \n", reflect.TypeOf(mv))
    	mv = make(map[string]string)
    	fmt.Printf("初始化后map的值:%v \n", mv)
    	fmt.Printf("初始化后map值是否为空:%v \n", mv == nil)
    	fmt.Printf("初始化后map类型:%v \n", reflect.TypeOf(mv))
    	mv["wife"] = "Ruby"
    	fmt.Printf("赋值后map的值:%v \n", mv)
    
    }
    
    

    输出结果

    首次声明map值是否为空:true
    首次声明时map的值:map[]
    首次声明时map类型:map[string]string
    初始化后map的值:map[]
    初始化后map值是否为空:false
    初始化后map类型:map[string]string
    赋值后map的值:map[wife:Ruby]

    rang map 是无序的

    package main
    
    import "fmt"
    
    func main() {
    	mv := make(map[int]string)
    	letter := []string{"a", "b", "c", "d", "e"}
    	for k, v := range letter {
    		mv[k] = v
    	}
    	for k, v := range mv {
    		fmt.Printf("key:%v, val:%v \n", k, v)
    	}
    }
    
    

    输出结果

    key:4, val:e
    key:0, val:a
    key:1, val:b
    key:2, val:c
    key:3, val:d

    有序输出map
    map详解

    展开全文
  • golangmap的一些注意事项

    千次阅读 2019-09-03 14:58:31
    map 类似其它语言中的哈希表或字典,以key-value形式存储数据 key必须是支持==或!=比较运算的类型,不可以是函数、map或slice Map通过key查找value比线性搜索快很多 Map使用make()创建,支持:=这种简写方式 ...

    map

    • 类似其它语言中的哈希表或字典,以key-value形式存储数据
    • key必须是支持==或!=比较运算的类型,不可以是函数、map或slice
    • Map通过key查找value比线性搜索快很多
    • Map使用make()创建,支持:=这种简写方式

    • make([keyType]valueType,cap),cap表示容量,可省略
    • 超出容量时会自动扩容,但尽量提供一个合理的初始值
    • 使用len()获取元素个数
    • 键值对不存在时自动添加,使用delete()删除某键值对
    • 使用for range对map和slice进行迭代

    map的声明与默认值

    // 声明
    var m map[string]string
    
    // bool 的零值是false
    var m map[int]bool 
    a, ok := m[1]
    fmt.Println(a, ok) // false  false
    
    // int 的零值是0
    var m map[int]int 
    a, ok := m[1]
    fmt.Println(a, ok) // 0  false
    

    map的声明的时候默认值是nil ,此时进行取值,返回的是对应类型的零值(不存在也是返回零值)

    // 先声明map
    var m1 map[string]string
    // 再使用make函数创建一个非nil的map,nil map不能赋值
    m1 = make(map[string]string)
    // 最后给已声明的map赋值
    m1["a"] = "aa"
    m1["b"] = "bb"
    
    // 直接创建
    m2 := make(map[string]string)
    // 然后赋值
    m2["a"] = "aa"
    m2["b"] = "bb"
    
    // 初始化 + 赋值一体化
    m3 := map[string]string{
        "a": "aa",
        "b": "bb",
    }
    
    // ==========================================
    // 查找键值是否存在
    if v, ok := m1["a"]; ok {
        fmt.Println(v)
    } else {
        fmt.Println("Key Not Found")
    }
    
    // 遍历map
    for k, v := range m1 {
        fmt.Println(k, v)
    }
    
    m := make(map[interface{} ]interface{})
    m[1] = 56
    m["str"] = "dfsdf"
    fmt.Println(m)
    1. map数据类型初始化:

      两种方式:map[string]string{}或make(map[string]string)

    2. 未初始化的map是nil:

      未初始化的map是nil,它与一个空map基本等价,只是nil的map不允许往里面添加值。(A nil map is equivalent to an empty map except that no elements may be added) 
      因此,map是nil时,取值是不会报错的(取不到而已),但增加值会报错。 
      其实,还有一个区别,delete一个nil map会panic,但是delete 空map是一个空操作(并不会panic)(这个区别在最新的Go tips中已经没有了,即:delete一个nil map也不会panic)

    3. 通过fmt打印map时,空map和nil map结果是一样的:

      通过fmt打印map时,空map和nil map结果是一样的,都为map[]。所以,这个时候别断定map是空还是nil,而应该通过map == nil来判断。 
      Request中的Form字段就是如此,在没有直接或间接调用ParseForm()时,Form其实是nil,但是,你如果println出来,却是map[],可能有些困惑。通过跟踪源码可以发现,Form根本没有初始化。而在FormValue()方法中会判断Form是否为nil,然后决定是否调用ParseForm()方法,当然,你也可以手动调用ParseForm()方法。

    var m1 map[string]int
    m1 = make(map[string]int)
    m2 := make(map[string]int)
    fmt.Println(m1,m2)
    m1["chen"] = 88888
    m2["chen"] = 88888
    fmt.Println(m1,m2)
    fmt.Println(reflect.DeepEqual(m1, m2))

    若只有var m1 map[string]int 无m1 = make(map[string]int),无法向map中添加数据

    var m1 map[string]int
    m1["chen"] = 88888
    fmt.Println(m1)
    

    出现panic     panic: assignment to entry in nil map

    map的初始化

    // 声明之后必须初始化,才能使用
    m = make(map[string]int)
    m = map[string]int{}
    
    // 声明并初始化 <= 注意这里是 := 不是 =
    m := make(map[string]int)
    m := map[string]int{1:1}
    

    向未初始化的map赋值引起 panic: assign to entry in nil map.

    注意:golang中的map,的 key 可以是很多种类型,比如 bool, 数字,string, 指针, channel , 还有 只包含前面几个类型的 interface types, structs, arrays,显然,slice, map 还有 function 是不可以了,因为这几个没法用 == 来判断。

    如果是非法的key类型,会报错:invalid map key type xxx

    几种类型的比较:

    arr1 := []int{1,2,3,4}
    arr2 := []int{1,2,3,4}

    切片不可以arr1 == arr2,会报错invalid operation: arr1 == arr2 (slice can only be compared to nil)

    切片只可以与nil比较,判断是否为nil,不可以直接用“==”比较,但可以借助于reflect.DeepEqual(arr1, arr2)比较,返回true或false,此外map也可以通过reflect.DeepEqual(m1, m2)比较

    结构体比较

    不同结构的结构体不可以比较,但同一类型的实例值是可以比较的。

    两个 struct完全相等, 意味着里面的所有变量的值都完全相等

    type Person struct {
          Name, Country string
    }
     
    hits := make(map[Person]int)

    判断key是否在map中

    if _, ok := map[key]; ok {
        //存在进行相应操作
    }
    

    map的新增 & 删除 & 更新 & 查询

    // 新增
    m["name"] = "wade"
    
    // 删除,key不存在则啥也不干
    delete(m, "name")
    
    // 更新
    m["name"] = "Tigerwolf"
    
    // 查询,key不存在返回value类型的零值
    i := m["name"] // 三种查询方式,
    i, ok := m["name"]
    _, ok := m["name"]
    

    map的遍历

    需要强调的是map本身是无序的在遍历的时候并不会按照你传入的顺序,进行传出。

    正常遍历:

    for k, v := range m {
        fmt.Println(k, v)
    }

     有序遍历(借助数组排序):

    import "sort"
    var tempArr []string
    // 把key单独抽取出来,放在数组中
    for k, _ := range m {
        tempArr = append(tempArr, k)
    }
    // 进行数组的排序
    sort.Strings(tempArr)
    // 遍历数组就是有序的了
    for _, k := range tempArr {
        fmt.Println(k, m[k])
    }

    map作为函数传参

    Golang中是没有引用传递的,均为值传递。这意味着传递的是数据的拷贝。
    那么map本身是引用类型,作为形参或返回参数的时候,传递的是地址的拷贝扩容时也不会改变这个地址。

    map的底层数据结构

    type hmap struct {
        count        int  //元素个数
        flags        uint8   
        B            uint8 //扩容常量
        noverflow    uint16 //溢出 bucket 个数
        hash0        uint32 //hash 种子
        buckets      unsafe.Pointer //bucket 数组指针
        oldbuckets   unsafe.Pointer //扩容时旧的buckets 数组指针
        nevacuate    uintptr  //扩容搬迁进度
        extra        *mapextra //记录溢出相关
    }
    
    type bmap struct {
        tophash        [bucketCnt]uint8  
        // Followed by bucketCnt keys 
        //and then bucketan Cnt values  
        // Followed by overflow pointer.
    }
    

    说明:每个map的底层结构是hmap,是有若干个机构为bmap的bucket组成的数组,每个bucket可以存放若干个元素(通常是8个),那么每个key会根据hash算法归到同一个bucket中,当一个bucket中的元素超过8个的时候,hmap会使用extra中的overflow来扩展存储key。

    来一个图,方便记忆:

    map的hash值计算

    那么具体key是分配到哪个bucket呢?也就是bmap中的tophash是如何计算?

    golang为每个类型定义了类型描述器_type,并实现了hashable类型的_type.alg.hash和_type.alg.equal

    type typeAlg struct {
        // function for hashing objects of this type
        // (ptr to object, seed) -> hash
        hash func(unsafe.Pointer, uintptr) uintptr
        // function for comparing objects of this type
        // (ptr to object A, ptr to object B) -> ==?
        equal func(unsafe.Pointer, unsafe.Pointer) bool

    具体实现文件:go/1.10.3/libexec/src/runtime/hashmap.go:

    // tophash calculates the tophash value for hash.
    func tophash(hash uintptr) uint8 {
        top := uint8(hash >> (sys.PtrSize*8 - 8))
        if top < minTopHash {
            top += minTopHash
        }
        return top
    }

    map的查找

    具体实现文件:go/1.10.3/libexec/src/runtime/hashmap.go:

    // mapaccess1 returns a pointer to h[key].  Never returns nil, instead
    // it will return a reference to the zero object for the value type if
    // the key is not in the map.
    // NOTE: The returned pointer may keep the whole map live, so don't
    // hold onto it for very long.
    func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
        ...
        // 并发访问检查
        if h.flags&hashWriting != 0 {
            throw("concurrent map read and map write")
        }
        
        // 计算key的hash值
        alg := t.key.alg
        hash := alg.hash(key, uintptr(h.hash0)) // alg.hash
    
        // hash值对m取余数得到对应的bucket
        m := uintptr(1)<<h.B - 1
        b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
    
        // 如果老的bucket还没有迁移,则在老的bucket里面找
        if c := h.oldbuckets; c != nil {
            if !h.sameSizeGrow() {
                m >>= 1
            }
            oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
            if !evacuated(oldb) {
                b = oldb
            }
        }
        
        // 计算tophash,取高8位
        top := uint8(hash >> (sys.PtrSize*8 - 8))
        
        for {
            for i := uintptr(0); i < bucketCnt; i++ {
                // 检查top值,如高8位不一样就找下一个
                if b.tophash[i] != top {
                    continue
                }
                
                // 取key的地址
                k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
                
                if alg.equal(key, k) { // alg.equal
                    // 取value得地址
                    v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
                }
            }
           
            // 如果当前bucket没有找到,则找bucket链的下一个bucket
            b = b.overflow(t)
            if b == nil {
                // 返回零值
                return unsafe.Pointer(&zeroVal[0])
            }
        }
    }

    map的更新/插入过程

    // Like mapaccess, but allocates a slot for the key if it is not present in the map.
    func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
        
        // 如果已经达到了load factor的最大值,那我们就继续开始扩容
        if !h.growing() && (overLoadFactor(int64(h.count), h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) {
            hashGrow(t, h)
            goto again
        }
    
        if inserti == nil {
            // burrent满了的话,需要申请一个新的
            newb := h.newoverflow(t, b)
            inserti = &newb.tophash[0]
            insertk = add(unsafe.Pointer(newb), dataOffset)
            val = add(insertk, bucketCnt*uintptr(t.keysize))
        }
    
        // 在插入的位置,存储键值
        if t.indirectkey {
            kmem := newobject(t.key)
            *(*unsafe.Pointer)(insertk) = kmem
            insertk = kmem
        }
        if t.indirectvalue {
            vmem := newobject(t.elem)
            *(*unsafe.Pointer)(val) = vmem
        }
        typedmemmove(t.key, insertk, key)
        *inserti = top
        h.count++
    }

    map的删除过程

    func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
        // 找key
       。。。
        // 若找到把对应的tophash里面的打上空的标记
        b.tophash[i] = empty
        h.count--
    }

    map的扩容机制

    map判断扩容的函数:

    // overLoadFactor reports whether count items placed in 1<<B buckets is over loadFactor.
    func overLoadFactor(count int, B uint8) bool {
        // 注意这里有一个loadFactorNum/loadFactorDen
        return count > bucketCnt && uintptr(count) > loadFactorNum*(bucketShift(B)/loadFactorDen)
    }
    
    func bucketShift(b uint8) uintptr {
        if sys.GoarchAmd64|sys.GoarchAmd64p32|sys.Goarch386 != 0 {
            b &= sys.PtrSize*8 - 1 // help x86 archs remove shift overflow checks
        }
        return uintptr(1) << b
    }

    每次map进行更新或者新增的时候,会先通过以上函数判断一下load factor。来决定是否扩容。

        扩容白话文:如果之前为2^n ,那么下一次扩容是2^(n+1),每次扩容都是之前的两倍。扩容后需要重新计算每一项在hash中的位置,新表为老的两倍,此时前文的oldbacket用上了,用来存同时存在的两个心就map,等数据迁移完毕就可以释放oldbacket了

    好处:均摊扩容时间,一定程度上缩短了扩容时间(是不是和gc的引用计数法有点像,都是均摊~)

    那么overLoadFactor函数中有一个常量6.5(loadFactorNum/loadFactorDen)来进行影响扩容时机。这个值的来源是测试取中的结果。

      loadFactor    %overflow  bytes/entry     hitprobe    missprobe
            4.00         2.13        20.77         3.00         4.00
            4.50         4.05        17.30         3.25         4.50
            5.00         6.85        14.77         3.50         5.00
            5.50        10.55        12.94         3.75         5.50
            6.00        15.27        11.67         4.00         6.00
            6.50        20.90        10.79         4.25         6.50
            7.00        27.14        10.15         4.50         7.00
            7.50        34.03         9.73         4.75         7.50
            8.00        41.10         9.40         5.00         8.00

    字段     说明
    %overflow     溢出率,平均一个bucket有多少个kv的时候会溢出
    bytes/entry     平均存一个kv需要额外存储多少字节的数据
    hitprobe     找到一个存在的key平均需要找几下
    missprobe     找到一个不存在的key平均需要找几下

    并发中的map

    安全性

    这里呢,实现一个小功能来证明下并发不是安全的
    并发起两个goroutine,分别对map进行数据的增加
     

    func main() {
        test := map[int]int {1:1}
        go func() {
            i := 0
            for i < 10000 {
                test[1]=1
                i++
            }
        }()
    
        go func() {
            i := 0
            for i < 10000 {
                test[1]=1
                i++
            }
        }()
    
        time.Sleep(2*time.Second)
        fmt.Println(test)
    }

    会发现有这样的报错:

    fatal error: concurrent map read and map write

    根本原因就是:并发的去读写map结构的数据了。
    处理方案 & 优缺点

    那解决方案就是加锁。上代码

    func main() {
        test := map[int]int {1:1}
        var s sync.RWMutex
        go func() {
            i := 0
            for i < 10000 {
                s.Lock()
                test[1]=1
                s.Unlock()
                i++
            }
        }()
    
        go func() {
            i := 0
            for i < 10000 {
                s.Lock()
                test[1]=1
                s.Unlock()
                i++
            }
        }()
    
        time.Sleep(2*time.Second)
        fmt.Println(test)
    }

        优点:实现简单粗暴,好理解
        缺点:锁的粒度为整个map,存在优化空间
        适用场景:all

    官方处理方案 & 优缺点

    想一想,在程序设计中,想增加运行的速度,那么必然要有另外的牺牲,很容易想到“空间换时间”的方案,现在来实战体验一把。

    func main() {
        test := sync.Map{}
        test.Store(1, 1)
        go func() {
            i := 0
            for i < 10000 {
                test.Store(1, 1)
                i++
            }
        }()
    
        go func() {
            i := 0
            for i < 10000 {
                test.Store(1, 1)
                i++
            }
        }()
    
        time.Sleep(time.Second)
        fmt.Println(test.Load(1))
    }

    运行完呢,会发现,其实是不会报错的。因为sync.Map里头已经实现了一套加锁的机制,让你更方便地使用map。

    sync.Map的原理介绍:sync.Map里头有两个map一个是专门用于读的read map,另一个是才是提供读写的dirty map;优先读read map,若不存在则加锁穿透读dirty map,同时记录一个未从read map读到的计数,当计数到达一定值,就将read map用dirty map进行覆盖。

        优点:是官方出的,是亲儿子;通过空间换时间的方式;读写分离;
        缺点:不适用于大量写的场景,这样会导致read map读不到数据而进一步加锁读取,同时dirty map也会一直晋升为read map,整体性能较差。
        适用场景:大量读,少量写

    额外的处理机制

    想一想,mysql加锁,是不是有表级锁、行级锁,前文的sync.RWMutex加锁方式相当于表级锁。

    而sync.Map其实也是相当于表级锁,只不过多读写分了两个map,本质还是一样的。

    既然这样,那就自然知道优化方向了:就是把锁的粒度尽可能降低来提高运行速度。

    思路:对一个大map进行hash,其内部是n个小map,根据key来来hash确定在具体的那个小map中,这样加锁的粒度就变成1/n了。
    网上找了下,真有大佬实现了:点这里https://github.com/orcaman/concurrent-map/blob/master/README-zh.md

    map的gc回收机制

    实战代码 && 处理机制

    我们知道呢,map在golang里头是只增不减的一种数组结构,他只会在删除的时候进行打标记说明该内存空间已经empty了,不会回收的。

    show my code,no bb:

    var intMap map[int]int
    
    func main() {
        printMemStats("初始化")
    
        // 添加1w个map值
        intMap = make(map[int]int, 10000)
        for i := 0; i < 10000; i++ {
            intMap[i] = i
        }
    
        // 手动进行gc操作
        runtime.GC()
        // 再次查看数据
        printMemStats("增加map数据后")
    
        log.Println("删除前数组长度:", len(intMap))
        for i := 0; i < 10000; i++ {
            delete(intMap, i)
        }
        log.Println("删除后数组长度:", len(intMap))
    
        // 再次进行手动GC回收
        runtime.GC()
        printMemStats("删除map数据后")
    
        // 设置为nil进行回收
        intMap = nil
        runtime.GC()
        printMemStats("设置为nil后")
    }
    
    func printMemStats(mag string) {
        var m runtime.MemStats
        runtime.ReadMemStats(&m)
        log.Printf("%v:分配的内存 = %vKB, GC的次数 = %v\n", mag, m.Alloc/1024, m.NumGC)
    }

    会输出:

    初始化:分配的内存 = 65KB, GC的次数 = 0
    增加map数据后:分配的内存 = 381KB, GC的次数 = 1
    删除前数组长度: 10000
    删除后数组长度: 0
    删除map数据后:分配的内存 = 381KB, GC的次数 = 2
    设置为nil后:分配的内存 = 68KB, GC的次数 = 3

    很明显可以看到delete是不会真正的把map释放的,所以要回收map还是需要设为nil
     

    展开全文
  • golang 获取map所有key的方式

    万次阅读 2019-06-28 16:24:31
    最佳方式:根据map的长度,新建一个数组,遍历map逐个压入 方法1: func getKeys1(m map[int]int) []int { // 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率较高 j := 0 keys := make([]...

    最佳方式:根据map的长度,新建一个数组,遍历map逐个压入

    方法1:

    func getKeys1(m map[int]int) []int {
    	// 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率较高
    	j := 0
    	keys := make([]int, len(m))
    	for k := range m {
    		keys[j] = k
    		j++
    	}
    	return keys
    }

    方法2:

    func getKeys2(m map[int]int) []int {
    	// 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率较高
    	keys := make([]int, 0, len(m))
    	for k := range m {
    		keys = append(keys, k)
    	}
    	return keys
    }

    其他方式:

    方法3:

    func getKeys3(m map[int]int) []int {
    	// 注意:由于数组默认长度为0,后面append时,需要重新申请内存和拷贝,所以效率较低
    	keys := []int{}
    	for k := range m {
    		keys = append(keys, k)
    	}
    	return keys
    }

    方法4:

    func getKeys4(m map[int]int) int {
    	// 注意:虽然此写法简洁,但MapKeys函数内部操作复杂,效率极低
    	keys := reflect.ValueOf(m).MapKeys()
    	return len(keys)
    }

    实验结果如图(可以看到方法1和方法2效率最高,内存操作也最少):

    完整代码如下:

    package test
    
    import (
    	"reflect"
    	"testing"
    )
    
    // 初始化map
    func initMap() map[int]int {
    	m := map[int]int{}
    	for i := 0; i < 10000; i++ {
    		m[i] = i
    	}
    	return m
    }
    
    func getKeys1(m map[int]int) []int {
    	// 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率较高
    	j := 0
    	keys := make([]int, len(m))
    	for k := range m {
    		keys[j] = k
    		j++
    	}
    	return keys
    }
    
    func getKeys2(m map[int]int) []int {
    	// 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率较高
    	keys := make([]int, 0, len(m))
    	for k := range m {
    		keys = append(keys, k)
    	}
    	return keys
    }
    
    // 初始化默认
    func getKeys3(m map[int]int) []int {
    	// 注意:由于数组默认长度为0,后面append时,需要重新申请内存和拷贝,所以效率较低
    	keys := []int{}
    	for k := range m {
    		keys = append(keys, k)
    	}
    	return keys
    }
    
    // 使用反射
    func getKeys4(m map[int]int) int {
    	// 注意:虽然此写法简洁,但MapKeys函数内部操作复杂,效率极低
    	keys := reflect.ValueOf(m).MapKeys()
    	return len(keys)
    }
    
    func BenchmarkMapkeys1(b *testing.B) {
    	// 初始化map
    	m := initMap()
    
    	b.ResetTimer()
    	for i := 0; i < b.N; i++ {
    		getKeys1(m)
    	}
    }
    func BenchmarkMapkeys2(b *testing.B) {
    	// 初始化map
    	m := initMap()
    
    	b.ResetTimer()
    	for i := 0; i < b.N; i++ {
    		getKeys2(m)
    	}
    }
    
    func BenchmarkMapkeys3(b *testing.B) {
    	// 初始化map
    	m := initMap()
    
    	b.ResetTimer()
    	for i := 0; i < b.N; i++ {
    		getKeys3(m)
    	}
    }
    
    func BenchmarkMapkeys4(b *testing.B) {
    	// 初始化map
    	m := initMap()
    
    	b.ResetTimer()
    	for i := 0; i < b.N; i++ {
    		getKeys4(m)
    	}
    }
    

     

    展开全文
  • golang map的遍历

    万次阅读 2017-10-04 15:26:04
    遍历keypackage main import ( "fmt" ) func main() { var mymap map[string]string mymap = map[string]string{"1a": "Very", "2b": "good", "3c": "day"} for one := range mymap {

    遍历key

    package main
    
    
    import (
            "fmt"
    )
    
    
    func main() {
            var mymap map[string]string
    
            mymap = map[string]string{"1a": "Very", "2b": "good", "3c": "day"}
    
            for one := range mymap {
                    fmt.Println(one)
            }
    
    }
    

    output:

    1a
    2b
    3c

    遍历value

    package main
    
    
    import (
            "fmt"
    )
    
    
    func main() {
            var mymap map[string]string
    
            mymap = map[string]string{"1a": "Very", "2b": "good", "3c": "day"}
    
            for _,value := range mymap {
                    fmt.Println(value)
            }
    
    }

    output:

    Very
    good
    day

    遍历key-value

    package main
    
    
    import (
            "fmt"
    )
    
    
    func main() {
            var mymap map[string]string
    
            mymap = map[string]string{"1a": "Very", "2b": "good", "3c": "day"}
    
            for key,value := range mymap {
                    fmt.Println(key,":",value)
            }
    
    }

    output:

    3c : day
    1a : Very
    2b : good

    展开全文
  • 由浅入深聊聊Golangmap

    万次阅读 2020-03-05 16:08:43
    今日听了大佬们对于map的讲解,结合自己之前的积累,专门来由浅入深的总结一下,希望可以与map之间做一个了断。 文章的深浅顺序是递进的,当你看完这篇文章,你也基本掌握了map的99%的知识点了,可以装逼和吹牛逼了...
  • Golang map实践以及实现原理

    千次阅读 2019-09-17 10:36:24
    Map实践以及实现原理实例 实例
  • golang-map分析

    千次阅读 2018-02-22 14:45:32
    转载自:https://juejin.im/entry/5a1e4bcd6fb9a045090942d8本文将主要...golang中的map是用hashmap作为底层实现的,在github的源码中相关的代码有两处:runtime/hashmap.go定义了map的基本结构和方法,runtime/h...
  • golang map 详解

    千次阅读 2017-12-28 15:15:00
    type PersonDB struct { Id string Name string ...//map是一堆键值对的未排序集合,在golang中是内置类型,可以直接使用,不像Java需要引入HashMap func main() { var personMap map[string]PersonDB
  • golang判断key是否在map

    万次阅读 2015-11-23 16:04:24
    判断方法示例代码 ...另外golang也没有提供item是否在array当中的判断方法,如果程序里面频繁用到了这种判断,可以将array转化为以array当中的成员为key的map再用上面的方法进行判断,这样会提高判断的效率.
  • golang map删除元素

    万次阅读 2018-09-08 09:37:17
    var pc map[string] string pc = make(map[string] string) pc["qingdao"] = "青岛" pc["jinan"] = "济南" pc["yantai"] = "烟台"
  • Golang 嵌套map赋值办法

    千次阅读 2014-07-02 09:55:32
    http://my.oschina.net/sol/blog/159060 m := map[string]map[string]string{} mm, ok := m["kkk"] if !ok { mm = make(map[string]string) m["kkk"] = mm } mm[k1k1k1] = "sssss
  • GoLang 遍历 map、slice、array方法 map1 := make(map[string]string) map1["a"] = "AAA" map1["b"] = "BBB" map1["c"] = "CCC" for k, v := range map1 { t.Log(k, v) } for _, v :
  • golang map转json

    万次阅读 2017-12-29 12:19:34
    ““ // map to jsonpackage mainimport ( ... “fmt”)func main() {s := []map[string]interface{}{}m1 := map[string]interface{}{"name": "John", "age": 10} m2 := map[string]interface{}{
  • Golangmap和未初始化map注意事项

    千次阅读 2019-03-29 15:45:29
    可以对未初始化的map进行取值,但取出来的东西是空: var m1 map[string]string fmt.Println(m1["1"]) 不能对未初始化的map进行赋值,这样将会抛出一个异常:panic: assignment to entry in nil map var m1 map...
  • package main ... demo := map[string]bool{ "a" : false, } fmt.Println(demo["a"]) _, ok := demo["a"] //判断a是否存在 fmt.Println(ok) //true _, ok2 := demo["b"] fmt.Println(...
  • golang中的map无序

    千次阅读 2020-09-01 21:19:39
    今天用for range遍历map,发现打印出来的map是无序的,网上搜了一下资料说:for range map 在开始处理循环逻辑的时候就做了随机播种。但用for range遍历切片,是有序的。
  • 按照之前我对map的理解,map中的数据应该是有序二叉树的存储顺序,正常的遍历也应该是有序的遍历和输出,但实际试了一下,却发现并非如此,网上查了下,发现从Go1开始,遍历的起始节点就是随机了,当然随机到什么...
  • golang_map的值拷贝函数实现

    千次阅读 2019-08-23 15:49:26
    func (p *Reporter) cloneTags(tags map[string]string) map[string]string { cloneTags := make(map[string]string) for k, v := range tags { cloneTags[k] = v } return cloneTags } 传入的是...
  • Golang map有序化

    千次阅读 2018-10-24 10:02:16
    要使得Map有序化,我们必须要对map的key进行排序,我们可以使用sort.Strings函数对字符串进行排序。 package main import ( "fmt" "sort" ) func main() { slice1 := map[string]int{ &...
  • golangmap声明及初始化

    万次阅读 2016-12-03 12:03:34
    map的声明 var m1 map[string]int map[key]value key必须支持==(避免使用浮点型)value不做规范 map的初始化 方式1 var m1 map[string]int=map[sting]int{"key":0} 方式2 m2:=make(map[string]int) 注意: map声明...
1 2 3 4 5 ... 20
收藏数 17,979
精华内容 7,191
关键字:

golang map