Неявное преобразование из 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
Слабая наименьшая верхняя граница является наименьшей верхней границей по отношению к слабому соответствию.