在 scala 中从 Int 到 Double 的隐式转换不起作用
Implicit conversion from Int to Double in scala doesn't work
我写了一些如下所示的隐式代码,我想知道为什么 i2d
函数隐式对话没有被调用。
object Test {
implicit def i2d(x: Int): Double = {
println("foo")
x.toDouble
}
implicit def d2i(x: Double): Int = {
x.toInt
}
val x: Int = 10
val y: Double = x
val z: Int = 3.5
}
scalac -Xprint:typer Test.scala
的输出
// Test.scala
[[syntax trees at end of typer]]
package <empty> {
object Test extends scala.AnyRef {
def <init>(): Test.type = {
Test.super.<init>();
()
};
implicit def i2d(x: Int): Double = {
scala.this.Predef.println("foo");
x.toDouble
};
implicit def d2i(x: Double): Int = x.toInt;
private[this] val x: Int = 10;
<stable> <accessor> def x: Int = Test.this.x;
private[this] val y: Double = Test.this.x.toDouble;
<stable> <accessor> def y: Double = Test.this.y;
private[this] val z: Int = Test.this.d2i(3.5);
<stable> <accessor> def z: Int = Test.this.z
}
}
规格
- scalac 版本为 2.11.8。
查看 Int 伴随对象中的最后一行。我认为这与观点的概念有关:
object Int extends AnyValCompanion {
/** The smallest value representable as a Int.
*/
final val MinValue = java.lang.Integer.MIN_VALUE
/** The largest value representable as a Int.
*/
final val MaxValue = java.lang.Integer.MAX_VALUE
/** Transform a value type into a boxed reference type.
*
* @param x the Int to be boxed
* @return a java.lang.Integer offering `x` as its underlying value.
*/
def box(x: Int): java.lang.Integer = java.lang.Integer.valueOf(x)
/** Transform a boxed type into a value type. Note that this
* method is not typesafe: it accepts any Object, but will throw
* an exception if the argument is not a java.lang.Integer.
*
* @param x the java.lang.Integer to be unboxed.
* @throws ClassCastException if the argument is not a java.lang.Integer
* @return the Int resulting from calling intValue() on `x`
*/
def unbox(x: java.lang.Object): Int = x.asInstanceOf[java.lang.Integer].intValue()
/** The String representation of the scala.Int companion object.
*/
override def toString = "object scala.Int"
/** Language mandated coercions from Int to "wider" types.
*/
implicit def int2long(x: Int): Long = x.toLong
implicit def int2float(x: Int): Float = x.toFloat
implicit def int2double(x: Int): Double = x.toDouble
}
另请参阅:Where does Scala look for implicits?
编辑
根据@som-snytt 的评论:
scala -Ywarn-numeric-widen
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_91).
Type in expressions for evaluation. Or try :help.
scala> object Test {
| implicit def i2d(x: Int): Double = {
| println("foo")
| x.toDouble
| }
|
| implicit def d2i(x: Double): Int = {
| x.toInt
| }
|
| val x: Int = 10
| val y: Double = x
| val z: Int = 3.5
| }
<console>:22: warning: implicit numeric widening
val y: Double = x
^
此外,添加到@Alec 的 about widening: http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#value-conversions
来自:http://www.scala-lang.org/files/archive/spec/2.11/03-types.html#weak-conformance
Weak Conformance
In some situations Scala uses a more general conformance relation. A type >SS weakly conforms to a type TT, written S<:wTS<:wT, if S<:TS<:T or both >SS and TT are primitive number types and SS precedes TT in the following >ordering.
Byte <:w<:w Short
Short <:w<:w Int
Char <:w<:w Int
Int <:w<:w Long
Long <:w<:w Float
Float <:w<:w Double
A weak least upper bound is a least upper bound with respect to weak conformance.
这比我想象的要复杂得多。
起初,我认为这是因为 Scala 解析隐式的方式。不知何故,我想到了this implicit in Int.scala
was getting prioritized. The rules for priority are usually intuitive, but for edge cases like this, we refer to 6.26.3 Overloading Resolution。令我困惑的是 int2double
的调用不存在 - 它已经内联到 .toDouble
!!
进一步研究后,似乎有一种关于值类型的边缘情况适用于从 Int
到 Double
的转换。一个叫做 weak conformance 的东西决定了我们如何转换 Byte -> Short -> Int -> Long -> Float -> Double
。所以,总而言之,我认为你不能否决这个内置转换...
此转换称为 numeric widening
Numeric Widening
If e
has a primitive number type which weakly conforms to the expected type, it is widened to the expected type
using one of the numeric conversion methods toShort
, toChar
,
toInt
, toLong
, toFloat
, toDouble
...
编辑
此外,如果有人想知道 为什么 这是一个东西,来自 Martin Odersky(这是一个旧的 link - 不要相信什么一般在这里说),如果我们没有这些额外的特殊转换,我们 运行 会遇到常见问题:
scala-hypothetical> val x = List(1, 2.0)
x: List[AnyVal]
Not very intuitive...
我写了一些如下所示的隐式代码,我想知道为什么 i2d
函数隐式对话没有被调用。
object Test {
implicit def i2d(x: Int): Double = {
println("foo")
x.toDouble
}
implicit def d2i(x: Double): Int = {
x.toInt
}
val x: Int = 10
val y: Double = x
val z: Int = 3.5
}
scalac -Xprint:typer Test.scala
// Test.scala
[[syntax trees at end of typer]]
package <empty> {
object Test extends scala.AnyRef {
def <init>(): Test.type = {
Test.super.<init>();
()
};
implicit def i2d(x: Int): Double = {
scala.this.Predef.println("foo");
x.toDouble
};
implicit def d2i(x: Double): Int = x.toInt;
private[this] val x: Int = 10;
<stable> <accessor> def x: Int = Test.this.x;
private[this] val y: Double = Test.this.x.toDouble;
<stable> <accessor> def y: Double = Test.this.y;
private[this] val z: Int = Test.this.d2i(3.5);
<stable> <accessor> def z: Int = Test.this.z
}
}
规格
- scalac 版本为 2.11.8。
查看 Int 伴随对象中的最后一行。我认为这与观点的概念有关:
object Int extends AnyValCompanion {
/** The smallest value representable as a Int.
*/
final val MinValue = java.lang.Integer.MIN_VALUE
/** The largest value representable as a Int.
*/
final val MaxValue = java.lang.Integer.MAX_VALUE
/** Transform a value type into a boxed reference type.
*
* @param x the Int to be boxed
* @return a java.lang.Integer offering `x` as its underlying value.
*/
def box(x: Int): java.lang.Integer = java.lang.Integer.valueOf(x)
/** Transform a boxed type into a value type. Note that this
* method is not typesafe: it accepts any Object, but will throw
* an exception if the argument is not a java.lang.Integer.
*
* @param x the java.lang.Integer to be unboxed.
* @throws ClassCastException if the argument is not a java.lang.Integer
* @return the Int resulting from calling intValue() on `x`
*/
def unbox(x: java.lang.Object): Int = x.asInstanceOf[java.lang.Integer].intValue()
/** The String representation of the scala.Int companion object.
*/
override def toString = "object scala.Int"
/** Language mandated coercions from Int to "wider" types.
*/
implicit def int2long(x: Int): Long = x.toLong
implicit def int2float(x: Int): Float = x.toFloat
implicit def int2double(x: Int): Double = x.toDouble
}
另请参阅:Where does Scala look for implicits?
编辑
根据@som-snytt 的评论:
scala -Ywarn-numeric-widen
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_91).
Type in expressions for evaluation. Or try :help.
scala> object Test {
| implicit def i2d(x: Int): Double = {
| println("foo")
| x.toDouble
| }
|
| implicit def d2i(x: Double): Int = {
| x.toInt
| }
|
| val x: Int = 10
| val y: Double = x
| val z: Int = 3.5
| }
<console>:22: warning: implicit numeric widening
val y: Double = x
^
此外,添加到@Alec 的
来自:http://www.scala-lang.org/files/archive/spec/2.11/03-types.html#weak-conformance
Weak Conformance In some situations Scala uses a more general conformance relation. A type >SS weakly conforms to a type TT, written S<:wTS<:wT, if S<:TS<:T or both >SS and TT are primitive number types and SS precedes TT in the following >ordering.
Byte <:w<:w Short
Short <:w<:w Int
Char <:w<:w Int
Int <:w<:w Long
Long <:w<:w Float
Float <:w<:w Double
A weak least upper bound is a least upper bound with respect to weak conformance.
这比我想象的要复杂得多。
起初,我认为这是因为 Scala 解析隐式的方式。不知何故,我想到了this implicit in Int.scala
was getting prioritized. The rules for priority are usually intuitive, but for edge cases like this, we refer to 6.26.3 Overloading Resolution。令我困惑的是 int2double
的调用不存在 - 它已经内联到 .toDouble
!!
进一步研究后,似乎有一种关于值类型的边缘情况适用于从 Int
到 Double
的转换。一个叫做 weak conformance 的东西决定了我们如何转换 Byte -> Short -> Int -> Long -> Float -> Double
。所以,总而言之,我认为你不能否决这个内置转换...
此转换称为 numeric widening
Numeric Widening
If
e
has a primitive number type which weakly conforms to the expected type, it is widened to the expected type using one of the numeric conversion methodstoShort
,toChar
,toInt
,toLong
,toFloat
,toDouble
...
编辑
此外,如果有人想知道 为什么 这是一个东西,来自 Martin Odersky(这是一个旧的 link - 不要相信什么一般在这里说),如果我们没有这些额外的特殊转换,我们 运行 会遇到常见问题:
scala-hypothetical> val x = List(1, 2.0) x: List[AnyVal]
Not very intuitive...