gpt4 book ai didi

clojure - 与记录、协议(protocol)和编译相关的令人惊讶的行为

转载 作者:行者123 更新时间:2023-12-03 00:40:16 24 4
gpt4 key购买 nike

我遇到了一种对我来说似乎有点令人惊讶的行为与 Clojure 记录相关。

设置如下:

  1. 一个命名空间定义一种记录类型:

    (ns defrecordissue.arecord)

    (defrecord ARecord [])
  2. 另一个命名空间定义了一个协议(protocol),并将其扩展到记录1中定义的类型:

    (ns defrecordissue.aprotocol
    (:require [defrecordissue.arecord])
    (:import [defrecordissue.arecord ARecord]))

    (defprotocol AProtocol
    (afn [this]))

    (extend-protocol AProtocol
    ARecord
    (afn [this] 42))
  3. 第三个命名空间构造记录的实例并调用记录协议(protocol)功能。

    (ns defrecordissue.aot1
    (:require [defrecordissue.aprotocol]
    [defrecordissue.arecord]))

    (defrecordissue.aprotocol/afn (defrecordissue.arecord/->ARecord))

编译 defrecordissue.aot1 命名空间时,在我的例子中使用lein编译defrecordissue.aot1,编译失败并显示以下异常:

Exception in thread "main" java.lang.IllegalArgumentException: No implementation of method: :afn of protocol: #'defrecordissue.aprotocol/AProtocol found for class: defrecordissue.arecord.ARecord, compiling:(aot1.clj:5:1)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3463)
at clojure.lang.Compiler.compile1(Compiler.java:7153)
at clojure.lang.Compiler.compile(Compiler.java:7219)
at clojure.lang.RT.compile(RT.java:398)
at clojure.lang.RT.load(RT.java:438)
at clojure.lang.RT.load(RT.java:411)
at clojure.core$load$fn__5018.invoke(core.clj:5530)
at clojure.core$load.doInvoke(core.clj:5529)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5336)
at clojure.core$compile$fn__5023.invoke(core.clj:5541)
at clojure.core$compile.invoke(core.clj:5540)
at user$eval7.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:6619)
at clojure.lang.Compiler.eval(Compiler.java:6609)
at clojure.lang.Compiler.eval(Compiler.java:6582)
at clojure.core$eval.invoke(core.clj:2852)
at clojure.main$eval_opt.invoke(main.clj:308)
at clojure.main$initialize.invoke(main.clj:327)
at clojure.main$null_opt.invoke(main.clj:362)
at clojure.main$main.doInvoke(main.clj:440)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:419)
at clojure.lang.AFn.applyToHelper(AFn.java:163)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)
Caused by: java.lang.IllegalArgumentException: No implementation of method: :afn of protocol: #'defrecordissue.aprotocol/AProtocol found for class: defrecordissue.arecord.ARecord
at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:541)
at defrecordissue.aprotocol$fn__40$G__35__45.invoke(aprotocol.clj:5)
at clojure.lang.AFn.applyToHelper(AFn.java:161)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3458)
... 25 more

如果我更改3)直接构造记录类,如下所示:

(ns defrecordissue.aot2
(:require [defrecordissue.aprotocol]
[defrecordissue.arecord]))

(defrecordissue.aprotocol/afn (defrecordissue.arecord.ARecord.))

编译成功。

我怀疑这与 http://dev.clojure.org/jira/browse/CLJ-371 ,但我不明白到底发生了什么。

我还应该补充一点,如果没有lein clean,编译会成功第二次,因为现在可以在类路径。因此,我可以通过 AOT 编译来解决这个问题定义记录类型的命名空间。

我在 GitHub 上创建了一个简单的 leiningen 项目,该项目说明了问题,使用方法见README: https://github.com/ragnard/defrecordissue

为什么我会看到这种行为,避免这种行为的正确方法是什么?

更新

我向 GitHub 存储库添加了一个新分支,更好地说明了核心问题: https://github.com/ragnard/defrecordissue/tree/more-realistic/

无论记录位于何处(即在哪个命名空间中),都会出现问题实例已构建。

最佳答案

我可以使用您的存储库重现该问题。以下是对我有用的三个解决方案:

  1. 告诉leincompile编译更多命名空间:

    lein compile defrecordissue.aprotocol defrecordissue.arecord defrecordissue.aot1
  2. 放置

    :aot [defrecordissue.aprotocol defrecordissue.arecord defrecordissue.aot1]

    project.clj中。

  3. 放置

    :aot :all

    project.clj中。

后两者使 leincompile 完成 lein aot1 的工作(在 2 的情况下)以及 lein aot1lein aot2(在 3 的情况下。)。

关于clojure - 与记录、协议(protocol)和编译相关的令人惊讶的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16056265/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com