Вот пример какого-то кода, над которым я работал, использует подход, позволяющий напрямую возвращать копию, а не мутировать состояние.Приятная вещь в этом виде подхода, по крайней мере на стороне сервера, заключается в том, что он позволяет мне легко реализовать семантику типа транзакции. Если что-то пойдет не так, когда вы делаете обновление, для меня тривиально иметь все, что было обновлено в согласованном состоянии.
Код, приведенный ниже, с игрового сервера, над которым я работаю, что делает что-то похожее на то, что вы делаете, это для отслеживания объектов, которые перемещаются во временных срезах. Этот подход не столь впечатляющий, как предлагает Дейв Гриффит, но он может быть полезен вам для созерцания.
case class PosController(
pos: Vector3 = Vector3.zero,
maxSpeed: Int = 90,
velocity: Vector3 = Vector3.zero,
target: Vector3 = Vector3.zero
) {
def moving = !velocity.isZero
def update(elapsed: Double) = {
if (!moving)
this
else {
val proposedMove = velocity * elapsed
// If we're about to overshoot, then stop at the exact position.
if (proposedMove.mag2 > pos.dist2(target))
copy(velocity = Vector3.zero, pos = target)
else
copy(pos = pos + proposedMove)
}
}
def setTarget(p: Vector3) = {
if (p == pos)
this
else {
// For now, go immediately to max velocity in the correct direction.
val direction = (p - pos).norm
val newVel = direction * maxSpeed
copy(velocity = direction * maxSpeed, target = p)
}
}
def setTargetRange(p: Vector3, range: Double) = {
val delta = p - pos
// Already in range?
if (delta.mag2 < range * range)
this
else {
// We're not in range. Select a spot on a line between them and us, at max range.
val d = delta.norm * range
setTarget(p - d)
}
}
def eta = if (!moving) 0.0 else pos.dist(target)/maxSpeed
}
Одна хорошая вещь о конкретных классов в Scala является то, что они создают метод копирования() для you-- просто пройти, в котором параметры изменились, а другие сохраняют ту же величину. Вы можете закодировать это вручную, если вы не используете классы case, но вам нужно помнить об обновлении метода копирования всякий раз, когда вы меняете значения, присутствующие в классе.
Что касается ресурсов, то для меня действительно что-то изменилось, когда я проводил время в Эрланге, где в принципе нет выбора, кроме как использовать неизменяемое состояние. У меня есть две книги Эрланг, над которыми я работал, и внимательно изучил каждый пример. Это, плюс, заставляя меня кое-что сделать в Erlang, сделало меня намного более удобным с работой с неизменяемыми данными.
Общее согласие (среди всех ответов) состоит в том, чтобы просто создавать копии моих объектов, которые представляют текущее состояние. Это не совсем то, что я искал, но вот этот ответ представляет собой действительно интересную пищу для размышлений, такую как определение итераторов, которые выражают, как изменяются ценности (а не выражают состояние ценностей) ... Я надеялся на ответ, который найти какой-то способ выразить позицию как некоторую функцию (или итерацию), которая выражает изменение переменной (вроде интеграла в исчислении). Спасибо, что ввел меня в классные вещи! – jtb