请在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
...