在项目开发过程中遇到很奇怪的事情,使用HashMap的时候,可以存入的数据,但是在其他地方查询或者获取数据的时候一直找不到,通过Debug排查也是发现数据存在,但是拿不到...
但是通过自己循环遍历是能拿到的
private getItemValueFromMap(bookId: string): NovelReaderSpeedRecord | undefined { let record: NovelReaderSpeedRecord | undefined this.records.forEach((value: NovelReaderSpeedRecord, key: string) => { if (key == bookId) { record = value return } }) // record = this.records.get(bookId) return record }
所以问题可能就在HashMap|Map判断字符的逻辑上了,这跟Android里面的HashMap不太一样啊,那这不就是系统的bug吗?所以继续研究看看。
你用的“看起来一样”的字符串,其实不是“同一个字符串值”
在 ArkTS 的 Map 中,string 的比较比你想象的要「严格」。
❌ 场景 1:key 不是「原始 string」,而是 String 对象
key 不是「原始 string」,而是 String 对象
const map = new Map<string, string>();const key1 = 'params';const key2 = new String('params') as unknown as string;map.set(key1, 'value');map.get(key2); // ❌ undefined(鸿蒙里常见)
原因
Map 使用SameValueZero
String 对象 ≠ primitive string
ArkTS 对这点比浏览器更“严格暴露”,Map 判断 key 是否相等,用的是「SameValueZero」
primitive string 和 String 对象,永远不相等
ArkTS 中这个差异比浏览器更容易暴露出来
你看到的“看起来一样”的 key,其实是什么?
'params'new String('params')
打印出来都是:params
但实际上:
| | |
|---|
'params' | string | |
new String('params') | object | |
在 TS / JS 中验证一下
const a = 'params';const b = new String('params');console.log(typeof a); // stringconsole.log(typeof b); // objectconsole.log(a === b); // false
Map 底层是如何比较 key 的?(规范层)
Map 使用的是:SameValueZero
SameValueZero不会把 object 自动转 primitive
为什么 ArkTS 更容易踩到这个坑?
const key = want.parameters['params'];
你以为是 string,但底层可能是:
为什么 set 能成功,但 get 却失败?
map.set(primitive_string, 'value');map.get(String_object); // 查不到
因为set的时候已经做了转化
解决方案(必须)
key 统一 primitive 化
const safeKey = String(key2);map.get(safeKey);
鸿蒙 ArkTS 中最稳妥的写法(推荐你直接用)
function normalizeKey(key: unknown): string { return String(key).trim();}
完整例子:
export class MyHashMap<V> extends HashMap<string,V>{ override hasKey(key: string): boolean { return super.hasKey(this.normalizeKey(key)); } override get(key: string): V { return super.get(this.normalizeKey(key)); } override set(key: string, value: V): Object { return super.set(this.normalizeKey(key), value); } override remove(key: string): V { return super.remove(this.normalizeKey(key)); } private normalizeKey(key: string): string { return String(key).trim(); }}
其他建议:https://z.l6j.cn/Y5EgkB
在ArkTS 3.x ~ 4.x:
Map对 key 来源非常敏感
JSON / Native / System 参数 一定要 normalize
官方 demo 里也几乎都用 Record
const params: Record<string, string> = {};params[key] = value;params[key]; // 永远 OK