当传递非map参数时,函数是否会以静默方式返回nil?

时间:2014-01-23 16:48:50

标签: exception map clojure

当您传递的内容不是预期地图的地图时,我会看到某些函数以某种方式静默返回nil(或您传递的默认值),这有点让我感到惊讶。

首先采用以下文档和示例,它按预期工作:

user> (doc dissoc)
-------------------------
clojure.core/dissoc
([map] [map key] [map key & ks])
  dissoc[iate]. Returns a new map of the same (hashed/sorted) type,
  that does not contain a mapping for key(s).

dissoc的第一个参数必须是根据文档的地图,所以这里会发生什么:

user> (dissoc {:a 1 :b 2} :b)
{:a 1}

工作正常,我通过了地图。让我们传递一些不是映射到该函数的函数,该函数的doc说第一个参数应该是map:

user> (dissoc 1 :b)
ClassCastException java.lang.Long cannot be cast to clojure.lang.IPersistentMap  clojure.lang.RT.dissoc (RT.java:758)

足够公平,在运行时抛出异常并且问题很明显,这是我预期的行为。

现在让我们采取另一种功能:

user> (doc get)
-------------------------
clojure.core/get
([map key] [map key not-found])
  Returns the value mapped to key, not-found or nil if key not present.

get的第一个参数必须是按照文档的地图,这里会发生什么:

user> (get {:a 1} :a)
1

到目前为止一切顺利。让我们传递一些不是映射到该函数的函数,该函数的doc说第一个参数应该是map:

user> (get 42 :a)
nil

没有例外。没什么。只是沉默"失败"。

当你传递的东西不是地图而不是另一个时,一个函数如何抛出异常,尽管这两个函数都是' docs清楚地说明第一个参数必须是地图?

是否有"规则"知道什么时候,在Clojure中,你会得到例外或nil或者我是否应该期望这种东西不一致?

作为一个侧面问题:Clojure和Clojure计划会打破"打破"如果,例如, get 被修改为抛出异常,而不是在你没有通过你应该去的地图时默默地返回nil?

2 个答案:

答案 0 :(得分:3)

对于非关联参数的get,可能会抛出 ,例如:

(contains? 42 :a)
;=> IllegalArgumentException 

(get 42 :a)
;=> nil ?? 

这是open issue in Clojure's Issue Tracker。正如问题描述中所述,返回nil的当前行为很可能是一个错误,并且可能会掩盖编程错误。

答案 1 :(得分:1)

get旨在处理所有关联数据结构。语言实现者可以选择检查参数是否是关联的,或者创建一个可以检查的所有关联事物的白名单,但是它有一些在clojure.lang.RT中定义的特殊情况,并且也可以在任何实现Map或IPersistentSet或ILookup的东西。

the code is not too hard to grok

现在,至于为什么它会默默地在没有实现这些接口的东西上返回nil,这是一个持久的Clojure设计策略的实例,它默默地返回nil而不是失败。这个决定肯定有权衡,但这是Clojure做事的普遍方式。