如何在Clojure中区分缺失的键和值为nil的键?

4
我们经常使用获取某个键的值并将其与nil进行比较的方法来测试哈希映射中是否存在某个键,例如:data
(defn test-my-hash-map [my-hash-map]
  (if (:data my-hash-map) 42 "plugh!"))

对于包含键:data且值不为nil的任何哈希表,此操作将生成42

(map test-my-hash-map
     [{:data "Hello!"}    ; ~~> 42
      {:no-data "Yikes!"} ; ~~> "plugh!"
      {:data nil}         ; ~~> "plugh!", but I need it to say 42 :(
     ])

我完全看不到任何解决方法,这会影响一些数据处理方案,因为我们从非Clojure的数据源中获取数据,在这些数据源中,缺少键意味着“该键没有数据”,而带有nil值的键意味着“我在那里有数据,但由于某种原因无法提供给你”。我不知道如何在Clojure代码中区分这些情况。 我的极其笨拙的解决方法是插入一个Java shim来检测差异,并在交给Clojure之前为特殊情况插入额外的列(键)。

2
“(contains? my-hash-map :data)”有什么问题吗? - fjarri
2个回答

5
有一个Clojure函数get,可以提供默认值。
(:foo {:bar 1}) ; ==> nil
(get {:bar 1} :foo "no key inserted") ; ==> "no key inserted"

当然还有contains?
(contains? {:bar 1} :bar) ; ==> true

contains 很好,因为代码读起来很清晰 (if (contains? row :data) ...) - Reb.Cabin

2

如果你只是想测试一个键是否存在,可以使用contains?

(contains? {:a nil} :a) ; => true
(contains? {:a nil} :b) ; => false

对于您的情况,您可以使用 get 来提供默认值:

(get {:a 42} :a "foo!") ; => 42
(get {:a nil} :a "foo!") ; => nil
(get {:a 42} :b "foo!") ; => "foo!"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接