Создание неизменных экземпляров и изменение копий идиоматическим способом
Я хотел бы условно создавать копии экземпляра объекта в зависимости от информации, внешней по отношению к этому экземпляру. Большая часть информации в копиях будет такой же, как и оригинал, но часть информации потребуется изменить. Эта информация передается между актерами, поэтому мне нужно, чтобы объекты были неизменяемыми, чтобы избежать странного поведения, связанного с параллелизмом. Следующий игрушечный код - простой пример того, с чем я хотел бы помочь.
Если у меня есть следующий код:
case class Container(condition:String,amount:Int,ID:Long)
Я могу сделать следующее:
val a = new Container("Hello",10,1234567890)
println("a = " + a)
val b = a.copy(amount = -5)
println("b = " + b)
println("amount in b is " + b.amount)
и вывод
a = Container(Hello,10,1234567890)
b = Container(Hello,-5,1234567890)
amount in b is -5
Я также могу условно создавать копии объекта, выполняя следующие действия:
import scala.Math._
val max = 3
val c = if(abs(b.amount) >= max) b.copy(amount = max,condition="Goodbye") else if(abs(b.amount) < max) b.copy(amount = abs(b.amount))
println("c = " + c)
Если я установлю сумму в объекте b на -5, то результат будет
c = Container(Goodbye,3,1234567890)
и если я установлю сумму в объекте b на -2, то вывод
c = Container(Hello,2,1234567890)
Однако, когда я пытаюсь распечатать c.amount, он помечается компилятором следующим сообщением
println("amount in c is " + c.amount)
значение суммы не является членом Any
Если я изменю строку создания объекта c на
val c:Container = if(abs(b.amount) >= max) b.copy(amount = max,condition="Goodbye") else if(abs(b.amount) < max) b.copy(amount = abs(b.amount))
Я получаю ошибку компилятора
несоответствие типов; найдено: требуется блок: контейнер
Каков лучший идиоматический способ условного создания неизменяемых экземпляров классов дел путем копирования существующих экземпляров и изменения значения или двух?
Спасибо брюс
1 ответ
Вы не включаете финал else
пункт. Таким образом, тип c
является Any
- единственный тип, который является супертипом обоих Container
а также Unit
, где Unit
является результатом не включая всеобъемлющее else
оговорка Если вы попытаетесь заставить тип результата быть Container
, написав c: Container =
Теперь компилятор сообщает вам, что пропал без вести else
оговорка, приводящая к Unit
не присваивается Container
,
таким образом
val c = if (abs(b.amount) >= max) {
b.copy(amount = max, condition = "Goodbye")
} else if (abs(b.amount) < max) {
b.copy(amount = abs(b.amount))
} else b // leave untouched !
работает. Компилятор не достаточно умен, чтобы понять, что последний else
пункт не может быть достигнут логически (нужно знать, что abs
а также >=
а также <
означает, что они являются взаимоисключающими и исчерпывающими, и что abs
чисто функциональный, как есть b.amount
).
Другими словами, поскольку вы знаете, что эти два предложения являются взаимоисключающими и исчерпывающими, вы можете упростить
val c = if (abs(b.amount) >= max) {
b.copy(amount = max, condition = "Goodbye")
} else { // i.e. abs(b.amount) < max
b.copy(amount = abs(b.amount))
}