所有人!
我在Scala模式匹配方面有一些问题。我正在为我的Web应用程序使用Korolev框架,但是我认为问题仍然存在于Scala中。
我对所有州都有基本特征:
trait BaseState {
val notifications: List[Notification]
}
以及两个派生的案例类:
case class GuestState(
notifications: List[Notification] = List(),
isRegistration: Boolean = false
) extends BaseState
和
case class AuthenticatedState(
notifications: List[Notification] = List(),
user: UserWithPermissions
) extends BaseState
在事件处理程序之一中,我需要获得类似的状态而无需任何通知。现在,它像这样工作:
event('click) { access =>
access.transition {
case s: GuestState => s.copy(notifications = notifications.filter(x => x != n))
case s: AuthenticatedState => s.copy(notifications = notifications.filter(x => x != n))
}
}
对于这两种类型,我必须对代码进行完全相同的操作,因为BaseState
没有copy()
方法,并且编译器会因错误而失败。
如何在scala-way中正确执行?谢谢。
答案 0 :(得分:2)
这两种情况实际上并没有做同样的事情,因为两种copy
方法具有不同的签名。因此,尽管从文本上看可能是相同的,但是代码实际上在每种情况下都做不同的事情。
这里的一个选项是向特征添加一个抽象的filterNotifications
方法并调用它:
trait BaseState {
val notifications: List[Notification]
def filterNotifications(f: Notification => Boolean): BaseState
}
case class GuestState(
notifications: List[Notification] = List(),
isRegistration: Boolean = false
) extends BaseState {
def filterNotifications(f: Notification => Boolean): BaseState =
this.copy(notifications=notifications.filter(f))
}
case class AuthenticatedState(
notifications: List[Notification] = List(),
user: UserWithPermissions
) extends BaseState {
def filterNotifications(f: Notification => Boolean): BaseState =
this.copy(notifications=notifications.filter(f))
}
答案 1 :(得分:2)
过去,我有类似的情况,但从来没有找到一个真正优雅的解决方案,因为具有相同或相似签名的复制方法无法轻松地以多态方式表示。
我通常在特征和案例类中添加一些内容,以使重复至少在一个地方:
trait BaseState {
type ThisType <: BaseState
val notifications: List[Notification]
def withNotifications(notifications: List[Notification]): ThisType
}
case class GuestState(notifications: List[Notification] = List(),
isRegistration: Boolean = false) extends BaseState {
type ThisType = GuestState
def withNotifications(notifications: List[Notification]): ThisType =
copy(notifications = notifications)
}
case class AuthenticatedState(notifications: List[Notification] = List(),
user: UserWithPermissions) extends BaseState {
type ThisType = AuthenticatedState
def withNotifications(notifications: List[Notification]): ThisType =
copy(notifications = notifications)
}
这与理想情况相去甚远,也许还有更好的模式。
但是,如果您像示例中那样大量使用逻辑,则至少会大大减少样板。如果还重复使用了过滤器逻辑,则可以在基本特征中添加更具体的filterNotififications
。
与其他答案相比,该解决方案的优势在于您在过滤时不会损失类型精度。
记住要尽可能地密封特质。
答案 2 :(得分:2)
不改变基本特征就无法解决。显然,编译器不允许您对特征执行操作copy
。
一种方法是在其他回答中建议在BaseState上指定映射/过滤功能。
另一种方法是用组合替换继承:
case class Notified(state: BaseState, notifications: List[Notification] = List())
sealed trait BaseState
case class GuestState(isRegistration: Boolean = false) extends BaseState
case class AuthenticatedState(user: UserWithPermissions) extends BaseState
val notified = Notified(GuestState())
val result = notified.copy(notifications = notifications.filter(_ => true))