【问题标题】:Updating an atom with update and inc fails使用 update 和 inc 更新 atom 失败
【发布时间】:2019-05-06 17:42:25
【问题描述】:

我有一个原子(在 ClojureScript 中):

(def player
  (atom {:episode 0 ...}))

我想将:episode 加一:

(swap! player update :episode inc)

这在 Lein REPL 中运行良好。

但是,当运行时,它会抛出:

mfp.js:5808 Uncaught Error: No protocol method IDeref.-deref defined for type cljs.core/PersistentHashMap: ...

    at Object.cljs$core$missing_protocol [as missing_protocol] (mfp.js:5808)
    at Object.cljs$core$_deref [as _deref] (mfp.js:7268)
    at cljs$core$deref (mfp.js:9396)
    at mfp$update (mfp.js:36808)
    at mfp.js:18388
    at Function.cljs.core.swap_BANG_.cljs$core$IFn$_invoke$arity$4 (mfp.js:18389)
    at cljs$core$swap_BANG_ (mfp.js:18341)
    at mfp$next_episode (mfp.js:36946)
    at HTMLAnchorElement.<anonymous> (mfp.js:36920)

我可以通过使用更长的形式来解决这个问题:

(swap! player assoc :episode (+ 1 (@player :episode)))

但是,我想知道为什么第一种形式不起作用。谢谢。

【问题讨论】:

  • 您似乎正在尝试 swap! 取消引用的值而不是原子本身。确保将原子传递给swap!
  • 什么代码不起作用? (swap! player update :episode inc) 应该像你说的那样工作。
  • @Carcigenicate 我非常同意,但是如果player 是一张地图,您确定这是您收到的错误消息吗?对于像我这样更习惯 JVM-clojure 的人来说,它看起来像一个包含哈希图的原子,但传递的函数不是 inc - 它是一些试图取消其输入的函数。事实上,我看到 cljs.core/update 直接调用 deref - 就好像有人写了(swap! player update :k deref)
  • @amalloy 你是对的。错误的第一行似乎直截了当且很常见,以至于我对其余部分感到震惊。不过,这将是一个更奇怪的错误。
  • 实际上,我对第二个不能正常工作的看法是错误的。 swap! 允许的“隐式函数”出于某种原因让我失望。我认为切换到 C 语言正在腐烂我的大脑。

标签: clojure clojurescript


【解决方案1】:

您使用的是什么版本的 Clojure/ClojureScript?我只是尝试一下:

project.clj

(defproject cljsdemo "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "https://www.eclipse.org/legal/epl-2.0/"}
  :dependencies [[org.clojure/clojure "1.10.0"]
                 [org.clojure/clojurescript "1.10.520"]]
  :main ^:skip-aot cljsdemo.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}}
  :plugins [[lein-cljsbuild "1.1.7"]]
  :cljsbuild {
              :builds [{
                        ;; The path to the top-level ClojureScript source directory:
                        :source-paths ["src-cljs"]
                        ;; The standard ClojureScript compiler options:
                        ;; (See the ClojureScript compiler documentation for details.)
                        :compiler {:output-to "public/js/main.js" ;; default: target/cljsbuild-main.js
                                   :optimizations :advanced
                                   :pretty-print false}}]}

src-cljs/foo/demo.cljs

(ns foo.demo)

(def player
  (atom {:episode 0 :hello "world"}))

(println
 (clj->js
  (swap! player update :episode inc)))

public/index.html

<html>
  <body>
    <h1>Testing...</h1>
    <script src="js/main.js"></script>
  </body>
</html>

目录结构:

$ tree
.
├── project.clj
├── public
│   └── index.html
└── src-cljs
    └── foo
        └── demo.cljs

编译代码:lein cljsbuild once.

然后我用:cd public; python -m SimpleHTTPServer 3000 启动一个 Web 服务器并在 Firefox 上打开 http://0.0.0.0:3000/,我在 JavaScript 控制台上看到以下内容:

#js {:episode 1, :hello world}

【讨论】:

  • 感谢您的回答。正如@ez121sl 在 cmets 中指出的那样,update 在导致问题的代码中被重新定义。
  • @Siegmeyer 评论是短暂的,应该被视为随时可能消失。如果您找到了问题的答案,请通过将其发布为答案来记录这一事实。
  • 当然可以。
【解决方案2】:

正如 @ez121sl 在 cmets 中指出的那样,函数 update 在代码的其他地方被重新定义,这导致了错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-29
    • 1970-01-01
    • 2017-01-16
    • 2021-08-24
    • 1970-01-01
    • 2019-11-07
    • 2015-11-10
    • 1970-01-01
    相关资源
    最近更新 更多