请分享您的想法,参与2024 年 Clojure 状态调查!

欢迎!请访问关于页面,了解更多关于这个工作方式的信息。

0
编译器

保存以下代码片段并运行,就像
{quote}
java -jar clojure-1.6.0.jar snippet.clj
{quote}

会产生

`
$ java -jar clojure-1.6.0.jar snippet.clj
Exception in thread "main" java.lang.IllegalArgumentException: Unable to resolve classname: clojure.core$boolean@1356d4d4, compiling:(/Users/kamstrup/tmp/snippet.clj:15:1)

at clojure.lang.Compiler.analyzeSeq(Compiler.java:6651)
at clojure.lang.Compiler.analyze(Compiler.java:6445)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6632)
at clojure.lang.Compiler.analyze(Compiler.java:6445)
at clojure.lang.Compiler.access$100(Compiler.java:38)
at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:538)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6644)
at clojure.lang.Compiler.analyze(Compiler.java:6445)
at clojure.lang.Compiler.analyze(Compiler.java:6406)
at clojure.lang.Compiler.eval(Compiler.java:6707)
at clojure.lang.Compiler.load(Compiler.java:7130)
at clojure.lang.Compiler.loadFile(Compiler.java:7086)
at clojure.main$load_script.invoke(main.clj:274)
at clojure.main$script_opt.invoke(main.clj:336)
at clojure.main$main.doInvoke(main.clj:420)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.lang.Var.invoke(Var.java:379)
at clojure.lang.AFn.applyToHelper(AFn.java:154)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)

Caused by: java.lang.IllegalArgumentException: Unable to resolve classname: clojure.core$boolean@1356d4d4

at clojure.lang.Compiler$HostExpr.tagToClass(Compiler.java:1069)
at clojure.lang.Compiler$InvokeExpr.getJavaClass(Compiler.java:3659)
at clojure.lang.Compiler$LocalBinding.hasJavaClass(Compiler.java:5657)
at clojure.lang.Compiler$LocalBindingExpr.hasJavaClass(Compiler.java:5751)
at clojure.lang.Compiler.maybePrimitiveType(Compiler.java:1283)
at clojure.lang.Compiler$IfExpr.doEmit(Compiler.java:2631)
at clojure.lang.Compiler$IfExpr.emit(Compiler.java:2613)
at clojure.lang.Compiler$BodyExpr.emit(Compiler.java:5826)
at clojure.lang.Compiler$LetExpr.doEmit(Compiler.java:6180)
at clojure.lang.Compiler$LetExpr.emit(Compiler.java:6133)
at clojure.lang.Compiler$BodyExpr.emit(Compiler.java:5826)
at clojure.lang.Compiler$FnMethod.doEmit(Compiler.java:5374)
at clojure.lang.Compiler$FnMethod.emit(Compiler.java:5232)
at clojure.lang.Compiler$FnExpr.emitMethods(Compiler.java:3771)
at clojure.lang.Compiler$ObjExpr.compile(Compiler.java:4410)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3904)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6642)
... 19 more

`

该代码片段

`
Clojure 编译器(1.6.0)的 Bug:如果我们在这里用 ^boolean 标注返回,则编译器将得到
IllegalArgumentException: Unable to resolve classname: clojure.core$boolean。
移除它后,一切如预期
(defn ^boolean foo-bar?
[node]
(= node "foo-bar"))

看看,我们可以在这里有 ^boolean,但不能在 foo-bar? 上 !! :-)
(defn ^boolean bar-foo?
[node]
(= node "bar-foo"))

而不是移除 foo-bar? 上的 ^boolean 返回,我们也可以移除这个函数
以确保所有内容如预期工作
(defn ^boolean interesting?
[node]
(or (foo-bar? node) (bar-foo? node)))

(println "Foo-Bar?" (foo-bar? "baz"))
`

5 答案

0

评论由 kamstrup 提出

在代码片段注释 2 中有打字错误:s/xtc-scenario?/foo-bar?/

0

评论由 bronsa 提出

根据文档(https://clojure.org/special_forms),def 符号的元数据将按规则进行评估,评估 boolean 会得到 clojure.core/boolean 函数,这并不是一个有效的类型提示。

作为一种规则,在 argvec 上而不是在 def 符号上附加返回标签,在这个例子中你应该写
(defn foo-bar? ^boolean [node] (= node "foo-bar"))

我理解...

`(defn ^boolean foo [] true) `

并且

`(defn foo ^boolean [] true) `

行为不同,且编译器会在使用类型提示而不是在函数定义时抛出错误,这一点令人困惑(我已经就这一点以及关于类型提示缺乏文档/规范的问题抱怨了一段时间),但这并不是一个错误

0
by

评论由 kamstrup 提出

感谢您的澄清,尼科拉,您确实是正确的。

在方法名称之前放置返回类型注释似乎是在我在网上阅读的许多Clojure代码中的一种常见做法。一些在线教程和clojure.org文档本身(fx.https://clojure.org/cheatsheet)都促进了这一点。
`(defn ^:private ^String my-fn ...)`
可以在https://clojure.org/cheatsheet上找到)

0
by

由jafingerhut发表的评论

米克尔:如果类型标签是Java类,而不是原语,那么^Classname是正确类型标签。如果你使用Eastwood,它可以警告这些错误类型标签,并在此处提供有关哪些有效以及哪些无效的文档:https://github.com/jonase/eastwood#wrong-tag

也在这里:https://github.com/jonase/eastwood#unused-meta-on-macro

0
by
参考:[https://clojure.atlassian.net/browse/CLJ-1674](https://clojure.atlassian.net/browse/CLJ-1674)(由alex+import报告)
...