当前位置: 首页 > news >正文

Go语言容器之map、list和nil

一、map

  • map和C++中map一样,里面存放的是key-value键值对
  • 在Go中map是引用类型,声明语法:var map变量名 map[key的类型]value的类型
    package mainimport "fmt"func main() {var mp map[string]intmpls := map[string]int{"one":1, "two":2, "three":3}mpmk := make(map[string]int)mp = mplsmpmk["语文"] = 1mpmk["数学"] = 2mpmk["英语"] = 4mp["four"] = 4mp["five"] = 5fmt.Println("mp[one]", mp["one"])fmt.Println("mp[ten]", mp["ten"])fmt.Println("mp", mp)fmt.Println("mpmk[语文]", mpmk["语文"])fmt.Println(mpmk)
    }
    
    结果:
    在这里插入图片描述

1.map的容量

  • 和数组不一样,map可以根据新增的key-value进行动态的增加删除,所以不存在长度、最大限制;但是可以选择标明map的初始容量capacity,格式如下:
    make(map[key类型]value类型, cap)

2.map的遍历

  • 遍历map可以用for循环语句和range关键字进行遍历
    package mainimport "fmt"func main() {mpls := map[string]int{"one":1, "two":2, "three":3, "four":4, "five":5, "six":6, "seven":7, "eight":8, "nine":9, "ten":10}//遍历mapfor key, value := range mpls{fmt.Printf("key:%s",key)fmt.Printf(": value:%d\n", value)fmt.Println("value:", mpls[key])}fmt.Println("只遍历key:")//只遍历keyfor key, _ := range mpls{fmt.Printf("key:%s ", key)}fmt.Println("\n只遍历value:")//只遍历valuefor _, value := range mpls{fmt.Printf("value:%d ", value)}
    }
    
    结果:
    在这里插入图片描述

3.map中元素的删除

  • delete(map变量名, key对应的键)
    package mainimport "fmt"func main() {mpls := map[string]int{"one":1, "two":2, "three":3, "four":4, "five":5, "six":6, "seven":7, "eight":8, "nine":9, "ten":10}//遍历mapfor key, value := range mpls{fmt.Printf(" key: %s, value: %d||",key, value)}delete(mpls, "five")delete(mpls,"nine")delete(mpls,"three")fmt.Println("\n删除后:")fmt.Println(mpls)
    }
    
    结果:在这里插入图片描述

4.并发map(sync.Map)

  • Go语言中,map在并发情况下,只读是线程安全的,但是同时读写线程是不安全的
  • 需要并发读写的时候,一般是用加锁的方式。go中有一个效率高的并发安全的map,即snyc.Map。
  • sync.Map有以下特征:
    (1)无须初始化,直接声明即可
    (2)sync.Map和map不一样,不可以用map的方式对其进行操作。而是有自己特有的方式,Store表示存储,Load表示获取,Delete表示删除
    (3)使用Range配合一个回调函数进行遍历错做,通过回调函数返回内部遍历出来的值,Range参数中回调函数的返回值在需要继续迭代遍历时,返回true,终止遍历时返回false
  • 举例:
    package mainimport ("fmt""sync"
    )func main() {var snmp sync.Map//存储数据snmp.Store("语文", 100)snmp.Store("数学", 130)snmp.Store("英语", 120)snmp.Store("生物", 90)snmp.Store("物理", 30)//查看数据fmt.Println(snmp.Load("生物"))fmt.Println(snmp.Load("数学"))//删除数据snmp.Delete("生物")//遍历snmp.Range(func(k, v interface{})bool{fmt.Println("iterate:", k, v)return true})
    }
    
    结果:
    在这里插入图片描述

二、list

  • 在Go中,列表list内部的实现原理是双链表,能够高效地进行任意位置元素的插入和删除操作

1.列表的初始化

  • 方式一:通过container/list包中的New()函数来进行初始化。变量名 := list.New()
  • 方式二:通过var关键字声明初始化list。var 变量名 list.List

2.列表的插入、删除

  • 向列表中插入元素,因为是双链表,可以从队尾、队首两头直接插。PushFront向队首前方插入元素,PushBack向队尾后方插入元素,InsertAfter在队列中某元素之后插入一个元素,InsertBefore在队列某元素之前插入一个元素
  • Remove移除某个元素
package mainimport ("container/list""fmt"
)func main() {ls := list.New()ls.PushFront("d")//队首添加dele2 := ls.PushBack("e")//队尾添加e。且存放e元素的句柄。队列:d->eele1 := ls.PushFront("c")//队首添加c。且存放c元素的句柄。队列:c->d->els.PushBack("g")//队尾添加f。队列:c->d->e->gls.PushFront("a")//队首添加a。队列:a->c->d->e->g//遍历队列:for i := ls.Front(); i != nil; i = i.Next(){fmt.Printf(" %v -> ", i.Value)}fmt.Println()ls.InsertBefore("b", ele1)//在c元素前面添加b。队列:a->b->c->d->e->gls.InsertAfter("f", ele2)//在e元素后面添加f。队列:a->b->c->d->e->f->gele3 := ls.InsertAfter("i", ele2)//在e元素后面添加i。队列:a->b->c->d->e->i->f->g//遍历队列:for i := ls.Front(); i != nil; i = i.Next(){fmt.Printf(" %v -> ", i.Value)}ls.Remove(ele3)//删除元素ifmt.Println()//遍历队列:for i := ls.Front(); i != nil; i = i.Next(){fmt.Printf(" %v -> ", i.Value)}
}

结果:
在这里插入图片描述

三、零值、空值nil

  • 在Go语言中,布尔类型的零值(初始化值)为false,数值类型的零值为0,字符串类型的零值为空字符串"",而指针、切片、映射、通道和接口类型的零值都是nil空值
  • Go中,nil是一个预定义好的标识符。

1.nil的特性

(1)nil是不能比较的,无论nil的类型是否相同也都不能进行比较,会编译报错

package mainimport "fmt"func main() {fmt.Println(nil == nil)
}

结果:在这里插入图片描述(2)nil不是关键字或者保留字
(3)nil没有默认的类型
(4)不同类型的nil的指针是一样的

package mainimport ("fmt"
)func main() {var arr[]intvar mp map[int]intvar num intfmt.Printf("%p\n", arr)fmt.Printf("%p\n", mp)fmt.Printf("%p\n", num)
}

结果:
在这里插入图片描述
(5)nil是指针、切片、map、channel、接口、函数的零值

package mainimport ("fmt"
)func main() {var ptr *stringvar slce []intvar arr[]intvar mp map[int]intvar cha chan intvar fn func()var ins interface{}fmt.Printf("%#v\n", ptr)fmt.Printf("%#v\n", slce)fmt.Printf("%#v\n", arr)fmt.Printf("%#v\n", mp)fmt.Printf("%#v\n", cha)fmt.Printf("%#v\n", fn)fmt.Printf("%#v\n", ins)
}

结果:
在这里插入图片描述
(6)不同类型的nil值占用的内存大小不一样,按照类型大小

package mainimport ("fmt""unsafe"
)func main() {var ptr *stringvar slce []intvar arr[]intvar mp map[int]intvar cha chan intvar fn func()var ins interface{}fmt.Println(unsafe.Sizeof(ptr))fmt.Println(unsafe.Sizeof(slce))fmt.Println(unsafe.Sizeof(arr))fmt.Println(unsafe.Sizeof(mp))fmt.Println(unsafe.Sizeof(cha))fmt.Println(unsafe.Sizeof(fn))fmt.Println(unsafe.Sizeof(ins))
}

结果:
在这里插入图片描述

四、make和new关键字的区别

  • 两个内置函数可以用来在堆上分配内存
  • make只能用来分配和初始化slice、map、chan的类型的数据,而new可以分配任意类型的数据
  • make分配数据内存返回的是引用,即Type,而new返回一个指向接收参数类型的指针,即*Type。(make 关键字的主要作用是创建 slice、map 和 Channel 等内置的数据结构,而 new 的主要作用是为类型申请一片内存空间,并返回指向这片内存的指针。
  • 接收参数个数不一样:make() 只接收一个参数,而 new() 可以接收多个参数
  • make分配的空间后,会进行初始化。而new分配的空间会清零
http://www.lryc.cn/news/37152.html

相关文章:

  • 软件测试的案例分析 - 闰年1
  • 【强化学习】强化学习数学基础:值函数近似
  • JVM系列——Java与线程,介绍线程原理和操作系统的关系
  • C++打开文件夹对话框之BROWSEINFO
  • Nuxt项目配置、目录结构说明-实战教程基础-Day02
  • 单链表的头插,尾插,头删,尾删等操作
  • Qt扫盲-QProcess理论总结
  • JAVA进阶 —— Steam流
  • Ubuntu Protobuf 安装(测试有效)
  • 驱动程序开发:FTP服务器和OpenSSH的移植与搭建、以及一些笔记
  • 优化改进YOLOv5算法之添加GIoU、DIoU、CIoU、EIoU、Wise-IoU模块(超详细)
  • windows电脑pc如何使用svn获取文档和代码
  • ROS1学习笔记:tf坐标系广播与监听的编程实现(ubuntu20.04)
  • ​力扣解法汇总1590. 使数组和能被 P 整除
  • Spring源码阅读(基础)
  • 服务搭建篇(九) 使用GitLab+Jenkins搭建CI\CD执行环境 (上) 基础环境搭建
  • CDC 长沙站丨云原生技术研讨会:数字兴链,云化未来!
  • A.特定领域知识图谱知识推理方案:知识图谱推理算法综述[二](DTransE/PairRE:基于表示学习的知识图谱链接预测算法)
  • 香港酒店模拟分析项目报告--使用tableau、python、matlab
  • 第18天-商城业务(商品检索服务,基于Elastic Search完成商品检索)
  • 5.2 对射式红外传感器旋转编码器计次
  • 【数据库概论】第九章 关系查询处理和查询优化
  • (WIP) my cloud test bed (by quqi99)
  • git | git 2023 详细版
  • camunda流程引擎基本使用(笔记)
  • JS之数据结构与算法
  • CnOpenData·A股上市企业数字化转型指数数据
  • VMware16pro虚拟机安装全过程
  • 阿里云第六代云服务器最新价格表(计算型c6、通用型g6和内存型r6)
  • 微小目标识别研究(2)——基于K近邻的白酒杂质检测算法实现