通过参数确定要更改的成员

时间:2015-01-22 13:13:17

标签: scala parameters pass-by-reference pass-by-name

遵循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
  }
}

由于undo / redo非常相似,我想将公共代码提取到一个函数中,我希望将源/目标对传递为redoState / undoState,反之亦然

有没有办法告诉函数应该在哪里存储什么? (在C ++中,我会在这种情况下传递指向成员的指针)。

3 个答案:

答案 0 :(得分:1)

使用返回值:

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的{​​{1}}成员:

Box

答案 1 :(得分:1)

您可以创建并传递函数来设置新状态(撤消或重做):

...
var undoState = Seq[UndoState]()
var redoState = Seq[UndoState]()

def anywaydo(set: (Seq[UndoState]) => Unit) {
  set(...)
  ...
}

def undo {
  anywaydo((state) => undoState = state)
}

答案 2 :(得分:1)

你可以使你的状态(可变)堆栈而不是(不可变的)seqs,并将它们传递给一个共同的函数进行操作:

  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”功能,您可以通过以下方式以有趣的方式执行此操作:

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            
    }
  }

然后,您可以执行undoState -> redoState为“撤消”或redoState -> undoState为“重做”......