【问题标题】:sorted-map throws exception on failed key look-up排序映射在失败的键查找时抛出异常
【发布时间】:2016-05-24 10:13:22
【问题描述】:
user=> (def m (sorted-map 1 2))
#'user/m
user=> (map? m)
true
user=> (get m :type)
ClassCastException java.lang.Long cannot be cast to clojure.lang.Keyword
  clojure.lang.Keyword.compareTo (Keyword.java:114)

sorted-map 似乎选择了数值比较功能,不会与关键字进行比较。

最好推理一下,“这个东西支持 IPersistentMap。所以,我可以在它上面调用get 以查明它是否是我知道的一种地图,而不会有抛出异常的风险。” get 的文档字符串表示“如果键不存在,则返回映射到键、未找到或 nil 的值。”

在键查找时抛出异常是一个错误吗?更重要的是,是否有一种安全、标准的方法来检查任意对象是否属于给定的“类型”(由与其:type 键关联的值定义)?

【问题讨论】:

  • sorted-map 生成一个 TreeMap,它使用已排序的键进行排序。要找到特定的密钥,它应该将现有密钥与您请求的密钥进行比较,这就是失败的地方:(< 1 :asd)

标签: exception dictionary clojure dynamic-typing


【解决方案1】:

sorted-map 的键在某种程度上应该具有可比性似乎是合理的,1:type 的情况并非如此,这就是您的异常的原因。

话虽如此,我认为您应该能够使用任何类型的键查询映射并在提供的键和映射中的键不可比较的情况下获得 nil

您可以通过sorted-map-by 提供您自己的比较器来解决问题,该比较器执行所需的类型检查。

【讨论】:

  • 我主要关心的是我可以编写一个小函数来测试任何对象是否具有感兴趣的“类型”——例如,查看它是否是map?,然后查询它的:type钥匙。 sorted-map-by 方法是否要求我永远不要制作一个普通的 sorted-map 也不要接受来自库函数的一个?
【解决方案2】:

这是一个发人深省的问题,我很高兴你提出这个问题。经过深思熟虑,我倾向于期望与另一个答案中提到的相同 - 我可能希望返回 nil,但也许 Rich 有这样做的哲学原因。

至于你问题的最后一部分:你可以使用type。如果您想测试已知类型,也可以使用instance?。我想诀窍是类型(我几乎总是相信)将成为底层 Java 类

user=> (type foo)
clojure.lang.PersistentTreeMap

user=> (instance? clojure.lang.PersistentTreeMap foo)
true

编辑: 根据下面的讨论,我在这里放了一些额外的示例代码(比 cmets 更容易阅读)。这将允许将任意元数据附加到数据结构:

user=> (def foo (sorted-map 1 2))
#'user/foo
user=> (def foo-enhanced (with-meta foo {:type :integer-keys}))
#'user/foo-enhanced
user=> foo-enhanced
{1 2}
user=> (meta foo-enhanced)
{:type :integer-keys}

【讨论】:

  • 我想我的问题并不清楚:我的意思是广义上的“类型”,如果您对哪些键和值有不同的约定或期望,则两个不同的地图具有不同的“类型”进入他们。人们通常使用:type 键来表示这些期望。当我编写一些调试代码来打印参数但only if they're not a certain huge map 代表系统的整个状态时,我遇到了导致这个问题的问题。不过其他地图还不错。对此有什么想法吗?
  • 没有更多上下文很难说太多,但您可能会看到metawith-meta。这实际上可能是一种更安全的方式。我将在上面举一个例子。
  • 谢谢!我没想过使用meta。我会考虑的。
  • 嗯,想了想,我觉得meta 行不通。它要求所有代码都遵循一定的约定。我只是在寻找一种方法来判断,无论是否遵循某个约定,如果一个对象是一个包含具有特定值的 :type 键的映射。 (我目前的解决方法是将对get 的调用包含在捕获所有 异常的try 块中。我希望有更好的方法!)
猜你喜欢
  • 2014-07-25
  • 2013-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-22
  • 1970-01-01
相关资源
最近更新 更多