Создание неизменных экземпляров и изменение копий идиоматическим способом - PullRequest
0 голосов
/ 05 апреля 2011

Я хотел бы условно создать копии экземпляра объекта в зависимости от информации, внешней по отношению к этому экземпляру.Большая часть информации в копиях будет такой же, как и оригинал, но часть информации необходимо будет изменить.Эта информация передается между актерами, поэтому мне нужно, чтобы объекты были неизменяемыми, чтобы избежать странного поведения, связанного с параллелизмом.Следующий игрушечный код - простой пример того, с чем мне бы хотелось помочь.

Если у меня есть следующий код:

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)

значение value не является членом 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 Ответ

12 голосов
/ 05 апреля 2011

Вы не включили окончательное предложение 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))
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...