Go语言map
map 是一种特殊的数据结构:一种元素对(pair)的无序集合,pair 的一个元素是 key,对应的另一个元素是 value,所以这个结构也称为关联数组或字典。这是一种快速寻找值的理想结构:给定 key,对应的value 可以迅速定位。 Map是给予散列表来实现,就是我们常说的Hash表,所以我们每次迭代Map的时候,打印的Key和Value是无序的,每次迭代的都不一样,即使我们按照一定的顺序存在也不行。 Map的散列表包含一组桶,每次存储和查找键值对的时候,都要先选择一个桶。如何选择桶呢?就是把指定的键传给散列函数,就可以索引到相应的桶了,进而找到对应的键值。 这种方式的好处在于,存储的数据越多,索引分布越均匀,所以我们访问键值对的速度也就越快,当然存储的细节还有很多,大家可以参考Hash相关的知识,这里我们只要记住Map存储的是无序的键值对集合。 map 是引用类型,可以使用如下声明: var variableName map[keyType]valueType
在声明的时候不需要知道 map 的长度,map 是可以动态增长的。 未初始化的 map 的值是 nil。 key 可以是任意可以用 == 或者 != 操作符比较的类型,比如 string、int、float。所以数组、切片和结构体不能作为 key,但是指针和接口类型可以。如果要用结构体作为 key 可以提供 Key() 和 Hash() 方法,这样可以通过结构体的域计算出唯一的数字或者字符串的 key。 value 可以是任意类型的;通过使用空接口类型,我们可以存储任意值,但是使用这种类型作为值时需要先做一次类型断言。 map 传递给函数的代价很小: 在 32 位机器上占 4 个字节,64 位机器上占 8 个字节,无论实际上存储了多少数据。通过 key 在 map 中寻找值是很快的,比线性查找快得多,但是仍然比从数组和切片的索引中直接读取要慢 100 倍;所以如果你很在乎性能的话还是建议用切片来解决问题。 示例: var map1 map[string]int Map的创建有 map 是引用类型的: 内存用 make 方法来分配。 dict := make(map[string]int) 示例中创建了一个键类型为 dict := make(map[string]int) dict["itbsl"] = 25 存储了一个Key为itbsl的,Value为25的键值对数据。 此外还有一种使用map字面量的方式创建和初始化map,对于上面的例子,我们可以同等实现。 dict := map[string]int{"itbsl": 25} 使用一个大括号进行初始化,键值对通过 dict := map[string]int{"itbsl":25,"kevin": 50} 当然我们可以不指定任何键值对,也就是一个空map。 dict := map[string]int{} 不管怎么样,使用map的字面量创建一定要带上大括号。如果我们要创建一个 var dict map[string]int 这样就好了,但是这样我们是不能操作存储键值对的,必须要初始化后才可以,比如使用 var dict map[string]int dict = make(map[string]int) dict["itbsl"] = 25 fmt.Println(dict) Map的使用很简单,和数组切片差不多,数组切片是使用索引,Map是通过键。 dict := make(map[string]int) dict["itbsl"] = 25 以上示例,如果键 获取一个Map键的值也很简单,和存储差不多,还是给予上面的例子。 age := dict["itbsl"] 在Go Map中,如果我们获取一个不存在的键的值,也是可以的,返回的是值类型的零值,这样就会导致我们不知道是真的存在一个为零值的键值对呢,还是说这个键值对就不存在。对此,Map为我们提供了检测一个键值对是否存在的方法。 age,exists := dict["itbsl"] 看这个例子,和获取键的值没有太大区别,只是多了一个返回值。第一个返回值是键的值;第二个返回值标记这个键是否存在,这是一个 如果我们想删除一个Map中的键值对,可以使用Go内置的 delete(dict,"itbsl")
想要遍历Map的话,可以使用 dict := map[string]int{"itbsl": 25} for key,value := range dict { fmt.Println(key,value) } 这里的 func main() { dict := map[string]int{"kevin": 40,"itbsl": 25} var names []string for name := range dict { names = append(names,name) } sort.Strings(names) //排序 for _,key := range names { fmt.Println(key,dict[key]) } } 这个例子里有个技巧, 和数组不同,map 可以根据新增的 key-value 对动态的伸缩,因此它不存在固定长度或者最大限制。但是你也可以选择标明 map 的初始容量 map2 := make(map[string]float,100) 当 map 增长到容量上限的时候,如果再增加新的 key-value 对,map 的大小会自动加 1。所以出于性能的考虑,对于大的 map 或者会快速扩张的 map,即使只是大概知道容量,也最好先标明。 map 默认是无序的,不管是按照 key 还是按照 value 默认都不排序。 如果你想为 map 排序,需要将 key(或者 value)拷贝到一个切片,再对切片排序,然后可以使用切片的 for-range 方法打印出所有的 key 和 value。 函数间传递Map是不会拷贝一个该Map的副本的,也就是说如果一个Map传递给一个函数,该函数对这个Map做了修改,那么这个Map的所有引用,都会感知到这个修改。 func main() { dict := map[string]int{"kevin": 40,"itbsl": 25} modify(dict) fmt.Println(dict["kevin"]) fmt.Printf("main函数dict的地址为: %pn",dict) } 输出结果为: modify函数dict的地址为: 0xc000076120 10 main函数dict的地址为: 0xc000076120 上面这个例子输出的结果是 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |