我在对话框上挂了一个WindowListener,结果出错
$ clj windowlistener.clj
WARNING: When invoking clojure.main, use -M
Syntax error (IllegalArgumentException) compiling reify* at (windowlistener.clj:9:10).
Can't define method not in interfaces: windowIconified
这是我的代码。你看到问题了吗?
(import 'javax.swing.JOptionPane
'java.awt.event.WindowListener)
(let [jdialog (.createDialog
(JOptionPane. (System/getProperty "java.version"))
"WindowListener")
wl (reify WindowListener
(windowActivated [this e])
(windowClosed [this e])
(windowClosing [this e])
(windowDeactivated [this e])
(windowDeiconified [this e])
(windowIconified [this e])
(windowOpened [this e]))]
(.addWindowListener jdialog wl)
(.show jdialog))
我知道方法名拼写正确,因为我从Firefox显示的Javadoc [1] 中粘贴,然后重新排列括号。哈哈,复制粘贴是我的错误!这是我的十六进制转储
$ od -tcx1 ~/windowlistener.clj
...
0000700 ( w i n d o w I c
20 20 20 20 20 20 20 28 77 69 6e 64 6f 77 49 63
0000720 o n i f i e d 342 200 213 [ t h i s
6f 6e 69 66 69 65 64 e2 80 8b 20 5b 74 68 69 73
0000740 e ] ) \t \n
那342 200 213(即e2 80 8b垃圾)是什么?我猜文件是UTF-8格式的,在这种情况下,这些字节表示Unicode码点0x200b(通过位操作[2]),它表示零宽空格,根据unicode.org[3]。
(顺便说一句,我没有在Oracle的网页上找到这些字节。也许Firefox为了剪贴板的好处,在元素之间插入了零宽空格。)
我很惊讶编译器把零宽空格当作符号字符。这种行为与javadoc不相同。根据Character,零宽空格是标识符可忽略的
$ clj
Clojure 1.10.1
user=> (Character/isIdentifierIgnorable 0x200b)
true
Unicode小心翼翼地建议“为了安全” [4] “缩小”标识符集合,据推测,可能是因为构建具有看不见区分的代码是一种没有正当用途的权力。
实际上,javadoc忽略了零宽空格:在“public static void main”中的“main”中间插入零宽空格,你的程序仍然能正常工作。[5] 如果没有这个先例,我可能更愿意直接拒绝“可忽略的”,但我可以使用linters来做这件事。
我还对错误消息没有明确指出问题感到不满。javadoc通过首先剔除标识符可忽略的字符来避开这个挑战,因此没有看不见的方面需要揭露。无论如何,并非所有无意的零宽空格的使用都立即导致编译器错误。我从javadoc粘贴的代码充满了它们,包括附加到参数名称上,它们不会导致错误,直到以后——而且很可能是与“正确”的拼写相关的错误,而不是被感染的拼写。
总结来说,为了人道主义原因,我们建议Clojure将“可忽略的标识符”字符从符号中排除,无论是通过忽略它们(如javac所做)还是将它们视为一个错误吗?
[1] https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/event/WindowListener.html
[2] https://en.wikipedia.org/wiki/UTF-8#Encoding
[3] https://util.unicode.org/UnicodeJsps/character.jsp?a=200B
[4] http://unicode.org/reports/tr31/#Figure_Code_Point_Categories_for_Identifier_Parsing
[5] 您可以使用Unicode字面量来完成
class A {
public static void m\u200bain(String[] args) throws Exception {
System.out.println("Hello world!");
}
}