Longs 的 Clojure 重载方法解析 [英] Clojure overloaded method resolution for Longs

查看:15
本文介绍了Longs 的 Clojure 重载方法解析的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这种行为对我来说毫无意义:

This behavior makes no sense to me:

user=> (type 1)
java.lang.Long
user=> (type (cast Long 1))
java.lang.Long
user=> (type 1)
java.lang.Long
user=> (type (Long. 1))
java.lang.Long
user=> (type (cast Long 1))
java.lang.Long
user=> (BigDecimal. 1)
1M
user=> (BigDecimal. (Long. 1))
CompilerException java.lang.IllegalArgumentException: More than one matching method found: java.math.BigDecimal, compiling:(NO_SOURCE_PATH:22) 
user=> (BigDecimal. (cast Long 1))
1M

为什么 (BigDecimal. (Long. 1)) 案例无法找到明确的匹配方法签名,而其他两个表达式(具有完全相同的参数类型)却成功了?

Why does the (BigDecimal. (Long. 1)) case fail to find an unambiguous matching method signature while the other two expressions—which have exactly the same argument type—succeed?

我发现这种行为的奇怪之处在于它似乎是 Long 类型所特有的:

What I find even more strange about this behavior is that it seems particular to the Long type:

user=> (BigDecimal. (Long. 1))
CompilerException java.lang.IllegalArgumentException: More than one matching method found: java.math.BigDecimal, compiling:(NO_SOURCE_PATH:1) 
user=> (BigDecimal. (Integer. 1))
1M

推荐答案

来自 Clojure 讨论组中的这个讨论 似乎您遇到了 Rich Hickey 做出的设计决策.具体来说,因为 BigDecimal 没有签名 BigDecimal(Long long) (Edit: 的构造函数,因此编译器不得不在 intlong 构造函数 - 请参阅下面的评论以讨论为什么使用 Integer 有效),编译器不会尝试猜测"您的意思是哪个构造函数,并且显式失败.

From this discussion on the Clojure discussion group it seems you have encountered a design decision made by Rich Hickey. Specifically, because BigDecimal does not have a constructor of the signature BigDecimal(Long long) ( and therefore leaves the compiler having to choose between the int and long constructors - see comments below for discussion on why using Integer works), the compiler will not attempt to "guess" which constructor you will meant, and explicitly fails.

底线是 Java 端的特定类型要求需要显式装箱才能获得正确且非脆弱的代码.- 丰富的希基

The bottom line is specific type requirements on the Java side require explicit boxing on order to have correct and non-brittle code. - Rich Hickey

请注意,根据 本文档:

与先前版本的 Clojure 相比,数字文字被解析为原始 long 或 double.

In contrast to previous versions of Clojure, numeric literals are parsed as primitive longs or doubles.

要了解其他操作为何起作用,您必须深入研究 Clojure 源代码,特别是 Compiler.java 及其内部类 NumberExpr.这就是您的文字被自动装箱为 Long 的地方,编译器反过来调用 Object.getClass() (它们都 typeclass 做).

To understand why the other operations work, you have to dig into Clojure source, specifically Compiler.java and its inner class NumberExpr. That is the where your literal gets auto-boxed to a Long and the compiler has no problem in turn calling Object.getClass() (which both type and class do).

Compiler.getMatchingParams(),Clojure 编译器尝试解析使用哪个 BigDecimal 的构造函数.但是,您已明确指定参数的类型为 Long - BigDecimal 没有采用该类型的构造函数.

In the Compiler.getMatchingParams(), the Clojure compiler attempts to resolve which constructor of BigDecimal to use. However, you have explicitly specified that your parameter has the type Long - there is no constructor for BigDecimal that takes that type.

也许这不是常识",但 Rich Hickey 决定您需要精确地确定参数的类型,并且它们必须与 Java 类的类型相匹配.编译器拒绝猜测您的意图.

Maybe this isn't "common sense," but Rich Hickey made the decision that you need to be precise about the type of your parameters and that they have to match the type of the Java class. The compiler is refusing to guess your intent.

注意以下几点:

user=> (new BigDecimal 1M)
Reflection warning, NO_SOURCE_PATH:33 - call to java.math.BigDecimal ctor can't be resolved.
IllegalArgumentException No matching ctor found for class java.math.BigDecimal  clojure.lang.Reflector.invokeConstructor (Reflector.java:183)

另请注意,此 Java 代码有效并解析为 BigDecimal 的 int 构造函数:

Also note that this Java code is valid and resolves to the int constructor for BigDecimal:

    byte b = 1;
    new BigDecimal(new Byte(b));

但是这段代码也失败了(即使它应该"使用 int 构造函数):

But this code also fails (even though it "should" use the int constructor):

user=> (BigDecimal. (Byte. (byte 1)))
Reflection warning, NO_SOURCE_PATH:37 - call to java.math.BigDecimal ctor can't be resolved.
IllegalArgumentException No matching ctor found for class java.math.BigDecimal  clojure.lang.Reflector.invokeConstructor (Reflector.java:183)

tl;dr:Clojure 支持 Java interop 但这并不意味着它必须遵循 Java Language Specification 的推广规则.

tl;dr: Clojure supports Java interop but that does not mean it has to follow the promotion rules of Java Language Specification.

cast 怎么样?

What about cast?

下面的评论询问了 (cast).在这种情况下,您明确告诉 Clojure 编译器将类型解析委托给 JVM.请注意以下可编译但在运行时失败的(无意义的)代码:

A comment below asks about (cast). In that case you are explicitly telling the Clojure compiler to delegate type resolution to the JVM. Note the following (nonsensical) code that compiles, yet fails at runtime:

user=> (set! *warn-on-reflection* true)
true
user=> (defn make-big-dec [obj] (BigDecimal. (cast Math obj)))
Reflection warning, NO_SOURCE_PATH:7 - call to java.math.BigDecimal ctor can't be resolved.
#'user/make-big-dec
user=> (make-big-dec 1)
ClassCastException   java.lang.Class.cast (Class.java:2990)

后记二

Clojure 社区对此主题进行了大量讨论.请查看这些详细的主题:

There has been quite a bit of discussion on this topic in the Clojure community. Please check out these detailed threads:

增强的原始支持(Rich Hickey)

Enhanced Primitive Support (Rich Hickey)

Clojure 1.3 处理整数和长整数(内森·马尔兹)

这篇关于Longs 的 Clojure 重载方法解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆