我是Clojure的新手,我目前仍然遇到以下代码,当我像这样运行它时抛出NullPointerException:
(mapset inc [1 1 2 2])
(defn mapset
[fn v]
(loop [[head & tail] v result-set (hash-set)]
(if (nil? head)
result-set)
(conj result-set (fn head))
(recur tail result-set)))
当我在if块中打印结果集时,它会打印一个空集,而我期望这样的集合:#{2 3}
在尝试解释堆栈跟踪后,我猜NullPointerException与以下行有关:
(conj result-set (fn head))
。
stacktrace以及结果集为空的事实让我相信inc操作以某种方式被调用nil作为输入。
我很高兴解释为什么会发生这种错误
上面提到的(shortend)stacktrace看起来像这样:
java.lang.NullPointerException
Numbers.java: 1013 clojure.lang.Numbers/ops
Numbers.java: 112 clojure.lang.Numbers/inc
core.clj: 908 clojure.core/inc
core.clj: 903 clojure.core/inc
REPL: 6 user/mapset
REPL: 1 user/mapset
答案 0 :(得分:3)
我做了一些小改动:
(defn mapset [f v]
(loop [[head & tail] v
result-set (hash-set)]
(if (nil? head)
result-set
(let [res (f head)]
(recur tail (conj result-set res))))))
(defn x-1 []
(mapset inc [1 1 2 2]))
(x-1)
;;=> #{3 2}
现在mapset
会在f
的每个输入上调用函数v
,然后将该调用的结果放入在hash-set
创建的if
中。首先。
问题在于if
语句的控制流逻辑。在fn
之后,执行流程仍在继续。因此,即使f
为head
nil
,函数if
(我重命名为when
,而不是将其保留为宏的名称)也被调用你的意图。
正如最初编码的那样,if
(更明显是In [23]: x = ['data_0', 'data_1', 'data_100', 'data_101', 'data_109', 'data_11', 'data_110']
In [24]: sorted(x)
Out[24]: ['data_0', 'data_1', 'data_100', 'data_101', 'data_109', 'data_11', 'data_110']
)没有做任何有用的事情。但是一旦我意识到你想要一个key
,但是过早关闭了这个问题,那么答案就会落到实处。因此,微小的变化解决了这个问题 - 你的基础逻辑是合理的 - 修正后的功能才起作用。