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

欢迎!请查看关于页面,了解更多有关如何使用本网站的信息。

0
Java 互操作

尝试获取Unicode字符串的长度,我在RosettaCode 【1】 上找到了这个名为 grapheme-length 的代码

(def grapheme-length
  #(->> (doto (BreakIterator/getCharacterInstance)
          (.setText %))
        (partial (memfn next))
        repeatedly
        (take-while (partial not= BreakIterator/DONE))
        count))

我这样从REPL中调用它来测试它

(star-traders.util/grapheme-length "\uD83D\uDE04⌘\uD83D\uDE00") ; Expecting 3

虽然它确实返回了预期的值,但我还得到了一个意外的红色警告信息,让我考虑向 clojure.lang.InjectedInvoker 的维护者报告...

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by clojure.lang.InjectedInvoker/0x0000000800cc8440 (file:/Users/myusername/.m2/repository/org/clojure/clojure/1.10.1/clojure-1.10.1.jar) to method sun.text.RuleBasedBreakIterator.setText(java.text.CharacterIterator)
WARNING: Please consider reporting this to the maintainers of clojure.lang.InjectedInvoker/0x0000000800cc8440
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

显然这是一个由于Java 9模块系统的添加而导致的JVM已知问题,并在Clojure FAQ中提及。 【2】

虽然问题确实消失,如果将 --illegal-access=deny 添加到JVM参数中,但看起来推荐的解决方案是使用类型提示修复代码。

我尝试使用 --illegal-access=warn 来定位问题所在并修复它,如下所示

          (.setText ^java.text.BreakIterator %)) ; Problem happens here (I think)

然而问题仍然存在,这让我好奇我该使用正确的类型。

我该如何修改代码以消除编译器警告,而不是压制警告?

【1】https://rosettacode.org/wiki/String_length#Grapheme_Length_2
【2】https://clojure.org/guides/faq#illegal_access

1 个答案

+1
作者:
已被选中 作者:
 
最佳答案

实际上,这条代码中有几行引发了反射警告:即 .setText 调用和 .next 调用。我认为您需要以下内容来解决这两个问题:

user=> (def grapheme-length
  #(->> (doto (BreakIterator/getCharacterInstance)
          (.setText ^String %)) ; hint the argument here
        (partial (fn [^BreakIterator o] (.next o))) ; hint the object here
        repeatedly
        (take-while (partial not= BreakIterator/DONE))
        count))
#'user/grapheme-length
user=> (grapheme-length "\uD83D\uDE04⌘\uD83D\uDE00")
3
user=> 
作者:
总的来说,memfn 由于其实现本身,总会引入反射。
作者:
这行代码解决了问题,Sean。谢谢。我对你是怎么想到这个解决方法的很感兴趣,但那是另一天的对话。我怀疑我并没有理解错误消息的真正含义。(感谢 Alex -- 这是我的第一次接触 memfn。)
作者:
我将我的 REPL 会话复制到 Gist 中并添加了注释:[在这里](https://gist.github.com/seancorfield/01e42dbf3de68bab6ef3d7d6245af192)
...