12

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 です。
4

2 に答える 2

15

これは私が思っていたよりもずっと複雑でした。

最初は、Scala が暗黙を解決する方法のせいだと思っていました。どういうわけか、この暗黙のうちInt.scalaが優先されていると思いました。優先度のルールは通常直感的ですが、このような極端なケースについては、6.26.3 オーバーロードの解決を参照してください。私を混乱させたのは、への呼び出しがint2doubleそこにないことでした-それはすでににインライン化されています.toDouble!!

もう少し掘り下げてみると、 から への変換に適用される値の型に関するエッジ ケースがあるIntようDoubleです。弱適合性と呼ばれるものが、変換方法を決定しますByte -> Short -> Int -> Long -> Float -> Double。したがって、全体として、この組み込みの変換を無効にすることはできないと思います...

この変換は数値拡大と呼ばれます

数値拡大

期待される型に弱く適合するプリミティブな数値型を持つ場合、e数値変換メソッドのいずれかを使用して期待される型に拡張されますtoShort, toChar, toInt, toLong, ...toFloattoDouble

編集

また、Martin Odersky (これは古いリンクです。ここで一般的に言われていることは信用しないでください) から、なぜこれが問題なのか疑問に思っている人のために、これらの特別な機能がない場合、よくある問題に遭遇します。変換:

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

あまり直感的ではありません...

于 2016-08-16T05:13:16.297 に答える
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
}

ここに画像の説明を入力

参照: 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#value-conversions

から: http://www.scala-lang.org/files/archive/spec/2.11/03-types.html#weak-conformance

弱い適合性 場合によっては、Scala はより一般的な適合関係を使用します。S<:TS<:T または >SS と TT の両方がプリミティブ数型であり、次の順序で SS が TT より前にある場合、>SS 型は S<:wTS<:wT と書かれた TT 型に弱く適合します。

バイト <:w<:w ショート

短い <:w<:w 整数

文字 <:w<:w 整数

Int <:w<:w Long

Long <:w<:w フロート

フロート <:w<:w ダブル

弱い最小上限は、弱い適合性に関する最小上限です。

于 2016-08-16T05:08:27.093 に答える