我想限制类型[R]只包含在某处列出的特定元组。我的主要目标是:确保编译器在任何其他元组而不是其中一个元组传递给以下特征时引发错误。
trait QV_Storable[R <: QV_Cue] {
val prefix: String
val tableName = prefix.concat(Random.alphanumeric take 8 mkString)
def Make(rows: Iterable[R.storageColumns]): String
}
然后我确实QV_Storable
只接受SegmentCue
中列出的元组,因为它是QV_Cue
的副图。请注意我将R.storageColumns
传递给Make(rows: Iterable[R.storageColumns])
。因此,我确实希望有一种方法来访问类类型的参数。
trait QV_Cue{
type storageColumns <: Product
type metaColumns <: Product
}
object SegmentCue extends QV_Cue {
type storageCols = (CoreDataID, String)
type metaCols = (Int, String, Date, Int)
}
无论如何都有这样限制吗? 来自Tuple1,Tuple3等的子类型不太好。
答案 0 :(得分:3)
您可以提供一个类型类,只有足够的元组实现:
trait Ok[T] {}
// (Int, Int) is Ok
implicit val tupleIntIntOk: Ok[(Int, Int)] = new Ok[(Int, Int)] {}
// (String, _) is Ok too
implicit def tupleStringAOk[A]: Ok[(String, A)] = new Ok[(String, A)] {}
trait QV_Storable[R] {
def method(implicit rok: Ok[R]): Unit
// ...
}
在此方案中,如果范围中没有正确类型的QV_Storable.method
值,则无法调用rok
。
通过这种方式,您可以使用任何R
创建QV_Storable,但如果没有正确的Ok
,则无法实际使用任何内容。
有点不同的方法是在类型级别上制作类似的技巧。然而,没有隐含的决议:
sealed trait Ok[T] {}
case class TupleIntIntOk() extends Ok[(Int, Int)]
case class TupleStringAOk[A]() extends Ok[(String, A)]
trait QV_Storable[R, OkR <: Ok[R]] {
val prefix: String
// ...
}
// compiles
val foo = new QV_Storable[(Int, Int), TupleIntIntOk] { val prefix = "xy" }
// doesn't
val bar = new QV_Storable[(Int, String), /* nothing to put here */] { val prefix = "bar "}