我正在尝试在当前应用程序的上下文中创建状态机。以下是我想要做的一个例子。
我已经定义了一系列状态,这些状态随着应用程序的增长而增长,并且单个状态可以转换为任意数量的其他特征(例如,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特性来定义可能的转换。它的目的是允许编译器阻止我定义无效的Transition,并在我对转换结果进行模式匹配时确认我,以确定我们现在处于什么状态(而不是仅匹配所有状态)匹配可能状态的子集。)
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
}
上面是一个示例Transition。我希望能够返回一个类型为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继承特性的不同类型实例BuiltFrom:BuiltFrom [StateB]和BuiltFrom [StateA]
我想知道是否有办法可以解决这个问题。或者,我愿意接受重新设计的建议,以实现相同的目标(尽可能利用编译器的优势)。
谢谢!