【发布时间】:2019-02-15 03:36:46
【问题描述】:
实际问题:
让我们想象一下,一家奇观馆的客户预订了一场音乐会。
音乐会的一些门票有座位。
客户带来了配偶。
限制:
1. 双方客户的票和对应配偶的票是就座 或 两者都是没有坐下。
如何在类型级别施加此限制?
我最初的想法:
case class Ticket[S <: Option[String]](id: String, seat: S)
case class ConcertReservation[A <: Option[String]](userTicket: Ticket[A],
spouseTicket: Ticket[A])
val concertReservation =
ConcertReservation(
userTicket = Ticket(id = "id1", seat = Some("<seatId>")),
spouseTicket = Ticket(id = "id2", seat = None)
)
我想通过 ConcertReservation[A] 上的类型参数 A 来强加 userTicket 和配偶Ticket 必须是同一类型。
这样做可以让编译器捕捉到上述违反限制的行为:
Error:(12, 26) type mismatch;
found : .....Temp.Ticket[Some[String]]
required: .....Ticket[Option[String]]
Note: Some[String] <: Option[String], but class Ticket is invariant in type S.
You may wish to define S as +S instead. (SLS 4.5)
userTicket = Ticket(id = "id1", seat = Some("assad")),
但有可能克服这一点。例如下面的代码(编译):
val concertReservation2: ConcertReservation[Option[String]] =
ConcertReservation(
userTicket = Ticket(id = "id1", seat = Some("assad")),
spouseTicket = Ticket(id = "id2", seat = None)
)
有没有一种惯用的方法来实现我想要的?也许是某种“模式”?
谢谢,
【问题讨论】:
-
也许你应该使用
assert?写在ConcertReservation的正文中验证逻辑assert((userTicket.nonEmpty && spouseTicket.nonEmpty) || (userTicket.isEmpty && spouseTicket.isEmpty)) -
这在实践中是可行的。感谢您回答的麻烦。但是,我正在寻找类型级解决方案。可以在编译时验证。
-
另外,您可以使用 Some+Some 和 None+None 保留创建
ConcertReservation的两个子类型,并使ConcertReservation抽象和密封(如 Option 及其子类 Some 和 None)。 -
如果你想要一个类型限制改变 ConcertReservation 类型参数为 [A <: some threre option onyl>