我已经编写了一些隐式代码,如下所示,我想知道为什么不调用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
}
}
功能
答案 0 :(得分:13)
这比我想象的要多得多。
起初,我认为这是因为Scala如何解决隐含问题。不知何故,我认为this implicit in Int.scala
被优先考虑。优先级规则通常很直观,但对于像这样的边缘情况,我们引用6.26.3 Overloading Resolution。令我困惑的是,int2double
的调用不存在 - 它已经内联到.toDouble
!!
挖了一点之后,似乎有一个关于值类型的边缘情况适用于从Int
到Double
的转换。名为weak conformance的内容决定了我们如何转换Byte -> Short -> Int -> Long -> Float -> Double
。所以,总而言之,我不认为你可以否决这种内置转换...
此转化称为numeric widening
数字扩展
如果
e
具有与预期类型弱符合的原始数字类型,则将其扩展为预期类型 使用其中一种数字转换方法toShort
,toChar
,toInt
,toLong
,toFloat
,toDouble
...
此外,如果有人想知道为什么这是一件事,请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
}
击> <击> 撞击>
另请参阅: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
弱弱上限是弱一致性的最小上限。