纠正Character / isWhitespace的用法包括:
(Character/isWhitespace \a) => false
(Character/isWhitespace \ ) => true
然而,我的第一次尝试是这样,我发现错误令人困惑。
(Character/isWhitespace "")
=> IllegalArgumentException No matching method found: isWhitespace
=> clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:80)
IllegalArgument
部分有意义,但为什么会说“找不到匹配的方法”?显然,该功能确实存在。
我问这个问题的原因是我是Clojure的新手,并且认为我从根本上误解了一些东西。
当我输入(Character/isWhitespace \a)
时,我认为我说的是:“我知道有一个Character
命名空间,其中有一个名为{{的函数1}},我想调用该函数并传入isWhitespace
“。
在这个心理模型上,我上面的结果令人困惑,因为看起来Clojure说,“每当你给我一个这个函数不接受的参数类型时,我就会假装该函数不存在。 “例如,“你不允许混合砖块,所以如果你试试,我会给你一个BlenderDoesntExist错误。”这很奇怪。
有些答案似乎意味着
\a
仅是Clojure用于查找函数的部分,另一部分是参数的类型。 (我已经做了一些搜索:这可能是一种多方法吗?)一个好的答案会为我澄清这个过程。
答案 0 :(得分:10)
clojure编译器依赖于反射来查找Java互操作类方法的匹配签名,并且当找不到任何内容时它会引发它自己的异常。
在这种情况下,IllegalArgumentException
被正确引发,但会显示noMethodReport
错误消息,这会导致混淆。
clojure
github repo上的this is the source code responsible for it。
首先,Java互操作解析演练。
当clojure解析器找到.
点宏时,HostExpr
解析器会处理解析,该解析会尝试确定第二个参数是符号还是类。
如果它是一个类,则认为它是被调用的类的静态方法,并且在StaticMethodExpr
上继续解析。
解析器内部的第一件事是尝试通过对类的反射来找到方法:
List methods = Reflector.getMethods(c, args.count(), methodName, true);
if(methods.isEmpty())
throw new IllegalArgumentException("No matching method: " + methodName);
它正确找到它并且此时不会引发异常
然后它将参数添加到找到的方法中:
java.lang.reflect.Method m = (java.lang.reflect.Method) methods.get(i);
params.add(m.getParameterTypes());
之后尝试查找匹配方法签名索引:
methodidx = getMatchingParams(methodName, params, args, rets);
对于这种情况,返回'-1'并且method
保持为空。这就是解析阶段。
评估时间......
然后,当invokeStaticMethod
被调用时,它会在getMethods
上调用Reflector.java
,正确找到'isWhitespace'的两个匹配签名。
最后你看到的令人困惑的信息,在功能中:
static Object invokeMatchingMethod(String methodName, List methods, Object target, Object[] args)
测试找到的方法参数匹配,试图找到具有适当签名的方法:
for(Iterator i = methods.iterator(); i.hasNext();)
{
m = (Method) i.next();
Class[] params = m.getParameterTypes();
if(isCongruent(params, args))
如果未找到匹配的签名,则会引发异常
if(m == null)
throw new IllegalArgumentException(noMethodReport(methodName,target));
所以答案是clojure编译器依赖于反射来找到方法的匹配签名,并且当找不到任何内容时它会引发它自己的异常。
在这种情况下,IllegalArgumentException
被正确引发,但会显示noMethodReport
错误消息,这会导致混淆。
答案 1 :(得分:6)
Character/isWhitespace
是一种Java方法(java.lang.Character
类的静态方法)。有关调用Java方法的语法示例,请参阅Java interop。
虽然常规Clojure函数仅由它们的名称定义,但Java方法由它们的signature定义,其中包括它们的名称以及它们的参数的数量和类型。
Character类中定义的isWhitespace
方法的唯一变体是isWhitespace(char ch)
和isWhitespace(int codepoint)
。因此,使用字符串调用isWhitespace
时,“没有匹配的方法”。
答案 2 :(得分:3)
因为“”是一个字符串,而不是字符。
user=> (type \a)
java.lang.Character
user=> (type "")
java.lang.String
字符串(java)类没有“isWhitespace”方法,而“字符”方法则没有。你不能用螺丝刀钉钉子。
那里有一些提示:
How to represent empty char in Java Character class
“”是一个空字符串。但是没有“空”字符的代表。尽管字符“\ 0”表示:
user=> (Character/isWhitespace \0)
false
isWhitespace角色的文档:
http://docs.oracle.com/javase/6/docs/api/java/lang/Character.html#isWhitespace%28char%29
说:
“从U + 0000到U + FFFF的字符集有时被称为基本多语言平面(BMP)。代码点大于U + FFFF的字符称为补充字符.Java 2平台使用char数组和String和StringBuffer类中的UTF-16表示。在此表示中,补充字符表示为一对char值,第一个来自高代理范围,(\ uD800- \ uDBFF),第二个来自低代理范围(\ uDC00- \ uDFFF)。“哪个空引号不属于哪个。
换句话说,isWhitespace方法无法“理解”空字符串。
此外,来自clojure java interlop doc http://clojure.org/java_interop:
上面给出了访问字段或方法成员的首选惯用表单。实例成员表单适用于字段和方法。 它们都扩展为在宏展开时调用点运算符(如下所述)。
所以输入
(Character/isWhitespace "")
扩展为
(. Classname instanceMember instance args*)
(. Character isWhitespace "")
导致错误。
user=> (. Character isWhitespace "")
java.lang.IllegalArgumentException: No matching method found: isWhitespace (NO_SOURCE_FILE:0)
虽然您必须查看clojure源代码以确认,但我的猜测是来自可能出现在下面的动态Java编译:
public class toto {
public toto ()
{
Character.isWhitespace("");
}
}
然后:
javac toto.class
toto.java:5: error: no suitable method found for isWhitespace(String)
Character.isWhitespace("");
^
method Character.isWhitespace(int) is not applicable
(actual argument String cannot be converted to int by method invocation conversion)
method Character.isWhitespace(char) is not applicable
(actual argument String cannot be converted to char by method invocation conversion)
1 error
答案 3 :(得分:2)