scala中从Int到Double的隐式转换不';行不通

scala中从Int到Double的隐式转换不';行不通,scala,implicit-conversion,scalac,Scala,Implicit Conversion,Scalac,我已经编写了一些如下所示的隐式代码,我想知道为什么没有调用i2d函数implicit conversation 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:

我已经编写了一些如下所示的隐式代码,我想知道为什么没有调用
i2d
函数implicit conversation

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
  }
}
//Test.scala
[[打字机末尾的语法树]]
包装{
对象测试扩展了scala.AnyRef{
def():Test.type={
测试。超级。();
()
};
隐式def i2d(x:Int):Double={
scala.this.Predef.println(“foo”);
x、 加倍
};
隐式def d2i(x:Double):Int=x.toInt;
private[this]valx:Int=10;
def x:Int=Test.this.x;
private[this]valy:Double=Test.this.x.toDouble;
defy:Double=Test.this.y;
private[this]valz:Int=Test.this.d2i(3.5);
def z:Int=Test.this.z
}
}
规格

  • scalac版本是2.11.8
查看Int companion对象中的最后一行。我认为这与观点的概念有关:

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
}

另见:

编辑

根据@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
                         ^
scala-Ywarn数字加宽
欢迎使用Scala 2.11.8(Java热点(TM)64位服务器虚拟机,Java 1.8.091)。
键入要计算的表达式。或者尝试:帮助。
scala>对象测试{
|隐式def i2d(x:Int):Double={
|println(“foo”)
|x.toDouble
|   }
|
|隐式def d2i(x:Double):Int={
|x.toInt
|   }
|
|val x:Int=10
|值y:Double=x
|val z:Int=3.5
| }
:22:警告:隐式数字加宽
值y:Double=x
^
此外,要在@Alec中添加关于加宽的内容:

发件人:

弱一致性
在某些情况下,Scala使用更通用的一致性关系。类型>SS弱地符合类型TT,写为S这比我想象的要复杂得多

起初,我认为这是因为Scala如何解析隐式。不知怎么的,我觉得我已经被优先考虑了。优先级规则通常是直观的,但对于这样的边缘情况,我们参考。但让我困惑的是,对
int2double
的调用不存在-它已经内联到
.toDouble

进一步挖掘之后,似乎有一个关于值类型的边缘案例,适用于从
Int
Double
的转换。一个名为的东西指示我们如何转换
字节->短->整数->长->浮点->双-/code>。所以,总而言之,我不认为你可以否决这个内置转换

这种转换称为

数字加宽 如果
e
有一个与预期类型弱一致的原始数字类型,则该类型将扩展为预期类型 使用一种数值转换方法
toShort
toChar
toInt
toLong
toFloat
toDouble

编辑 此外,如果有人想知道这是为什么,从(这是一个旧链接-不要相信这里所说的话),如果我们没有这些额外的特殊转换,我们会遇到常见的问题:

不是很直观


使用
-Ywarn numeric EXTEND
使转换可见。令人误解的是,隐式方法在本例中与问题无关。@Yaneeve Alecs answer对此解释得很好。@Alec您引用的ML线程包括2.10中用作回退机制的伴随隐式方法的示例,以及2.11中用于视图的隐式方法的示例。@Yaneeve请原谅,另一个答案是邮件列表线程的“旧链接”,这仍然是经典的。例如,参见Paul Phillips消息,该消息使用2.10中的转换方法,但不使用2.11中的转换方法;Jason Zaugg插嘴说,如果您想要
Int=>Double
等,2.11中的方法仍然可用。重复
scala-hypothetical> val x = List(1, 2.0) 
x: List[AnyVal]