【问题标题】:how to enfore ADT with same type parameter如何使用相同类型的参数强制执行 ADT
【发布时间】:2017-01-16 13:20:26
【问题描述】:

我有以下 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))

它运行良好,但现在我需要有 2 个单独的类型,1 个使用 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))

我想问几个问题:

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

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

    但它仍然可以正常运行(为 DontCare 案例打印 10)

【问题讨论】:

    标签: scala generics domain-driven-design algebraic-data-types


    【解决方案1】:

    我认为你所拥有的是正确的。我建议你一起定义你的 ADT(现在你有 EventDontCare 单独定义)。此外,由于基本特征 Event 没有 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 Type Erasure 会导致问题吗?
    猜你喜欢
    • 1970-01-01
    • 2020-05-12
    • 2020-10-27
    • 2017-04-18
    • 2019-09-21
    • 1970-01-01
    • 1970-01-01
    • 2016-08-13
    • 2021-04-02
    相关资源
    最近更新 更多