sealed trait Desc {
type T
}
trait Dataset[A] {
def toDS[A] = new Dataset[A] {}
}
trait DataFrame {}
sealed trait DFDesc extends Desc {
type T = Dummy
}
sealed trait DSDesc[A] extends Desc {
type T = A
}
trait JobConstruction {
def apply(desc: Desc): Job[desc.T]
}
sealed trait Job[DescType] {
def description: Desc { type T = DescType }
}
abstract class DSJob[V] extends Job[V] {
def result(con: JobConstruction): Dataset[V]
}
abstract class DFJob extends Job[Dummy] {
def result(con: JobConstruction): DataFrame
}
trait Dummy {}
case class SampleDFDesc() extends DFDesc
case class SampleDFJob(description: SampleDFDesc) extends DFJob {
override def result(con: JobConstruction) = new DataFrame {}
}
case class SampleDSDesc() extends DSDesc[Int]
case class SampleDSJob(description: SampleDSDesc) extends DSJob[Int] {
override def result(con: JobConstruction) = new Dataset[Int] {}
}
object Main {
val sampleConst = new JobConstruction {
override def apply(desc: Desc): Job[desc.T] = desc match {
case desc2: SampleDFDesc => SampleDFJob(desc2)
case desc2: SampleDSDesc => SampleDSJob(desc2)
}
}
}
无法使用
进行编译/tmp/sample.scala:73: error: type mismatch;
found : this.SampleDFJob
required: this.Job[desc.T]
case desc2: SampleDFDesc => SampleDFJob(desc2)
^
/tmp/sample.scala:74: error: type mismatch;
found : this.SampleDSJob
required: this.Job[desc.T]
case desc2: SampleDSDesc => SampleDSJob(desc2)
编辑:
我想让它以某种方式起作用:
case class SampleDepDesc(df: SampleDFDesc) extends DSDesc[Int]
case class SampleDepJob(description: SampleDepDesc) extends DSJob[Int] {
override def result(con: JobConstruction): Dataset[Int] = con(description.df).result(con).toDS[Int]
}
答案 0 :(得分:2)
如果你这样编写sampleConst
,错误就会以更有趣的方式形成:
object Main {
val sampleConst = new JobConstruction {
override def apply(desc: Desc): Job[desc.T] = {
val result = desc match {
case desc2: SampleDFDesc => SampleDFJob(desc2)
case desc2: SampleDSDesc => SampleDSJob(desc2)
}
result
}
}
错误消息变为:
type mismatch;
found : Product with Serializable with main.Job[_ >: main.Dummy with Int]{def description: Product with Serializable with main.Desc{type T >: main.Dummy with Int}}
required: main.Job[desc.T]
Note: Any >: desc.T (and Product with Serializable with main.Job[_ >: main.Dummy with Int]{def description: Product with Serializable with main.Desc{type T >: main.Dummy with Int}} <: main.Job[_ >: main.Dummy with Int]), but trait Job is invariant in type DescType. You may wish to define DescType as -DescType instead. (SLS 4.5)
此消息难以阅读。原因似乎是逆向问题,如第四行所述,但让我们先尝试使这个错误信息可读。
这条消息如此长的原因是Scala正在做很多体操,以便理解所有类型的铸件和遗产。我们将(暂时)扁平化类型层次结构,以便在所有这些中看得更清楚。
此处,中间类SampleDFJob
,SampleDSJob
,SampleDFDesc
和SampleDSDesc
已被删除:
sealed trait Desc {
type T
}
sealed trait DFDesc extends Desc {
type T = Dummy
}
sealed trait DSDesc[A] extends Desc {
type T = A
}
trait JobConstruction {
def apply(desc: Desc): Job[desc.T]
}
sealed trait Job[DescType] {
def description: Desc { type T = DescType }
}
class DSJob[V] extends Job[V]
class DFJob extends Job[Dummy]
trait Dummy {}
object Main {
val sampleConst = new JobConstruction {
override def apply(desc: Desc): Job[desc.T] = {
val result = desc match {
case desc2: DFDesc => new DFJob
case desc2: DSDesc[Int] => new DSJob[Int]
}
result
}
}
}
现在出现错误信息:
type mismatch;
found : main.Job[_1] where type _1 >: main.Dummy with Int
required: main.Job[desc.T]
问题似乎是Scala无法将main.Job[_ >: main.Dummy with Int]
投射到desc.T
。
注意:为什么这种奇怪的类型?那么,result
的泛型类型会有所不同,具体取决于模式匹配的情况(在第一种情况下,我们有Dummy
,在第二种情况下,我们有一个Int
)。由于Scala是静态类型的(至少在编译期间),它将尝试组成一个返回类型,它是所有可能类型的“公分母”(或者更确切地说是父类型)。它找到的最好的东西是_ >: main.Dummy with Int
,它是“在模式匹配中找到的任何类型的父类型的任何类型”(main.Dummy
和Int
)。
我认为此类型无法强制转换为desc.T
的原因是Scala无法在编译时确认返回的类型始终为相同(自{{1 }}是不变的} DescType
。实际上,Job[desc.T]
来自desc.T
或SampleDFDesc.T
,而返回类型将为SampleDSDesc.T
,并且没有任何内容可以保证这两种类型相同(如果DescType
}而不是SampleDSJob
?)
我认为不可能完全按照您尝试的方式进行编码,但您可以尝试... 避开问题:
如果您确定每个案例的返回类型始终与DSJob[String]
的类型相同,那么您可以使用desc.T
指定显式广播,如下所示:
asInstanceOf
当然,这不是类型安全的。
或者,如果您可以设法编写object Main {
val sampleConst = new JobConstruction {
override def apply(desc: Desc): Job[desc.T] = (desc match {
case desc2: SampleDFDesc => SampleDFJob(desc2)
case desc2: SampleDSDesc => SampleDSJob(desc2)
}).asInstanceOf[Job[desc.T]]
}
}
类以便Job
可以是逆变(DescType
),则可以编写-DescType
方法以获得以下内容签名代替:
Job.apply
答案 1 :(得分:0)
这不是一个真正的解决方案,但是您可以使用类型参数替换内部特征类型,此代码编译:
sealed trait Desc[T]
trait Dataset[A]
trait DataFrame
sealed trait DFDesc extends Desc[Dummy]
sealed trait DSDesc[A] extends Desc[A]
trait JobConstruction {
def apply[A](desc: Desc[A]): Job[A]
}
sealed trait Job[A] {
def description: Desc[A]
}
abstract class DSJob[V] extends Job[V] {
def result: Dataset[V]
}
abstract class DFJob extends Job[Dummy] {
def result: DataFrame
}
trait Dummy
case class SampleDFDesc() extends DFDesc
case class SampleDFJob(description: SampleDFDesc) extends DFJob {
def result = new DataFrame {}
}
case class SampleDSDesc() extends DSDesc[Int]
case class SampleDSJob(description: SampleDSDesc) extends DSJob[Int] {
def result = new Dataset[Int] {}
}
val sampleConst = new JobConstruction {
override def apply[A](desc: Desc[A]): Job[A] = desc match {
case desc2: SampleDFDesc => SampleDFJob(desc2)
case desc2: SampleDSDesc => SampleDSJob(desc2)
}
}
至于如何使路径依赖类型起作用,我很好奇。