我有一个期望(String,Double)作为参数
的方法scala> def testTupleType(x: (String, Double)) = {}
testTupleType: (x: (String, Double))Unit
scala> val x: Int = 2
x: Int = 2
然后我尝试将参数传递给testTupleType方法,如:
scala> val testTuple = ("String", x)
testTuple: (String, Int) = (String,2)
scala> testTupleType(testTuple)
<console>:11: error: type mismatch;
found : (String, Int)
required: (String, Double)
testTupleType(testTuple)
它按预期显示错误。但是当我传递参数内联时:
scala> testTupleType(("String", x))
没有任何错误!我不知道这是因为这里有隐式转换吗?
答案 0 :(得分:4)
scala中没有从Int
到Double
的隐式转换。见 3.5.3
SLS中的弱一致性。
如果testTupleType(testTuple)
错误包含所有信息:(String, Int)
不是(String, Double)
。
使用“内联”参数:
testTupleType(("String", x))
这意味着:
testTupleType(Tuple2.apply("String", x))
方法apply
接受2种类型参数:
def apply[T1, T2](_1: T1, _2: T2): (T1, T2)
testTupleType
接受(String, Double)
,因此apply
((T1, T2)
)的结果类型应为(String, Double)
。类型推断后:
testTupleType(Tuple2.apply[String, Double]("String", x))
或:
val a: (String, Double) = Tuple2.apply[String, Double]("String", x)
testTupleType(a)
由于一致性较弱,您可以在Int
使用Double
。
答案 1 :(得分:2)
要了解问题,请查看-Xprint:typer
显示的内容:
在第一种情况下,您将testTuple: (String, Int) = (String,2)
传递给期望testTupleType: (x: (String, Double))Unit
的方法,但Scala没有从Tuple2[String, Int]
到Tuple2[String, Double]
的隐式转换:
val t = Tuple2[String, Int]("a", 2)
val a: (String, Double) = t
<console>:8: error: type mismatch;
found : (String, Int)
required: (String, Double)
val a: (String, Double) = t
^
请记住,(String,Int)只是调用Tuple2.apply的编译器的语法糖。
那么为什么秒片段有效呢?因为Scala将其变为Tuple2[String, Double]
:
private[this] val res1: Unit = testTupleType(scala.Tuple2.apply[String, Double]("String", x.toDouble));
<stable> <accessor> def res1: Unit = res1
总结一下,在第一种情况下,你已经有了一个Tuple2 [String,Int],并且Scala没有隐式转换为Tuple2 [String,Double],但是你可以创建自己的:
implicit def tsi2tdi(t: Tuple2[String, Int]): Tuple2[String, Double] = (t._1, t._2.toDouble)
并且在秒的情况下,它看到你有一个String和一个Int,你需要将它们转换为Tuple2[String, Double]
。
<强>更新强>
不,它不是由apply
方法调用,而是由编译器调用。编译Scala时执行不同的分析阶段,其中一个称为typer
。当scalac
看到代码中有Int
时,您想要得到的是Double
值,它知道根据提到的弱一致性规则senia ,它可以通过调用Double
方法从Int
获得toDouble
。这不是Scala观点中的隐式转换。如果你还记得原始转换是在C和Java中,早在Scala之前
答案 2 :(得分:1)
问题是由于您的代码取决于隐式转换,在这种情况下,当您传递testTuple内联时,它不会发生。
如果你使用val x:Double = 2
它应该有用。