- 人工智能
- AI 技能
- 文档
- 开发工具
【免费下载链接】DocAgent
本篇技术指南以仓颉语言标准库std.collection中的哈希表实现HashMap<K, V>为核心,通过官方示例文件 sample_hashmap_get_add_contains.md 讲解其最基本的三个操作——添加键值对(add)、按键取值(get)与按键判断(contains)。读完本文,你将掌握HashMap的构造方式、Option返回值语义及其安全取值手段,并能直接上手编写可运行的键值对存取代码。
HashMap 是什么
HashMap<K, V>是Map<K, V>接口的哈希表实现,位于仓颉标准库的std.collection包中,定义见 HashMap_class.md。哈希表是一种常用的数据结构,其基本原理是把每个键映射为一个哈希值,再用该哈希值确定元素在底层数组中的存储位置,从而实现快速查找、插入和删除。由于哈希运算与数组下标访问的时间代价基本恒定,哈希表上这三类操作的时间复杂度通常是 O(1)。
需要特别注意的是:因为哈希表底层的数组大小是动态的(插入元素过多时会触发扩容),所以HashMap 不能保证元素的顺序不可变。这与 TreeMap(基于红黑树、按键有序)形成鲜明对比,在 collection_package_overview.md 中有明确说明。此外,std.collection提供的集合类型都不支持并发安全。
HashMap<K, V>的类声明对键类型有约束:K <: Hashable & Equatable<K>,即键必须可哈希且可判等,这是哈希表正确寻址的前提。类本身实现Map<K, V>接口,并扩展了Equatable<HashMap<K, V>>(支持==/!=)与ToString(支持toString())接口。
示例:get/add/contains 的基本用法
仓库中的官方示例 sample_hashmap_get_add_contains.md 完整演示了三个核心函数,代码如下:
import std.collection.* main() { var map: HashMap<String, Int64> = HashMap<String, Int64>() map.add("a", 99) // map : [("a", 99)] map.add("b", 100) // map : [("a", 99), ("b", 100)] var a = map.get("a") var bool = map.contains("a") print("a=${a.getOrThrow()} ") print("bool=${bool.toString()}") return 0 }运行结果:
a=99 bool=true这段代码虽短,却覆盖了HashMap最典型的使用流程:先构造空映射,再连续add两个键值对,随后用get取出指定键的值,用contains判断键是否存在。下面逐一拆解每个环节。
构造:HashMap<String, Int64>()
示例通过HashMap<String, Int64>()构造一个键为String、值为Int64的空哈希表。HashMap共提供 5 个构造函数(详见 collection_package_class.md):
| 构造函数 | 原型 | 说明 |
|---|---|---|
| 默认构造 | init() | 默认初始容量为 16 |
| 键值对数组 | init(elements: Array<(K, V)>) | 根据数组 size 设置容量,重复键按迭代器顺序后者覆盖前者 |
| 键值对集合 | init(elements: Collection<(K, V)>) | 根据集合 size 设置容量,重复键处理同上 |
| 指定容量 | init(capacity: Int64) | 容量小于 0 时抛IllegalArgumentException |
| 个数+规则函数 | init(size: Int64, initElement: (Int64) -> (K, V)) | 由规则函数生成键值对,size 小于 0 时抛IllegalArgumentException |
对于元素个数可预估的场景,推荐使用init(capacity)预分配容量,避免插入过程中反复扩容带来的性能开销。
add:将键值对放入 HashMap
public func add(key: K, value: V): Option<V>add用于把键值对放入HashMap。其关键语义是覆盖策略:对于映射中已有的键,该键对应的值将被新值替换,同时返回旧值;对于新键,则直接添加,返回Option<V>.None。返回值用Option封装,正好让调用方区分"本次是新增还是覆盖"。
示例中两次调用:
map.add("a", 99) // map : [("a", 99)] map.add("b", 100) // map : [("a", 99), ("b", 100)]执行后映射包含两个键值对。由于Map不允许重复键,每个键最多映射到一个值(见 Map_interface.md),因此若再次map.add("a", 200),"a"的值会被更新为 200,且返回Some(99)。
除单个键值对形式外,add还有一个批量重载add(all!: Collection<(K, V)>): Unit,可按集合迭代器顺序批量放入,同样遵循"已有键被新值替换"的规则,相关完整示例见 sample_hashmap_add_remove_clear.md。
运算符糖:map[key] = value
HashMap对add做了运算符重载:public operator func [](key: K, value!: V): Unit。当键存在时新值覆盖旧值,键不存在时添加键值对。因此map["a"] = 99与map.add("a", 99)效果一致,日常编码中可以按习惯选用。
get:按键取值的正确姿势
public func get(key: K): ?Vget返回指定键映射到的值,返回值类型为Option<V>(语法上写作?V):如果映射中存在该键,返回Some(value);如果不存在,返回Option<V>.None。这一设计避免了"取不存在的键时抛异常或返回空指针"的尴尬,把"可能没有值"这一信息显式地编码进类型系统。
示例中:
var a = map.get("a") print("a=${a.getOrThrow()} ")map.get("a")得到Option<Int64>,随后调用a.getOrThrow()取出原始Int64值。getOrThrow是Option提供的安全取值方法,定义在 core_package_enums.md:
getOrThrow(): T:当实例为Some<T>时返回其中值;若为None则抛出NoneValueException;getOrThrow(exception: () -> Exception): T:当实例为None时,执行传入的异常函数并抛出其返回的异常,适合在键缺失时需要自定义错误信息(如"配置项不存在")的场景。
因此get+getOrThrow的组合适合"键必然存在"的业务假设;如果键可能缺失,更稳妥的做法是先contains判断,或利用Option的match分支分别处理Some与None(HashMap的迭代遍历即采用该模式,参见 sample_hashmap_add_remove_clear.md 中的批量添加示例)。
get同样有运算符重载:public operator func [](key: K): V,即map["a"]直接返回键对应的值。注意该重载在键不存在时会抛NoneValueException(见 collection_package_class.md),所以[]取值的健壮性不如get+ 判空,使用前需自行保证键存在。
contains:判断键是否存在
public func contains(key: K): Boolcontains用于判断映射中是否存在指定键的映射,存在返回true,否则返回false。示例中:
var bool = map.contains("a") print("bool=${bool.toString()}")因为此前已add("a", 99),所以输出bool=true。contains是典型的"先判断再取"组合的搭档:在键可能缺失的场景下,先contains确认,再安全地取值或走其他逻辑分支。
contains还有一个批量重载contains(all!: Collection<K>): Bool,用于判断是否包含集合中所有键的映射,全部包含才返回true。
一个完整的增查删清演示
为加深对HashMap语义的理解,仓库还提供了配套示例 sample_hashmap_add_remove_clear.md,演示批量添加、删除与清空:
import std.collection.* main() { var map: HashMap<String, Int64> = HashMap<String, Int64>() var arr: Array<(String, Int64)> = [("d", 11), ("e", 12)] map.add("a", 13) print("a=${map.get("a").getOrThrow()} ") map.add(all: arr) // map : [("d", 11), ("e", 12)] var d = map.get("d") print("d=${d.getOrThrow()} ") map.remove("d") // map : [("e", 12)] var bool = map.contains("d") print("bool=${bool.toString()} ") map.clear() // map: [] var bool1 = map.contains("e") print("bool1=${bool1.toString()}") return 0 }运行结果:
a=13 d=11 bool=false bool1=false其中remove("d")删除指定键的映射并返回被删值(键不存在时返回None),clear()清空所有键值对。可以看到,删除与清空之后contains的判定随之变为false,三个函数配合即可完成映射的完整生命周期管理。
更多成员函数速览
除add/get/contains外,HashMap还提供一系列常用成员(完整 API 见 HashMap_class.md 与 collection_package_class.md):
| 函数 | 原型 | 说明 |
|---|---|---|
size/capacity | prop | 分别返回键值对个数与容量 |
addIfAbsent | (key: K, value: V): ?V | 键不存在才添加,否则不做修改并返回旧值 |
remove | (key: K): Option<V> | 删除指定键的映射,返回被删值或None |
removeIf | (predicate: (K, V) -> Bool): Unit | 遍历删除满足条件的键值对,predicate 内修改映射会抛ConcurrentModificationException |
replace | (key: K, value: V): ?V | 键已存在则更新值并返回旧值,否则不做修改 |
reserve | (additional: Int64): Unit | 扩容,剩余容量不足时按容量 1.5 倍规则扩容 |
keys/values | () | 返回所有键/值的容器视图 |
iterator | () | 返回HashMapIterator<K, V>用于遍历 |
entryView | (key: K): MapEntryView<K, V> | 获取指定键的引用视图 |
clone/toArray/isEmpty | () | 克隆、转数组、判空 |
小结
HashMap是仓颉标准库std.collection中面向"键值映射 + 快速查找"场景的首选容器:用add(或map[k] = v)写入,用get加getOrThrow(或map[k])读取,用contains判存。其Option化的返回值让缺失键成为可显式处理的常态分支,而非运行时异常。掌握这三个基本函数后,再结合批量add、remove、clear与迭代遍历,即可应对大多数映射类业务需求。相关示例与 API 文档均可从 std/collection 目录下继续查阅。
- 人工智能
- AI 技能
- 文档
- 开发工具
【免费下载链接】DocAgent
相关推荐
仓颉标准库 HashMap 键值操作实战:get/add/contains 用法与哈希表源码原理
仓颉标准库 HashMap 键值操作实战:get/add/contains 用法与哈希表源码原理 本文以仓颉(Cangjie)标准库 std.collectio
编程语言语言运行时标准库垃圾回收并发编程仓颉编程语言 HashMap 入门实战:get/add/contains 函数的使用与原理解析
仓颉编程语言 HashMap 入门实战:get/add/contains 函数的使用与原理解析 仓颉标准库 std.collection 包中的 HashMap
文档知识库教程OpenHarmony仓颉标准库 std.collection 实战:HashMap 的 add / remove / clear 增删改清操作详解
仓颉标准库 std.collection 实战:HashMap 的 add / remove / clear 增删改清操作详解 导读 本文以 sample_ha
人工智能AI 技能文档开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考