2011-04-05 21 views
0

我想根据外部信息有条件地创建对象实例的副本。副本中的大部分信息与原始信息相同,但有些信息需要更改。这些信息是在角色之间传递的,所以我需要这些对象是不可变的,以避免奇怪的并发相关行为。下面的玩具编码就是我希望得到一些帮助的一个简单例子。以惯用的方式创建不可变实例并修改副本

如果我有以下代码:

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) 

值量没有任何

成员如果我改变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)) 

我得到的编译器错误

类型不匹配;发现:单位要求: 集装箱

什么是有条件通过复制现有的实例,并修改或两个创造价值的情况下,类不变情况下,最好的,惯用的方法是什么?

感谢, 布鲁斯

回答

12

你不包括最后的else条款。因而c类型是Any - 也就是超型两者的ContainerUnit,其中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)) 
} 
+0

谢谢,这工作 – 2011-04-05 16:53:00

相关问题