【发布时间】:2015-04-19 17:35:54
【问题描述】:
我正在创建一个 map-reduce 框架,现在我正在尝试创建一个构建器类来实例化处理管道。此构建器需要保存用户指定的函数列表,以便稍后它可以使用这些函数作为参数来构造管道以实例化 Worker 对象。
我正在使用案例类来创建函数“持有者”,也为“工人”创建函数。我的问题是,当我继续分析持有者时,如果我对它们进行模式匹配,则函数中的类型信息似乎由于类型擦除而丢失。这是一些似乎可以重现我遇到的问题的最小代码。
trait Holders
case class MapHolder[A, B](f: A => B) extends Holders
trait Worker
case class MapWrk[A, B](f: A => B) extends Worker
object MyTypeErasureProblem extends App {
val myFunc = MapHolder((x: Int) => x + 10)
def buildWorker(hh: Holders) =
hh match {
case MapHolder(f) => MapWrk(f)
}
println(buildWorker(myFunc).f(10))
}
编译错误是
Error:(22, 35) type mismatch;
found : Nothing => Any
required: A => Any
case MapHolder(f) => MapWrk(f)
^
Error:(26, 33) type mismatch;
found : Int(10)
required: Nothing
println(buildWorker(myFunc).f(10))
^
如果我们这样定义buildWorker,问题就可以解决:
def buildWorker[A,B](hh: MapHolder[A,B]) = ...
但我需要处理不同类型的Holders,包括
case class ReduceHolder[V](f: (V,V) => V) extends Holders
顺便说一句,它在类似的代码中工作得很好,根本没有错误或警告。事实上,只有泛型类型A=>B 似乎是一个问题,因为函数参数变成Nothing,传递具有其他泛型类型的对象工作,例如Tuple2[A,B].
在我看来,这似乎是一个与类型擦除有关的问题,但我该如何解决呢?我已经尝试ClassTag所有的东西,但它没有工作。
更多信息
这是 Travis 建议的方法的更新,在 Holder 中使用 buildWorker 方法。
这就是我需要的方式:
case class DataHolder[T](f: T) {
def buildWorker() = DataWrk[T](f)
}
case class DataWrk[T](f: T)
object MyTypeErasureProblem2 extends App {
val pipeline = List(
DataHolder[Int](10).buildWorker(),
DataHolder[String]("abc").buildWorker()
)
val result = pipeline collect {
case DataWrk(f: Int) => "Int data"
case DataWrk(f: String) => "String data"
}
result foreach println
}
输出:
Int data
String data
但是如果我们使用函数类型,它就不再起作用了:
case class MapHolder[T](f: T => T) {
def buildWorker() = MapWrk[T](f)
}
case class MapWrk[T](f: T => T)
object MyTypeErasureProblem extends App {
val pipeline = List(
MapHolder[Int]((x: Int) => x + 10).buildWorker(),
MapHolder[String]((x: String) => x + "abc").buildWorker()
)
val result = pipeline collect {
case MapWrk(f: (Int => Int)) => "Int endofunction"
case MapWrk(f: (String => String)) => "String endofunction"
}
result foreach println
}
输出:
Int endofunction
Int endofunction
当我们尝试匹配实例化的Workers 时,第一个case 始终匹配。
【问题讨论】:
-
你能在
Holders上放一个抽象的buildWorker: Workers方法吗? -
我可以,实际上,但我认为这不能解决问题。我仍然需要类似
buildWorker的函数来处理Holders 的列表,但是当我们到达可以调用hh.buildWorker方法的代码部分时,它们的类型已经丢失。我尝试了类似的方法,但是我们必须将持有者与MapHolder[Any,Any]匹配,例如,这似乎把事情搞砸了(我无法对生成的MapWkrs 进行模式匹配)。 -
你不需要匹配
MapHolder,但是它对buildWorker的实现可以做正确的事情。如果buildWorker的返回类型是Workers,则没有可丢失的类型。 -
看来你需要硬着头皮在你的特质上加上一些类型参数。
-
更新了我的答案以涵盖更新后的问题。
标签: scala pattern-matching type-erasure