【发布时间】:2014-03-20 08:13:33
【问题描述】:
我正在尝试在当前应用程序的上下文中创建状态机。下面是我正在尝试做的一个例子。
我已经定义了一系列状态,这些状态将随着应用程序的增长而增长,并且单个状态可以转换为任意数量的其他特征(例如,A 可以转换为 B、C 或 D)。我希望能够对所有状态进行模式匹配,以便在我遗漏任何状态时让编译器警告我。
sealed trait State {
val name: String
}
// can transition to B or C
case class StateA(data: String) extends State{
val name = "A"
}
// can transition to C
case class StateB(data: String) extends State with BuiltFrom[StateA]{
val name = "B"
}
/*
* ISSUE: class StateC inherits different type instances of trait BuiltFrom: BuiltFrom[StateB] and BuiltFrom[StateA]
*/
case class StateC(data: String) extends State with BuiltFrom[StateA] with BuiltFrom[StateB]{
val name = "C"
}
sealed trait BuiltFrom[-State]
// Attempted to use these
// sealed trait FromA extends BuiltFrom[StateA]
// sealed trait FromB extends BuiltFrom[StateB]
我试图使用 BuiltFrom 特征来定义哪些转换是可能的。它的目的是允许编译器阻止我定义一个无效的转换,并在我对转换结果进行模式匹配时警告我,以确定我们现在处于什么状态(而不是只匹配所有状态匹配可能状态的子集)。
abstract class Transition[S <: State, V](state: S) {
// Abstract member to define the transition
protected def trans(s: S, v: V): BuiltFrom[S]
// syntactical sugar
def transition(v: V): BuiltFrom[S] = trans(state, v)
}
上面我已经以这样一种方式定义了转换,对于任何状态 S,唯一可以返回的新状态必须是 BuiltFrom[S] 类型。我还接受一些进行转换所需的数据(通常是 POST 表单数据)。
case class PostedFormData(data: String)
case class TransitionA(a: StateA) extends Transition[StateA, PostedFormData](a) {
def trans(state: StateA, formData: PostedFormData) = {
if (formData.data.length > 0 ){ // for the sake of an example condition
StateB(formData.data)
}
else{
StateC(formData.data)
}
}
}
object TransitionA{
implicit def stateAToTransitionA(s: StateA): TransitionA = TransitionA(s) // implicit conversion
}
上面是一个示例转换。我希望能够返回 BuiltFrom[StateA] 类型的状态。
object Controller {
// Example usage
def action(state: StateA) = {
val form_data = PostedFormData("Some Data")
val new_state: BuiltFrom[StateA] = TransitionA.stateAToTransitionA(state).transition(form_data) // why will the implicit conversion not work here?
// Extract the new state
new_state match {
case b: StateB => {"B"}
case c: StateC => {"C"}
}
}
以上是我想在控制器级别使用转换代码的方式。理想情况下,隐式转换应该可以工作,但重要的是我可以对返回的状态进行模式匹配以确定我所处的新状态。
我遇到的问题是可以从多个状态转换到的状态。我收到以下错误:
StateC 类继承 trait BuiltFrom 的不同类型实例:BuiltFrom[StateB] 和 BuiltFrom[StateA]
我想知道是否有办法解决这个问题。或者,我愿意接受重新设计的建议,以实现相同的目标(尽可能利用编译器对我有利)。
谢谢!
【问题讨论】:
标签: scala