Scala“或”在通用范围内

时间:2017-05-21 21:47:59

标签: scala

我知道我可以这样写:

case class Something[T <: Foo with Bar](state: T)

这接受具有特征(或类和特征)FooBar的类。这是一个AND示例,需要扩展FooBar。是否有一个选项允许我传递扩展FooBar的类以模式匹配它们?

用例是我有多个具有不同行为的类,它们使用共享类型的状态:

trait FooState
trait BarState
trait BazState

case class Foo(state: FooState) // must not accept BarState or BazState
case class Bar(state: BarState) // must not accept FooState or BazState
case class Baz(state: BazState) // must not accept FooState or BarState

case class FooBar(state: FooState or BarState) // must not accept BazState
case class FooBaz(state: FooState or BazState) // must not accept BarState
case class BarBaz(state: BarState or BazState) // must not accept FooState

我知道我可以为每个复合类创建另一个特征,但这会迫使我将它添加到扩展任何这些先前特征的所有内容中。

2 个答案:

答案 0 :(得分:3)

是的,你通常会使用类型类来实现你想要的,以及一个上下文绑定。以下是:

trait Acceptable
object Acceptable {
  implicit val fooIsGood = new Acceptable[Foo] {}
  implicit val barIsGood = new Acceptable[Bar] {}
}

case class Something[T : Acceptable](state: T)

您可以使用它来实现使用此模式所需的任何功能。使用Either或联合产品实现真正的联合类型绑定,但在大多数情况下,这可能更简单。

答案 1 :(得分:1)

一种可能的方法是使用Either类型:

case class FooBar(state: Either[FooState, BarState]) {
  def someOperation() = {
    state match {
      case Left(fooState) => ???
      case Right(barState) => ???
    }
  }
}

您所描述的是一种工会类型。 Scala的当前版本不支持它们,因为您已经对它们进行了描述,但是它计划用于Dotty。

如果您需要更多的灵活性(例如,超过两种类型),请考虑使用函数式编程库中的Coproduct。 Scalaz,Cats和Shapeless都暴露了它们。