键入隐式转换的推断

时间:2018-01-19 17:46:30

标签: scala type-inference implicit-conversion implicit

考虑以下代码:

Mail::send('default template?', $data, function($message) use($data) {
    $message->to($data['email']);
    $message->subject('New email!!!');
});

有了这个范围,我想编写一个隐式方法,静默地从sealed trait Data case class StringData(string: String) extends Data case class IntData(int: Int) extends Data trait Reader[A] { def read(data: Data): A } implicit val stringReader: Reader[String] = { case StringData(string) => string case _ => sys.error("not a string") } implicit val intReader: Reader[Int] = { case IntData(int) => int case _ => sys.error("not an int") } 值转换为它们的“真实”Scala值。

Data

但是,此代码无法编译:

implicit def fromData[A: Reader](data: Data): A =
  implicitly[Reader[A]].read(data)

错误是类型不匹配。 implicits的标准调试方法显示val str: String = StringData("foo") val int: Int = IntData(420) 来自A不能被推测(所有隐式fromData都显示为适用)。

为方便起见,this是代码scastie的链接。在this other scastie中,提供了一个类似但不同的工作片段。

我的问题:这里发生了什么?

1 个答案:

答案 0 :(得分:0)

如下所示,对Data类以及读者隐式转换进行更改,可以编译代码。

import scala.language.implicitConversions

sealed trait Data[A]
case class StringData(string: String) extends Data[String]
case class IntData(int: Int) extends Data[Int]

trait Reader[A] {
  def read(data: Data[A]): A
}

implicit val stringReader: Reader[String] = {
  case StringData(string) => string
  case _                  => sys.error("not a string")
}
implicit val intReader: Reader[Int] = {
  case IntData(int) => int
  case _            => sys.error("not an int")
}

implicit def fromData[A](data: Data[A])(implicit ev: Reader[A]): A = ev.read(data)

val str: String = StringData("foo")
val int: Int = IntData(420)

您需要输入数据,以便编译器可以根据Data的类型参数推断应该使用哪个Reader。另请注意,如果未定义隐式Reader,则无法编译以下内容。

case class DoubleData(d: Double) extends Data[Double]

// Fails compilation because no implicit Reader exists.
val d: Double = DoubleData(5d)