通过参数确定要更改的成员
Determine by parameter which member to change
以下 Scala 代码给出了一个编译错误,指出我无法分配给一个 val:
简化示例:
class State {
val a = 1
val b = 2
def compute( res: =>Int, add : Int ): Unit = {
res = add + 123456
}
compute(a,b)
compute(b,a)
}
更接近我实际使用的例子:
class Editor {
var str:String = ""
var cursor:Int = 0
case class UndoState(str:String, cursor:Int)
var undoState = Seq[UndoState]()
var redoState = Seq[UndoState]()
def undo(): Unit = if (undoState.nonEmpty) {
redoState = UndoState(str,cursor) +: redoState
str = undoState.head.str
cursor = undoState.head.cursor
undoState = undoState.tail
}
def redo(): Unit = if (redoState.nonEmpty) {
undoState = UndoState(str,cursor) +: undoState
str = redoState.head.str
cursor = redoState.head.cursor
redoState = redoState.tail
}
}
由于撤消/重做非常相似,我想将通用代码提取到一个函数中,我想将源/目标对作为 redoState
/undoState
传递,另一个绕过去。
有什么方法可以告诉函数应该在哪里存储东西吗? (在 C++ 中,我会在这种情况下传递一个指向成员的指针)。
使用 return 值:
def compute( add : Int ): Int = {
add + 123456
}
val a = compute(b)
val b = compute(a)
像在 C++ 中那样通过引用传递在 Scala 中无法做到,而且通常也不是您想做的。但是,您可以传递包含对可变字段的引用的容器:
class Box(var value: Int)
def compute( box: Box, add : Box): Unit = {
box.value = add.value + 123456
}
val a = new Box(1)
val b = new Box(2)
compute(a, b)
compute(b, a)
或(略有不同)使 compute
成为 Box
的成员:
class Box(var value: Int) {
def compute(add: Box): Unit = {
value = add.value + 123456
}
}
val a = new Box(1)
val b = new Box(2)
a.compute(b)
b.compute(a)
您可以创建并传递函数来设置新状态(撤消或重做):
...
var undoState = Seq[UndoState]()
var redoState = Seq[UndoState]()
def anywaydo(set: (Seq[UndoState]) => Unit) {
set(...)
...
}
def undo {
anywaydo((state) => undoState = state)
}
您可以使您的状态(可变)堆栈而不是(不可变)序列,并将它们传递到一个通用函数中进行操作:
def undoredo(states: (Stack[UndoState], Stack[UndoState])): Unit = states match {
case (Stack(), _) => ()
case (from, to) =>
to.push(UndoState(str,cursor))
val state = from.pop
str = state.str
cursor = state.cursor
}
def undo() = undoredo(undoState -> redoState)
def redo() = undoredo(redoState -> undoState)
或者,如果您喜欢 scala 的奇特 "DSL-like" 功能,您可以通过以下方式以有趣的方式做到这一点:
implicit class StateStack(from: Stack[UndoState]) {
def ->(to: Stack[UndoState]): Unit = if(from.nonEmpty) {
to.push(UndoState(str,cursor))
val state = from.pop
str = state.str
cursor = state.cursor
}
}
然后,您可以对 "undo" 执行 undoState -> redoState
或对 "redo" 执行 redoState -> undoState
...
以下 Scala 代码给出了一个编译错误,指出我无法分配给一个 val:
简化示例:
class State {
val a = 1
val b = 2
def compute( res: =>Int, add : Int ): Unit = {
res = add + 123456
}
compute(a,b)
compute(b,a)
}
更接近我实际使用的例子:
class Editor {
var str:String = ""
var cursor:Int = 0
case class UndoState(str:String, cursor:Int)
var undoState = Seq[UndoState]()
var redoState = Seq[UndoState]()
def undo(): Unit = if (undoState.nonEmpty) {
redoState = UndoState(str,cursor) +: redoState
str = undoState.head.str
cursor = undoState.head.cursor
undoState = undoState.tail
}
def redo(): Unit = if (redoState.nonEmpty) {
undoState = UndoState(str,cursor) +: undoState
str = redoState.head.str
cursor = redoState.head.cursor
redoState = redoState.tail
}
}
由于撤消/重做非常相似,我想将通用代码提取到一个函数中,我想将源/目标对作为 redoState
/undoState
传递,另一个绕过去。
有什么方法可以告诉函数应该在哪里存储东西吗? (在 C++ 中,我会在这种情况下传递一个指向成员的指针)。
使用 return 值:
def compute( add : Int ): Int = {
add + 123456
}
val a = compute(b)
val b = compute(a)
像在 C++ 中那样通过引用传递在 Scala 中无法做到,而且通常也不是您想做的。但是,您可以传递包含对可变字段的引用的容器:
class Box(var value: Int)
def compute( box: Box, add : Box): Unit = {
box.value = add.value + 123456
}
val a = new Box(1)
val b = new Box(2)
compute(a, b)
compute(b, a)
或(略有不同)使 compute
成为 Box
的成员:
class Box(var value: Int) {
def compute(add: Box): Unit = {
value = add.value + 123456
}
}
val a = new Box(1)
val b = new Box(2)
a.compute(b)
b.compute(a)
您可以创建并传递函数来设置新状态(撤消或重做):
...
var undoState = Seq[UndoState]()
var redoState = Seq[UndoState]()
def anywaydo(set: (Seq[UndoState]) => Unit) {
set(...)
...
}
def undo {
anywaydo((state) => undoState = state)
}
您可以使您的状态(可变)堆栈而不是(不可变)序列,并将它们传递到一个通用函数中进行操作:
def undoredo(states: (Stack[UndoState], Stack[UndoState])): Unit = states match {
case (Stack(), _) => ()
case (from, to) =>
to.push(UndoState(str,cursor))
val state = from.pop
str = state.str
cursor = state.cursor
}
def undo() = undoredo(undoState -> redoState)
def redo() = undoredo(redoState -> undoState)
或者,如果您喜欢 scala 的奇特 "DSL-like" 功能,您可以通过以下方式以有趣的方式做到这一点:
implicit class StateStack(from: Stack[UndoState]) {
def ->(to: Stack[UndoState]): Unit = if(from.nonEmpty) {
to.push(UndoState(str,cursor))
val state = from.pop
str = state.str
cursor = state.cursor
}
}
然后,您可以对 "undo" 执行 undoState -> redoState
或对 "redo" 执行 redoState -> undoState
...