容器——映射(Map)和列表(ist)

5 篇文章 0 订阅

容器

3.3 映射(map)——建立事物关联的容器

Go 语言提供的映射关系容器为 map。map 使用散列表( hash )实现。

3.3.1 添加关联到map并访问关联和数据

Go语言中map的定义是这样的:

map[keyType]ValueType

  • KeyType为键类型
  • ValueType是键对应的值类型

一个map里, 符合KeyType和ValueType的映射总是成对出现。

下面的代码展示了map的基本使用环境。

scene := make(map[string]int)

scene["route"] = 66
fmt.Println(scene["route"])	//输出66

v := scene["route2"]
fmt.Println(v)			//输出0

某些情况下 需要明确知道查询中某个键是否在 map 中存在 ,可以使用一种特殊的写法来实现,看下面的代码:

v , ok := scene [” route ” ]

在默认获取键值的基础上,多取了一个变量 ok 可以判断键 route 是否存在于 map 中

还有一种在声明时填充内容的方式,代码如下

m := map[string]string{

    "W": "forward", 

    "A": "left", 

    "D": "right", 

    "S": "backward",
}

例子中并没有使用 make 而是使用大括号进行内容定义,就像 JSON 格式一样,冒号的左边是 key ,右边是值,键值对之间使用逗号分隔。

3.2.2 遍历map的"键值对"

map的遍历过程使用for range 循环完成,代码如下:

scene := make(map[string]int)

scene["route"] = 66
scene["route2"] = 4
scene["route3"] = 666

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

//如只遍历值,将不需要的键改为匿名遍历形式,
//只遍历键时,使用下面的形式:
for k := range scene {
    fmt.Println(k)
}

注意: 遍历输出的元素顺序与填充顺序无关,不能期望map在遍历时返回某种期望顺序的结果。如果需要特定排序的遍历结果,正确的做法时排序

3.3.3 使用delete()函数从map中删除键值对

delete()函数的格式如下:

delete(map, 键)

示例如下:

scene := make(map[string]int)

scene["route"] = 66
scene["route2"] = 4
scene["route3"] = 666

delete(scene, "route2")

for k, v := range scene {
	fmt.Println(k, v)
}
//代码输出如下:
//route 66
//route3 666

3.3.4 清空map中的所有元素

清空 map的唯一办法就是重新 make 一个新的 map 。不用担心垃圾回收的效率,Go 语言中的并行垃圾回收效率比写一个清空函数高效多了。

3.3.5 并发环境中使用的map—sync.Map

Go语言中的map在并发情况下,只读是线程安全的,同时读写线程不安全。

需要并发读写时,一般的方法是加锁,但这样的性能并不高。Go语言在1.9版本中提供了一种效率较高的并发安全sync.Map。sync.Map和map不同,不是以语言原生形态提供,而是在sync包下的特殊结构。

sync.Map有以下特性:

  • 无需初始化,直接声明即可
  • 不能使用map的方式进行取值和设置操作,而是使用方法调用,Store表示存储,Load表示获取,Delete表示删除
  • 使用Range配合一个回调函数进行遍历操作,通过回调返回内部遍历的值。Range参数中的回调函数返回值功能是:需要继续迭代遍历时,返回true; 终止迭代遍历时,返回false。
package main

import (
	"fmt"
	"sync"
)

func main() {
	var scene sync.Map

	//将键值对保存到sync.Map中
	scene.Store("greece", 96)
	scene.Store("london", 100)
	scene.Store("egypt", 200)

	//从sync.Map中根据键提取值
	fmt.Println(scene.Load("london"))

	//根据键删除对应的键值对
	scene.Delete("london")

	//遍历所有sync.Map中的键值对
	scene.Range(func(k, v interface{}) bool {
		fmt.Println("iterator: ", k, v)
		return true
	})
}

sync.Map 没有提供获取 map 量的方法,替代方法是获取时遍历自行计算数量。 sync.Map为了保证并发安全有一些性能损失,因此在非并发情况下,使用 map 相比使用 sync.Map会有更好的性能

3.4 列表(list)

列表是一种非连续存储的容器,由一个节点组成,节点通过一些变量记录彼此之间的关系。列表有多种实现方法,如单链表、双链表等。

Go 语言中 将列表使用 container/list 包来实现,内部的实现原理是双链表。列表能够高效地进行任意位置的元素插入和删除操作

3.4.1 初始列表

list的初始化有两种方法:New和声明。两种方法的初始化效果是一致的。

  1. New方法初始化list

    变量名 := list.New()

  2. 声明初始化list

    var 变量名 list.List

3.4.2 在列表中插入元素

双链表支持从队列前方或后方插入元素,分别对应的方法是 PushFront和PushBack。

提示: 这两个方法都会返回一个*list.Element 结构。如果在以后的使用中需要删除插入的元素,则只能通过***list. Element 配合 Remove()方法进行删除, 可以让删除更加效率化**。

代码示例如下:

l := list.New()

l.PushBack("76")
l.PushFront("first")

列表插入元素的方法如下表:

方法功能
InsertAfter(v interface{}, mark *list.Element) *Element在mark点之后插入元素,mark点由其他插入函数提供
InsertBefore(v interface{}, mark *list.Element) *Element在mark点之前插入元素,mark点由其他插入函数提供
PushBackList(other *List)添加other列表元素到尾部
PushFrontList(other *List)添加other列表元素到头部

3.4.3 从列表中删除元素

列表的插入函数的返回值会提供一个*list.Element结构,这个结构记录这列表元素的值和其他节点之间的关联关系。从列表中删除元素时,需要用到这个结构进行快速删除。

package main

import "container/list"

func main() {
	l := list.New()

	l.PushBack("container")
	l.PushFront(76)

	ele := l.PushBack("name")     //尾部添加元素后保存句柄
	l.InsertBefore("before", ele) //在name之前添加before
	l.InsertAfter("after", ele)   //在name之后添加after
	l.Remove(ele)	//删除元素
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值