【发布时间】:2015-11-07 00:07:48
【问题描述】:
我有以下类型:
trait Loader[A, B, C] {
//Any Spark loader requires
// A -> Input Type
// B -> Output Type
// C -> some type of implicit context provided by the compiler from
// the sourounding environment.
def load(input: A)(implicit context: C): B
}
object Loader {
implicit object HiveLoader extends Loader[HiveTableSource, DataFrame, HiveContext] {
def load(source: HiveTableSource)(implicit hc: HiveContext): DataFrame = {
val db = source.db
val tbl = source.tbl
val df = hc.sql(s"select * from $db.$tbl")
df
}
}
def loadDataSource[A,B,C](d: A)(implicit ldr: Loader[A,B,C], context: C):B =
ldr.load(d)
}
sealed trait DataSource
case class HiveTableSource(db: String, tbl: String) extends DataSource
当我尝试以下操作时,代码无法通过“找不到隐式参数 ldr”进行编译
c // this is of type DataSource
import Loader._
loadDataSource(c) //This Fails
但是,如果我明确地强制类型
LoadDataSource(c.asInstanceof[HiveTableSource]) The code compiles.
【问题讨论】:
-
这有什么好惊讶的?
c是DataSource类型;范围内没有Loader[DataSource, ?, ?]的隐式实例;因此,loadDataSource(c)无法编译。对我来说似乎合乎逻辑。 -
在运行时 c 是一个 HiveTableSource,如果添加更多源,则键入为 DataSource。我正在尝试让类型类正确推断子类型,因此我不必使用 asInstanceOf 显式键入
-
c的运行时类型在这里无关紧要。如果您想将它多态地视为DataSource,那么您必须在范围内拥有Load[DataSource, ?, ?]。首先,使用asInstanceOf否定了将其键入为DataSource的好处,并且通常是一种避免的方法。 -
DataSource 是通用的,没有具体的实现。我有子类型的类型类,但不知道如何让 scala 在 'c' 类型为 DataSource 时选择正确的子类型,以便它可以是多态的。
-
这就是我要说的——你不能。隐式参数在编译时选择 - 因此它们必须与
c的编译时类型匹配,而不是其运行时类型。