如何使用特定元组限制类类型参数? (斯卡拉2.10.4)

时间:2015-01-26 11:57:15

标签: scala templates tuples

我想限制类型[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等的子类型不太好。

1 个答案:

答案 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 "}