为什么Clojure对非法论证说"没有匹配的方法"?

Nat*_*ong 7 clojure

正确使用Character/isWhitespace的用法包括:

(Character/isWhitespace \a) => false
(Character/isWhitespace \ ) => true
Run Code Online (Sandbox Code Playgroud)

但是,我的第一次尝试是这个,我发现错误令人困惑.

(Character/isWhitespace "")
  =>  IllegalArgumentException No matching method found: isWhitespace
  => clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:80)
Run Code Online (Sandbox Code Playgroud)

IllegalArgument部分是有道理的,但为什么它说"找不到匹配的方法"?显然,该功能确实存在.

澄清

我问这个问题的原因是我是Clojure的新手,并认为我从根本上误解了一些东西.

当我输入时(Character/isWhitespace \a),我认为我所说的是:"我知道有一个Character命名空间,并且在其中有一个被调用的函数isWhitespace,我想调用该函数并传入\a".

在这个心智模型上,我上面的结果令人困惑,因为Clojure似乎在说,"每当你给我一个这个函数不接受的参数类型时,我就会假装该函数不存在." 例如,"你不允许混合砖块,所以如果你试试,我会给你一个BlenderDoesntExist错误." 这很奇怪.

一些答案似乎暗示了这一点

  • 这个名字Character/isWhitespace只是一部分的什么Clojure的使用查找功能,而另一部分则是参数的类型.(我已经做了一些搜索:这可能是一种多方法吗?)
  • 该方法正在Java类中查找?

一个很好的答案将为我澄清这个过程.

Gui*_*ler 10

TL;博士

clojure编译器依赖于反射,以便为Java互操作类方法找到匹配的签名,并且当找不到任何内容时,它会引发它自己的异常.

在这种情况下,IllegalArgumentException正确引发了a,但是noMethodReport显示的错误消息会导致混淆.

这个负责它的源代码clojureGitHub库.

长版

首先,Java互操作解析演练.

当clojure解析器找到.点宏时,HostExpr解析器处理解析,该解析尝试确定第二个参数是符号还是类.

如果它是一个类,则假定它是被调用的类的静态方法,并继续解析StaticMethodExpr.

解析器内部的第一件事是尝试通过对类的反射来查找方法:

  List methods = Reflector.getMethods(c, args.count(), methodName, true);
  if(methods.isEmpty())
      throw new IllegalArgumentException("No matching method: " + methodName);
Run Code Online (Sandbox Code Playgroud)

它正确找到它并且在那时没有引发异常

然后它将参数添加到找到的方法:

  java.lang.reflect.Method m = (java.lang.reflect.Method) methods.get(i);
  params.add(m.getParameterTypes());
Run Code Online (Sandbox Code Playgroud)

之后尝试查找匹配方法签名索引:

  methodidx = getMatchingParams(methodName, params, args, rets);
Run Code Online (Sandbox Code Playgroud)

对于这种情况,返回'-1'并method保持为空.这就是解析阶段.

评估时间......

然后,当invokeStaticMethod被调用时,它调用getMethodsReflector.java其正确找到"isWhitespace"两个匹配的签名.

最后你看到的令人困惑的信息,内部功能:

 static Object invokeMatchingMethod(String methodName, List methods, Object target, Object[] args)
Run Code Online (Sandbox Code Playgroud)

测试找到的方法参数匹配,试图找到具有适当签名的方法:

 for(Iterator i = methods.iterator(); i.hasNext();)
   {
    m = (Method) i.next();
    Class[] params = m.getParameterTypes();
    if(isCongruent(params, args))
Run Code Online (Sandbox Code Playgroud)

如果未找到匹配的签名,则引发异常

if(m == null)
   throw new IllegalArgumentException(noMethodReport(methodName,target));
Run Code Online (Sandbox Code Playgroud)

所以答案是clojure编译器依赖于反射来找到方法的匹配签名,并且当没有找到任何东西时它会引发它自己的异常.

在这种情况下,IllegalArgumentException正确引发了a,但是noMethodReport显示的错误消息会导致混淆.


Rör*_*örd 6

Character/isWhitespace是一种Java方法(类的静态方法java.lang.Character).有关调用Java方法的语法示例,请参阅Java interop.

虽然常规Clojure函数仅由其名称定义,但Java方法由其签名定义,其签名由其名称及其参数的数量和类型组成.

Character类中isWhitespace定义的方法的唯一变体是和.所以用字符串调用"没有匹配的方法" .isWhitespace(char ch)isWhitespace(int codepoint)isWhitespace