【发布时间】:2018-08-16 05:25:41
【问题描述】:
val d: Double = 42
当我尝试通过 intellij 找到隐式转换时,没有任何有趣的事情出现。此外,Int 不是Double 的子类型。那么 Scala 是如何做到的呢?
【问题讨论】:
-
@Stoopkid 从某种意义上说,我的问题与该线程相反:我几乎是在问为什么我不需要需要
.toDouble
val d: Double = 42
当我尝试通过 intellij 找到隐式转换时,没有任何有趣的事情出现。此外,Int 不是Double 的子类型。那么 Scala 是如何做到的呢?
【问题讨论】:
.toDouble
长话短说:这不是对某些伴随对象的普通隐式转换,数值类型得到特殊处理。
如果我们在这个脚本上运行scala -print:
val d: Double = 42
我们得到:
package <empty> {
object Main extends Object {
def main(args: Array[String]): Unit = {
new <$anon: Object>();
()
};
def <init>(): Main.type = {
Main.super.<init>();
()
}
};
final class anon$1 extends Object {
private[this] val d: Double = _;
<stable> <accessor> private def d(): Double = anon$1.this.d;
def <init>(): <$anon: Object> = {
anon$1.super.<init>();
anon$1.this.d = 42.0;
()
}
}
}
在脱糖代码中,我们看到一个双字面 42.0,但没有调用任何转换
函数(例如来自Predef)。因此,从Int 到Double 的转换必须不发生
在运行时,但在编译的早期阶段。
section 3.5.3 of the specification
告诉我们Int 弱符合 Double 因为弱符合关系<:w 的传递性:
Int <:w Long <:w Float <:w Double
此外,Section 6.26.1 (Value Conversions)
告诉我们,如果 e 类型为 T 的表达式出现在表达式
类型 pt 是预期的,T 弱符合 pt。在这种情况下,我们可以应用规则
e = 42
T = Int
pt = Double
因此,42 使用 toDouble 转换为 42.0。由于它是一个可以在编译时处理的常量,
我们在脱糖代码中看不到toDouble。但是,如果我们对具有非常数的类似程序进行脱糖
价值
val d: Double = (new scala.util.Random).nextInt(42)
我们得到:
package <empty> {
object Main extends Object {
def main(args: Array[String]): Unit = {
new <$anon: Object>();
()
};
def <init>(): Main.type = {
Main.super.<init>();
()
}
};
final class anon$1 extends Object {
private[this] val d: Double = _;
<stable> <accessor> private def d(): Double = anon$1.this.d;
def <init>(): <$anon: Object> = {
anon$1.super.<init>();
anon$1.this.d = new scala.util.Random().nextInt(42).toDouble();
()
}
}
}
toDouble 在那里,如指定的那样。
【讨论】: