【问题标题】:Increment a value in of an atom增加一个原子的值
【发布时间】:2018-12-17 19:23:48
【问题描述】:

我正在学习 clojurescript,我遇到了这个 sn-p。

:on-click (fn [] (swap! state/order update (:id gig) inc))

我查找了 update 函数的文档,它说更新需要一个键和一个函数。将旧值从原子传递给函数,然后更新原子。如果原子中的键没有现有值,则将 nil 作为输入传递给函数。 当我在 repl 中尝试同样的事情时它没有工作

(def atom-test (atom {}))
(swap! atom-test update :aa inc)
NullPointerException   clojure.lang.Numbers.ops (Numbers.java:1013)

添加 fnil 来捕获此 NullPointerException 有效。

user=> (swap! atom-test update :aa (fnil inc 0))
{:aa 1}

我不明白为什么它在 clojurescript 中的案例 1 中有效,以及为什么它在 clojure repl 中的案例 2 中无效。谁能解释一下这里的诀窍。

【问题讨论】:

  • 同理,可以在浏览器控制台输入1 + null得到1,不会报错。我会在两边都使用fnil

标签: clojure clojurescript


【解决方案1】:

inc 函数需要一个满足number? 的参数。在 Clojure 和 ClojureScript 中也是如此。

如果您传递其他内容,例如 nil,则程序不正确:(inc nil) 具有未定义的行为。这样做是不安全的。它恰好返回1,但这并不能保证并且是实施的意外。

例如,如果您将文字字符串传递给 inc,ClojureScript 将在编译时发出警告:

cljs.user=> (inc "a")
WARNING: cljs.core/+, all arguments must be numbers, got [string number] instead at line 1 <cljs repl>

也许在未来,编译器可能会类似地对(inc nil) 发出警告,但更有可能发生的情况是,将编写涵盖核心功能的规范,并指定cljs.core/inc 接受满足@987654330 的参数@。

TL;DR:在这里使用fnil 是正确的做法。

【讨论】:

    【解决方案2】:

    对于 cljs,操作安全处理 nil 而不会引发异常是很常见的。

    cljs.user=> (update {} :a inc)
    {:a 1}
    cljs.user=> (inc nil)
    1
    cljs.user=> (+ 1 nil)
    1
    

    https://cljs.github.io/api/syntax/nil

    【讨论】:

    • 我认为 Clojure 和 ClojureScript 的功能相似。
    猜你喜欢
    • 2011-05-20
    • 2012-05-17
    • 2015-08-31
    • 1970-01-01
    • 2013-05-25
    • 2019-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多