[英]How to get around the error “Type mismatch, expected: _$1, actual: Any” in scala?
I have a scenario similar to the following example 我有一个类似于以下示例的方案
// Reads from somewhere and returns List of type A
trait Reader[A] {
def read(): List[A]
}
// Transforms element of type A, performs some operation
// and converts result to string
trait Translator[A] {
def translate(a: A): String
}
object Factory {
def getReader(readerName:String) = {
readerName match {
case "one" => new Reader[String] {
override def read() = List("sasha")
}
case "two" => new Reader[Int] {
override def read() = List(3)
}
case _ => throw new IllegalArgumentException
}
}
def getTranslator(translatorName:String) = {
translatorName match {
case "one" => new Translator[String] {
override def translate (a: String) = a + " " + "nice!!!"
}
case "two" => new Translator[Int] {
override def translate(a: Int) = (a+2).toString
}
case "three" => new Translator[Int] {
override def translate(a: Int) = (a+3).toString
}
case _ => throw new IllegalArgumentException
}
}
}
Now when I do Factory.getReader("one").read().map(a => Factory.getTranslator("one").translate(a))
, I get a compile time error "Type mismatch, expected: _$1, actual: Any". 现在,当我执行
Factory.getReader("one").read().map(a => Factory.getTranslator("one").translate(a))
,我得到一个编译时错误“类型不匹配,预期:_ $ 1,实际:任何”。
If I am not wrong, compiler is saying it can't tell if the type A
of reader is same as type A
of translator. 如果我没有记错的话,编译器会说它无法确定阅读器的
A
类型是否与翻译器的A
类型相同。
I am unable to find online, how I can get around this problem ? 我在网上找不到,如何解决这个问题? Am I doing something fundamentally wrong in defining the classes the way I have ?
在定义我所拥有的类的过程中,我在做根本上错误的事情吗?
EDIT 编辑
Reason I have separate reader and translator is that, they seem to have different jobs, and I could apply more than one translator to the output of one reader (translator 2 and 3 above can be applied to output of reader 2). 我将阅读器和翻译器分开的原因是,它们似乎有不同的工作,我可以将一个以上的翻译器应用于一个阅读器的输出(上面的翻译器2和3可以应用于阅读器2的输出)。
The trouble with your approach is that you've defined a couple methods in which you want to return a different type depending on your input, but that input doesn't have any type information for the compiler to work with. 这种方法的麻烦之处在于,您已经定义了几个方法,根据输入您想返回不同的类型,但是该输入没有供编译器使用的任何类型信息。
Ie your getReader
function needs to act as both a String => Reader[String]
and a String => Reader[Int]
depending on the value (not type !) of the input. 也就是说,取决于输入的值 (不是type !),
getReader
函数需要同时充当String => Reader[String]
和String => Reader[Int]
。 The compiler tries to figure out the common type between those two cases and comes up with String => Reader[Any]
, but then when you try to use that, the loss of the specific type information becomes a problem. 编译器试图找出这两种情况之间的通用类型,并提出
String => Reader[Any]
,但是当您尝试使用它时,特定类型信息的丢失成为一个问题。
I think the best solution to this is to introduce a type parameter on the input side of your method, eg 我认为对此的最佳解决方案是在方法的输入端引入类型参数,例如
case class ReaderName[T](name: String)
// these would be defined as constants on an object somewhere
val ReaderOne = ReaderName[String]("one")
val ReaderTwo = ReaderName[Int]("two")
def getReader[T](readerName: ReaderName[T]): Reader[T] = readerName match {
case ReaderOne => new Reader[String] { ... }
case ReaderTwo => new Reader[Int] { ... }
case _ => throw ...
}
The point here is that you're attaching type information to a name in the form of the [T]
argument on ReaderName
. 这里的重点是您要在
ReaderName
上以[T]
参数的形式将类型信息附加到名称上。 That type information can be used by the compiler to ensure you get a Reader
instance for the appropriate T
type based on the ReaderName
you pass in. 编译器可以使用该类型信息来确保您根据传入的
ReaderName
获得相应T
类型的Reader
实例。
Note that you shouldn't try do this: 请注意,您不应尝试执行以下操作:
getReader(ReaderName[Int]("one")) // no!
because it will likely match ReaderOne
despite having the wrong type parameter (thanks to type erasure on the JVM), and you'll run into ClassCastExceptions down the road. 因为尽管类型参数错误(由于要在JVM上进行类型擦除),它仍可能与
ReaderOne
匹配,并且您将在以后遇到ClassCastExceptions。 You should be defining ReaderName instances as constants, and referencing those constants. 您应该将ReaderName实例定义为常量,并引用这些常量。
A similar approach would be to define the ReaderNames as a sealed trait/abstract class; 一种类似的方法是将ReaderNames定义为密封的特征/抽象类。 doing so would allow you to avoid having to throw IllegalArgumentExceptions, and would help protect against the "no!"
这样做将使您避免不得不抛出IllegalArgumentExceptions,并有助于防止出现“否!”。 example above.
上面的例子。
sealed abstract class ReaderName[T](val name: String)
object ReaderName {
case object One extends ReaderName[String]
case object Two extends ReaderName[Int]
}
def getReader[T](name: ReaderName[T]): Reader[T] = readerName match {
case ReaderName.One => new Reader[String] { ... }
case ReaderName.Two => new Reader[Int] { ... }
// no need for a `case _` becase ReaderName is sealed and we have handled all cases
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.