2024年Clojure调查问卷中分享您的想法!

欢迎!有关如何使用本论坛的更多信息,请参阅关于页面。

+1投票
协议

虽然可以扩展协议至原始数组,但指定类型类的操作略显复杂

(defprotocol P (p [_])) (extend-protocol P (Class/forName "[B") (p [_] "bytes")) (p (byte-array 0)) ;; => "bytes"

但如果尝试执行多项操作,情况就变得复杂了

`
(extend-protocol P
(Class/forName "[B") (p [_] "bytes")
(Class/forName "[I") (p [_] "ints"))
编译器异常:java.lang.UnsupportedOperationException: nth 不支持此类型:Character,编译:(NO_SOURCE_PATH:1:1)

clojure.lang.Compiler.analyze (Compiler.java:6380)
clojure.lang.Compiler.analyze (Compiler.java:6322)
clojure.lang.Compiler$MapExpr.parse (Compiler.java:2879)
clojure.lang.Compiler.analyze (Compiler.java:6369)
clojure.lang.Compiler.analyze (Compiler.java:6322)
clojure.lang.Compiler$InvokeExpr.parse (Compiler.java:3624)
clojure.lang.Compiler.analyzeSeq (Compiler.java:6562)
clojure.lang.Compiler.analyze (Compiler.java:6361)
clojure.lang.Compiler.analyze (Compiler.java:6322)
clojure.lang.Compiler$BodyExpr$Parser.parse (Compiler.java:5708)
clojure.lang.Compiler$FnMethod.parse (Compiler.java:5139)
clojure.lang.Compiler$FnExpr.parse (Compiler.java:3751)

原因是
UnsupportedOperationException nth 不支持此类型:Character

clojure.lang.RT.nthFrom (RT.java:857)
clojure.lang.RT.nth (RT.java:807)
clojure.core/emit-hinted-impl/hint--5951/fn--5953 (core_deftype.clj:758)
clojure.core/map/fn--4207 (core.clj:2487)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:60)
clojure.lang.RT.seq (RT.java:484)
clojure.lang.RT.countFrom (RT.java:537)
clojure.lang.RT.count (RT.java:530)
clojure.lang.Cons.count (Cons.java:49)
clojure.lang.Compiler.analyze (Compiler.java:6352)
clojure.lang.Compiler.analyze (Compiler.java:6322)

`

在 {parse-impls} 代码中,第二次 {(Class/forName "[I")} 被识别为函数,而不是新类型。一种权宜之计是将协议一次性扩展到一种类型。

如果在语法中可以指定原始数组类型,那么将会更好(即将添加到增强功能)——我们已经有了 {bytes, ints, longs} 等类型提示的语法,这对我来说看起来非常合适。

5 答案

0 投票

由:nahuel 添加了评论

在仅扩展一个数组类型时也出现了错误

`
(extend-protocol P
String (p [_] "string")
(Class/forName "[B") (p [_] "ints")
)

;=> 编译器异常:java.lang.UnsupportedOperationException: nth 不支持此类型 ...
`

但更改声明顺序可以解决它

`
(extend-protocol P
(Class/forName "[B") (p [_] "ints")
String (p [_] "string")
)

;=> OK
`

0 投票

评论者:alexmiller

与 CLJ-1790 重复

0 投票

评论者:alexmiller

经过进一步检查,我认为这并非与 CLJ-1790 重复,而是一个相关的问题。

0 投票

评论者:glchapman

使用 Class/forName 会有另一个问题,因为不再发出 {{this}} 参数的类型提示

user=> (extend-protocol P (Class/forName "[B") (p [this] (aget this 0))) 反射警告,NO_SOURCE_PATH:2:50 - 无法解析在 clojure.lang.RT 上的静态方法 aget (参数类型:未知,int)。

对于非原始数组也会生成反射警告(所以仅仅支持 {{ints}} 等并不能完全解决这个问题)。最好有一个解决方案,涵盖扩展协议到数组时的所有问题。

0 投票
参考:https://clojure.atlassian.net/browse/CLJ-1381 (由 alexmiller 报告)
...