简体   繁体   English

隐式转换的类型推断

[英]Type inference of implicit conversions

Consider this code: 考虑以下代码:

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")
}

With this in scope, I want to write an implicit method that silently converts from Data values to their "real" Scala values. 在此范围内,我想编写一个隐式方法,该方法将Data值静默转换为它们的“实际” Scala值。

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

But then, this code does not compile: 但是,此代码无法编译:

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

The error is a type mismatch. 错误是类型不匹配。 Standard debugging methods for implicits show that the A from fromData can't be infered (all implicit Reader s are shown as applicable). 标准的隐式调试方法表明,无法fromData中的A (所有隐式Reader均显示为适用)。

For your convenience, this is a link to a scastie of the code. 为了您的方便, 是指向该代码的链接。 In this other scastie , a similiar, yet different, and working snippet is presented. 另一本Scastie中 ,提供了一个类似但又不同的工作片段。

My question: What is going on here? 我的问题:这是怎么回事?

Making the change to your Data class as well as your reader implicit conversion as below allows the code to compile. 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)

You need data to be typed so that the compiler can infer which Reader should be used based on the type parameter of Data . 您需要输入数据,以便编译器可以根据Data的类型参数推断应使用哪个Reader。 Also notice that the following would not compile if you did not define an implicit Reader. 另请注意,如果未定义隐式Reader,则以下内容将不会编译。

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM