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

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

问题描述

这种行为对我没有意义:

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 类型特别:

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) (编辑)的构造函数,因此让编译器必须在 int long 构造函数 - 请参阅下面的注释,讨论为什么使用 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端的特定类型要求,需要显式加载才能拥有正确和非脆弱的代码。 - Rick Hickey

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

请注意,文字会被解析为基本类型,而不是盒装类型,每个此文档

Note that literals are parsed as primitives, not "boxed" types, per this documentation:


相反到以前版本的Clojure,数字文字被解析为原始长整型或双精度型。

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

为了理解为什么其他操作的工作,你必须挖掘Clojure源代码,特别是 Compiler.java 及其内部类 NumberExpr 。这是你的文本被自动装入到 Long 的地方,编译器没有问题反过来调用 Object.getClass() type class do)。

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语言规范的促销规则。

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)


b $ b

结语II

在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整数和长整数的处理(Nathan Marz)

Clojure 1.3 treatment of integers and longs (Nathan Marz)

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

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