Scala 如何使用相同的类型参数实施ADT

Scala 如何使用相同的类型参数实施ADT,scala,generics,domain-driven-design,algebraic-data-types,Scala,Generics,Domain Driven Design,Algebraic Data Types,我有以下ADT: sealed trait Event case class EventA(id: Int) extends Event case class EventB(id: Int) extends Event case object EventDontCare extends Event object Event { def test(ev: Event) = ev match { case EventA(x) => x case EventB(y)

我有以下ADT:

sealed trait Event
case class EventA(id: Int) extends Event
case class EventB(id: Int) extends Event
case object EventDontCare extends Event

object Event {
  def test(ev: Event) = ev match {
    case EventA(x)     => x
    case EventB(y)     => y + 1
    case EventDontCare => 0
  }
}

val eva = EventA(10)
println(Event.test(eva))
它工作得很好,但是现在我需要有两个独立的类型,一个使用Int作为上面的id,另一个使用String作为id。 我已尝试将类型参数添加到事件特征:

sealed trait GEvent[ID]
case class GEventA[ID](id: ID) extends GEvent[ID]
case class GEventB[ID](id: ID) extends GEvent[ID]

object EventInt {
  type Event = GEvent[Int]
  type EventA = GEventA[Int]
  type EventB = GEventB[Int]
  case object EventDontCare extends GEvent[Int]

  def test(ev: Event) = ev match {
    case x: EventA     => x.id
    case y: EventB     => y.id + 1
    case EventDontCare => 0
  }
}
object EventString {....}

val evi = new EventInt.EventA(10)
val evii = GEventA[Int](10)
val evd = EventInt.EventDontCare
println(EventInt.test(evd))
println(EventInt.test(evi))
println(EventInt.test(evii))
我想问几个问题:

是否有更好的方法将类型注入ADT的所有成员?我对上述方法不满意。 在测试方法中的模式匹配中,为什么不能使用case EventAx=>或事件case GEventA[Int]x=>? 同样,为什么我必须用new关键字创建evi变量? 即使我已经涵盖了所有3种情况,为什么编译器仍然警告我:

匹配可能并不详尽。它将在以下输入上失败: EventDontCare

但它仍然正确运行,为DontCare案例打印10


我认为你说的是对的。我建议您一起定义ADT,现在您已经分别定义了EventDont。此外,由于基本trait事件没有id,因此在那里强制类型是没有意义的。因此,我会将您的ADT改写为:

sealed trait Event
case class GEventA[ID](id: ID) extends Event
case class GEventB[ID](id: ID) extends Event
case object EventDontCare extends Event
模式匹配可以这样重新编写,以包括成员上的类型

def test(ev: Event) = ev match {
   case GEventA(id:Int) => id
   case GEventB(id:Int) => id + 1
   case EventDontCare   => 0
}
输入这个,我没有得到你提到的警告

最后,您观察到的类型别名是Scala中的工作方式。如果为案例类定义类型别名,则在不使用new的情况下,无法使用别名定义实例

可选部分

这里是ADT的另一种定义,它将id与其他实体解耦

sealed trait Event
case object GEventA extends Event
case object GEventB extends Event
case object EventDontCare extends Event
case class IdEvent[A, E <: Event](id: A, e: E) extends Event

这里的好处是,您不会因为id的详细信息而污染您的所有实体。

Humm类型的擦除会导致问题吗?