Go-映射类型详解(遍历、增删改查、判断相等、内存等)

简介: Go-映射类型详解(遍历、增删改查、判断相等、内存等)

介绍

  • 引用类型
  • Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索value。
  • key 类似于索引,指向数据的值,key必须可以使用==运算符来比较,不能重复。
  • Map 是使用 hash 表来实现的。
  • map自动扩容

声明

方式1

var map 变量名 map[key_type]value_type

代码

var m map[string]string

方式2

make函数

func make(Type, size IntegerType) Type

内建函数make分配并初始化一个类型为切片、映射、或通道的对象。其第一个实参为类型,而非值。make的返回类型与其参数相同,而非指向它的指针。其具体结果取决于具体的类型:


映射:初始分配的创建取决于size,但产生的映射长度为0。size可以省略,这种情况下就会分配一个小的起始大小。

map的键必须是可以通过操作符==来比较的数据类型。int、布尔、string、或包含前面的struct、数组等

声明时直接make

var 变量名 = make(map[key_type][value_type])

代码

var m1 = make(map[string]string,5)

初始化

key:value形式,添加到花括号中。

代码

m2 := map[string]string{"野王":"赵云"}

添加/修改

map[key] = value形式,没有会添加,有了会覆盖。

代码

1.  m1["上官"] = "言为心声"
2.  m1["婉儿"] = "字为心画"
3.  m2["野王"] = "老虎"
4.  m2["上单"] = "吕布"

删除

func delete(m map[Type]Type1, key Type)

内建函数delete按照指定的键将元素从映射中删除。若m为nil或无此元素,delete不进行操作。

delete(m1,"上官")

清空:重新make,没有其他语言类似clear的函数

查找

m[key]返回值和是否存在(bool类型)

  val,flag := m2["野王"]
  if flag{
    fmt.Println("野王:",val)
  }

内存

查看源码

src->runtime->map.go

// A header for a Go map.
type hmap struct {
  // Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
  // Make sure this stays in sync with the compiler's definition.
  count     int // # live cells == size of map.  Must be first (used by len() builtin)
  flags     uint8
  B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
  noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
  hash0     uint32 // hash seed
  buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
  oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
  nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)
  extra *mapextra // optional fields
}
// A bucket for a Go map.
type bmap struct {
  // tophash generally contains the top byte of the hash value
  // for each key in this bucket. If tophash[0] < minTopHash,
  // tophash[0] is a bucket evacuation state instead.
  tophash [bucketCnt]uint8
  // Followed by bucketCnt keys and then bucketCnt elems.
  // NOTE: packing all the keys together and then all the elems together makes the
  // code a bit more complicated than alternating key/elem/key/elem/... but it allows
  // us to eliminate padding which would be needed for, e.g., map[int64]int8.
  // Followed by an overflow pointer.
}

是哈希表实现,拉链法解决冲突。

遍历

for range

  for key,value := range m2{
    fmt.Println(key,value)
  }

注意:由于是无序的,go的设计者将遍历做了随机化处理,可就是说两次遍历的结果很可能不一样

排序

对key排序,然后遍历

  m2["野王2"] = "赵云"
  m2["野王3"] = "玛玛哈哈"
  m2["上单2"] = "马超"
  keys := []string{}
  for key,_ := range m2{
    keys = append(keys, key)
  }
  sort.Strings(keys)
  fmt.Println("上单和野王排行榜:")
  for _,key := range keys{
    fmt.Println(key,m2[key])
  }

注意:不是线程安全的,如果需要线程安全的,可以使用sync/Map,等到包的那一节会详细展开。

相等

和slice一样,map之间不能使用==直接比较,map可以和nil使用==比较,我们可以使用循环来判断。

  ok := func(m1,m2 map[string]string) bool{
    if len(m1) != len(m2){
      return false
    }
    for k,v := range m1{
      if v2,ok := m2[k]; !ok || v!=v2{
        return false
      }
    }
    return true
  } (m1,m2)
  fmt.Println("m1和m2相等?",ok)

全部代码

package main
import (
  "fmt"
  "sort"
)
func main() {
  //-------------声明---------------
  var m map[string]string
  //----------声明并分配空间------
  var m1 = make(map[string]string,5)
  m2 := map[string]string{"野王":"赵云"}
  //---------添加和修改---------------
  m1["上官"] = "言为心声"
  m1["婉儿"] = "字为心画"
  m2["野王"] = "老虎"
  m2["上单"] = "吕布"
  fmt.Println("m m1 m2:",m,m1,m2)
  //----------删除-------------------
  delete(m1,"上官")
  fmt.Println("m1:",m1)
  //------------查找-------------
  val,flag := m2["野王"]
  if flag{
    fmt.Println("野王:",val)
  }
  //------------遍历-------------
  for key,value := range m2{
    fmt.Println(key,value)
  }
    //------------排序------------
  m2["野王2"] = "赵云"
  m2["野王3"] = "玛玛哈哈"
  m2["上单2"] = "马超"
  keys := []string{}
  for key,_ := range m2{
    keys = append(keys, key)
  }
  sort.Strings(keys)
  fmt.Println("上单和野王排行榜:")
  for _,key := range keys{
    fmt.Println(key,m2[key])
  }
}

截图

2020062310470442.png

注意

  • key必须可以使用==比较,所以,数组是可以作为key的,但切片不行,类似于Python中的tuple和list
  • 向map存数据前需要make或初始化,仅使用var声明的是不行的,仅声明的话,那是nil

参考

更多Go相关内容:Go-Golang学习总结笔记

有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。

相关文章
|
4月前
|
弹性计算 定位技术 数据中心
阿里云服务器配置选择方法:付费类型、地域及CPU内存配置全解析
阿里云服务器怎么选?2025最新指南:就近选择地域,降低延迟;长期使用选包年包月,短期灵活选按量付费;企业选2核4G5M仅199元/年,个人选2核2G3M低至99元/年,高性价比爆款推荐,轻松上云。
409 11
|
9月前
|
存储 安全 Go
Map的遍历与判断键是否存在-《Go语言实战指南》
本文介绍了 Go 语言中对 `map` 的常见操作,包括遍历所有项和判断键是否存在。通过 `for range` 可以遍历 `map` 的键值对、仅键或仅值(需忽略键)。注意,`map` 遍历顺序是随机的。判断键是否存在时,使用双赋值语法 `value, ok := map[key]`,其中 `ok` 表示键是否存在。直接访问不存在的键会返回类型的零值,可能导致逻辑错误。掌握这些机制可更安全高效地处理键值对数据。
|
9月前
|
Go 开发者
Go语言内存共享与扩容机制 -《Go语言实战指南》
本文深入探讨了Go语言中切片的内存共享机制与自动扩容策略。切片作为动态数组的抽象,其底层结构包含指针、长度和容量。多个切片可能共享同一底层数组,修改一个切片可能影响其他切片。当切片容量不足时,`append`会触发扩容,新容量按指数增长以优化性能。为避免共享导致的副作用,可通过`copy`创建独立副本或在函数中使用只读方式处理。最后总结了最佳实践,帮助开发者高效使用切片,写出更优代码。
232 10
|
10月前
|
存储 算法 数据可视化
【二叉树遍历入门:从中序遍历到层序与右视图】【LeetCode 热题100】94:二叉树的中序遍历、102:二叉树的层序遍历、199:二叉树的右视图(详细解析)(Go语言版)
本文详细解析了二叉树的三种经典遍历方式:中序遍历(94题)、层序遍历(102题)和右视图(199题)。通过递归与迭代实现中序遍历,深入理解深度优先搜索(DFS);借助队列完成层序遍历和右视图,掌握广度优先搜索(BFS)。文章对比DFS与BFS的思维方式,总结不同遍历的应用场景,为后续构造树结构奠定基础。
513 10
|
11月前
|
Java 编译器 Go
go的内存逃逸分析
内存逃逸分析是Go编译器在编译期间根据变量的类型和作用域,确定变量分配在堆上还是栈上的过程。如果变量需要分配在堆上,则称作内存逃逸。Go语言有自动内存管理(GC),开发者无需手动释放内存,但编译器需准确分配内存以优化性能。常见的内存逃逸场景包括返回局部变量的指针、使用`interface{}`动态类型、栈空间不足和闭包等。内存逃逸会影响性能,因为操作堆比栈慢,且增加GC压力。合理使用内存逃逸分析工具(如`-gcflags=-m`)有助于编写高效代码。
239 2
|
存储 Go
go语言中映射
go语言中映射
206 11
go语言for遍历映射(map)
go语言for遍历映射(map)
469 12
|
Go 索引
go语言使用索引遍历
go语言使用索引遍历
185 9
go语言for 遍历字符串
go语言for 遍历字符串
216 8
|
存储 Go 索引
go语言使用for循环遍历
go语言使用for循环遍历
277 7

热门文章

最新文章