是否可以交换构造函数的参数? 请考虑以下示例:
case class Foo(a:Int, b:Int) {
if (a > b) {
val tmp = a
a = b
b = tmp
}
}
编译器抛出错误,因为我在第4行重新分配给val a
,这非常好。但是,我需要不可变对象。因此,将a
和b
声明为变量不是一种选择。
有没有已知的模式如何解决这个问题?
答案 0 :(得分:4)
制作内部交换方法:
case class Foo(a: Int, b: Int) {
def ifSwap = if (a > b) Foo(b, a) else this
}
val f1 = Foo(1,2).ifSwap // the result is Foo(1,2)
val f2 = Foo(2,1).ifSwap // the result is Foo(1,2)
如果你想保留不变性然后改变状态,你需要在每次修改时返回新实例,或者使用一些核心方式,如Lenses,State,
Records等......正如奥德斯基教授在SD'13谈话中所说,有些情况下你不应该害怕vars
答案 1 :(得分:3)
我想你想要实现的是Foo
的每个实例都订购了它的一对值,是吗?
一种可能性不是创建类case
而是自己定义它的构造和提取。该类不会继承产品,也不会继承默认的toString
等,但除此之外它还可以作为案例类使用:
class Foo private (val a: Int, val b: Int);
object Foo {
def apply(a: Int, b: Int): Foo =
if (a < b)
new Foo(a, b)
else
new Foo(b, a)
def unapply(f: Foo): Option[(Int,Int)] = Some((f.a, f.b))
}
// test:
def printFoo(f: Foo) = f match {
case Foo(x, y) => println(x + ", " + y);
}
printFoo(Foo(1,2))
printFoo(Foo(3,2))
另见:
答案 2 :(得分:2)
看来你可以将case类构造函数设为私有!扩展@PetrPudlák答案,我将构造函数设为私有,并定义一个foo
帮助器来创建案例类对象:
case class Foo private (a: Int, b: Int)
object Foo {
def foo(x: Int, y: Int) = if (x > y) Foo(y, x) else Foo(x, y)
}
然后我只使用foo
来实例化格式良好的Foo
对象,其余的case类功能按预期工作(相等,hashcode,unapply):
import Foo._
foo(1, 2) //> res0: worksheets.so.Foo = Foo(1,2)
foo(2, 1) //> res1: worksheets.so.Foo = Foo(1,2)
foo(3, 4) == foo(4, 3) //> res2: Boolean = true
// Foo(4, 2) does not compile
// extractor/pattern matching works:
val Foo(a, b) = foo(10,1) //> a : Int = 1
//| b : Int = 10
您也可以将foo
命名为OrderedFoo
或NormalFoo
更有意义的内容。
答案 3 :(得分:1)
scala> :paste
// Entering paste mode (ctrl-D to finish)
object Foo {
def swapped(b: Int, a: Int) = Foo(a=a, b=b)
}
case class Foo(a: Int, b: Int)
// Exiting paste mode, now interpreting.
defined module Foo
defined class Foo
scala> Foo.swapped(1, 2) == Foo(2, 1)
res0: Boolean = true