Clojure中字符串转keyword查询map返回nil问题排查
问题原因
查询返回nil的核心是动态生成key时搞错了Clojure keyword、symbol的构造规则,生成的key和map里实际存储的key完全不匹配:
- 你定义的
myarray里的key是:p1,属于keyword类型对象。它字面量前面的冒号是Clojure reader识别keyword的语法标记,不是keyword名称本身的一部分,:p1的实际名称字符串是"p1",没有前导冒号。 - 你写的
(keyword ":p1"),是把带冒号的字符串":p1"当做keyword名称传入,最终生成的keyword是:":p1"——这个key的名称本身就包含冒号,和map里的:p1是完全不同的两个对象,自然查不到结果。 - 你写的
(symbol ":p1")存在两个问题:一是map的key是keyword类型,不是symbol类型,Clojure map查询要求类型、值完全匹配才会返回对应值,类型不对直接查不到;二是传入带冒号的字符串生成的symbol名称本身带冒号,哪怕是同类型也和预期key不匹配。
正确写法
动态生成对应key查询时,只需要把不带前导冒号的目标名称字符串传给keyword函数即可:
(def myarray {:p1 "test"}) ;; 正确生成:p1 keyword,查询返回对应值 (get myarray (keyword "p1")) ;; => "test"
容易遗漏的核心要点
- Clojure中keyword、symbol字面量的前缀(keyword的前导冒号、语法quote的单引号)都是给编译器/reader用的语法标记,不属于对象本身的名称内容,动态构造这两类对象时不要把这些标记写进名称参数里。
- Clojure的map查询是精确匹配逻辑,只有key的类型、内部值完全一致时才能命中,哪怕REPL打印效果看起来相似,类型不符、名称多一个字符都会返回nil。比如
(symbol ":p1")打印效果和:p1接近,但前者是Symbol类型、后者是Keyword类型,二者永远不相等。 - 如果不确定自己动态生成的key是否正确,可以直接在REPL里查看生成对象的类型、对比和原key的相等性,很容易定位问题。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

