在scala中从Int到Double的隐式转换不起作用

时间:2016-08-16 04:20:16

标签: scala implicit-conversion scalac

我已经编写了一些隐式代码,如下所示,我想知道为什么不调用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。

2 个答案:

答案 0 :(得分:13)

这比我想象的要多得多。

起初,我认为这是因为Scala如何解决隐含问题。不知何故,我认为this implicit in Int.scala被优先考虑。优先级规则通常很直观,但对于像这样的边缘情况,我们引用6.26.3 Overloading Resolution。令我困惑的是,int2double的调用不存在 - 它已经内联到.toDouble !!

挖了一点之后,似乎有一个关于值类型的边缘情况适用于从IntDouble的转换。名为weak conformance的内容决定了我们如何转换Byte -> Short -> Int -> Long -> Float -> Double。所以,总而言之,我不认为你可以否决这种内置转换...

此转化称为numeric widening

  

数字扩展

     

如果e具有与预期类型弱符合的原始数字类型,则将其扩展为预期类型   使用其中一种数字转换方法toShorttoChar,   toInttoLongtoFloattoDouble ...

修改

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

scala-hypothetical> val x = List(1, 2.0) 
x: List[AnyVal]
     

不太直观......

答案 1 :(得分:3)

查看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
}

<击>

enter image description here

另请参阅: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 answer添加有关加宽的内容: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

  

弱一致性   在某些情况下,Scala使用更一般的一致性关系。类型&gt; SS弱地符合类型TT,写入S&lt;:WTS&lt;:wT,如果S&lt;:TS&lt;:T或两者&gt; SS和TT是原始数字类型并且SS在以下&gt;排序中在TT之前

     

Byte&lt;:w&lt;:w

     

简短&lt;:w&lt;:w Int

     

Char&lt;:w&lt;:w Int

     

Int&lt;:w&lt;:w long

     

长&lt;:w&lt;:w Float

     

Float&lt;:w&lt;:w Double

     

弱弱上限是弱一致性的最小上限。