Scala 如何将 Int 转换为 Double?
How does Scala convert Int to Double?
val d: Double = 42
当我尝试通过 intellij 查找隐式转换时,没有发现任何有趣的东西。此外,Int
不是 Double
的子类型。那么 Scala 是如何做到的呢?
长话短说:这不是对某些伴随对象的普通隐式转换,数字类型得到特殊处理。
如果我们 运行 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 extends Object {
private[this] val d: Double = _;
<stable> <accessor> private def d(): Double = anon.this.d;
def <init>(): <$anon: Object> = {
anon.super.<init>();
anon.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)
告诉我们 numeric widening 的规则适用于类型 T
的表达式 e
出现在
类型 pt
是预期的,T
弱符合 pt
。在这种情况下,我们可以应用规则
- 表达式
e = 42
- 表达式类型
T = Int
- 预期类型
pt = Double
因此,42
使用 toDouble
转换为 42.0
。因为它是一个可以在编译时处理的常量,
我们在脱糖代码中看不到 toDouble
。但是,如果我们用 non-constant 对类似的程序进行脱糖
值
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 extends Object {
private[this] val d: Double = _;
<stable> <accessor> private def d(): Double = anon.this.d;
def <init>(): <$anon: Object> = {
anon.super.<init>();
anon.this.d = new scala.util.Random().nextInt(42).toDouble();
()
}
}
}
并且 toDouble
在那里,如指定的那样。
val d: Double = 42
当我尝试通过 intellij 查找隐式转换时,没有发现任何有趣的东西。此外,Int
不是 Double
的子类型。那么 Scala 是如何做到的呢?
长话短说:这不是对某些伴随对象的普通隐式转换,数字类型得到特殊处理。
如果我们 运行 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 extends Object {
private[this] val d: Double = _;
<stable> <accessor> private def d(): Double = anon.this.d;
def <init>(): <$anon: Object> = {
anon.super.<init>();
anon.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)
告诉我们 numeric widening 的规则适用于类型 T
的表达式 e
出现在
类型 pt
是预期的,T
弱符合 pt
。在这种情况下,我们可以应用规则
- 表达式
e = 42
- 表达式类型
T = Int
- 预期类型
pt = Double
因此,42
使用 toDouble
转换为 42.0
。因为它是一个可以在编译时处理的常量,
我们在脱糖代码中看不到 toDouble
。但是,如果我们用 non-constant 对类似的程序进行脱糖
值
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 extends Object {
private[this] val d: Double = _;
<stable> <accessor> private def d(): Double = anon.this.d;
def <init>(): <$anon: Object> = {
anon.super.<init>();
anon.this.d = new scala.util.Random().nextInt(42).toDouble();
()
}
}
}
并且 toDouble
在那里,如指定的那样。