Неявное преобразование из Int в Double в Scala не работает

Я написал некоторый неявный код, как показано ниже, и мне интересно, почему 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
  }
}

Спекуляции

  • скалярная версия 2.11.8.

2 ответа

Решение

Это было намного сложнее, чем я думал.

Сначала я думал, что это из-за того, как Scala разрешает последствия. Почему-то я думал, что это подразумевается вInt.scalaбыл приоритетом. Правила приоритета, как правило, интуитивно понятны, но для подобных случаев мы обращаемся к 6.26.3 Разрешение перегрузки. Но меня смутило то, что int2double не там - он уже склонен к .toDouble!!

Выкопав немного больше, кажется, что есть крайний случай относительно типов значений, который применяется к преобразованию из Int в Double, То, что называется слабым соответствием, диктует, как мы преобразуем Byte -> Short -> Int -> Long -> Float -> Double, В общем, я не думаю, что вы можете отменить это встроенное преобразование...

Это преобразование известно как расширение чисел

Численное расширение

Если e имеет тип примитивного числа, который слабо соответствует ожидаемому типу, он расширен до ожидаемого типа, используя один из методов преобразования чисел toShort, toChar, toInt, toLong, toFloat, toDouble...

РЕДАКТИРОВАТЬ

Кроме того, в случае, если кому-то интересно, почему это происходит, от Мартина Одерского (это старая ссылка - не верьте тому, что здесь говорится в общем), мы сталкиваемся с общими проблемами, если у нас нет этих дополнительных специальных преобразования:

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

Не очень интуитивно понятно...

Посмотрите на последнюю строку в объекте-компаньоне 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
}

введите описание изображения здесь

Смотрите также: Где Scala ищет последствия?

РЕДАКТИРОВАТЬ

согласно комментарию @ 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/06-expressions.html

от: http://www.scala-lang.org/files/archive/spec/2.11/03-types.html

Слабое соответствие В некоторых ситуациях Scala использует более общее отношение соответствия. SS типа> слабо соответствует типу TT, записанному как S <: wTS <: wT, если S <: TS <: T или оба> SS и TT являются типами примитивных чисел, и SS предшествует TT в следующем> порядке.

Байт <: w <: w Short

Короткая <: w <: w Int

Char <: w <: w Int

Int <: w <: w Long

Long <: w <: w Float

Поплавок <: w <: w Double

Слабая наименьшая верхняя граница является наименьшей верхней границей по отношению к слабому соответствию.

Другие вопросы по тегам