假设我们有以下类型:
sealed trait T
case object Goat extends T
case object Monk extends T
case object Tiger extends T
现在,您如何构建
T
的集合?使得每个子项中至少有一个 T
出现在集合中,此约束在编译时强制执行?与此相反的集合:val s:Seq[T] = Seq(Goat)
编译,这个:
val ts:TotalSeq[T] = TotalSeq(Goat, Goat, Tiger)
才不是。我在上面使用过 Scala,但我也很乐意看到其他语言的解决方案。
(如果我的话有点不对,请原谅我;我感冒了,今天正在用拼图自娱自乐。)
最佳答案
它看起来像具有通用类型约束的构建器模式:http://www.tikalk.com/java/blog/type-safe-builder-scala-using-type-constraints
就像是:
sealed trait TBoolean
sealed trait TTrue extends TBoolean
sealed trait TFalse extends TBoolean
class SeqBuilder[HasGoat <: TBoolean, HasMonk <: TBoolean, HasTiger <: TBoolean] private (seq: Seq[T]) {
def +=(g: Goat.type) = new SeqBuilder[TTrue, HasMonk, HasTiger](g +: seq)
def +=(m: Monk.type) = new SeqBuilder[HasGoat, TTrue, HasTiger](m +: seq)
def +=(t: Tiger.type) = new SeqBuilder[HasGoat, HasMonk, TTrue](t +: seq)
def build()(implicit evg: HasGoat =:= TTrue, evm: HasMonk =:= TTrue, evt: HasTiger =:= TTrue) = seq
}
object SeqBuilder {
def apply = new SeqBuilder(Seq())
}
用法:
scala> SeqBuilder() + Goat + Tiger + Monk build()
res21: Seq[T] = List(Monk, Tiger, Goat)
scala> SeqBuilder() + Goat + Goat + Monk build()
<console>:34: error: Cannot prove that Nothing =:= TTrue.
SeqBuilder() + Goat + Goat + Monk build()
^
如果您想要的实例数量增加,您可以尝试使用 HMap
其他类似方法:幻影类型:http://james-iry.blogspot.com/2010/10/phantom-types-in-haskell-and-scala.html
另一种方法是询问为什么需要所有 3 个对象。假设您想在 seq 具有所有三个时进行操作,那么您可以执行以下操作:
object SeqBuilder {
val all = Seq(Goat, Monk, Tiger)
def apply(t: T*)(onAll: Seq[T] => Unit)(onViolation: => Unit) = {
val seq = Seq(t:_*)
if(all forall seq.contains) onAll(seq)
else onViolation
}
}
这样,如果没有提供所有必需的 Ts,则不会调用 onAll 函数,否则调用违规函数
关于scala - Total Collections,拒绝不包括所有可能性的类型的集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6216385/