是否可以交换构造函数的参数?考虑以下示例:
case class Foo(a:Int, b:Int) {
if (a > b) {
val tmp = a
a = b
b = tmp
}
}
编译器会抛出一个错误,因为我a
在第 4 行重新分配给 val,这非常好。但是,我需要不可变的对象。因此,将a
and声明b
为变量不是一种选择。
是否有已知的模式来解决这个问题?
是否可以交换构造函数的参数?考虑以下示例:
case class Foo(a:Int, b:Int) {
if (a > b) {
val tmp = a
a = b
b = tmp
}
}
编译器会抛出一个错误,因为我a
在第 4 行重新分配给 val,这非常好。但是,我需要不可变的对象。因此,将a
and声明b
为变量不是一种选择。
是否有已知的模式来解决这个问题?
做一个内部交换方法:
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等......正如 Odersky 教授在 SD'13 演讲中所说的那样,有你不应该害怕的情况vars
我想你想要实现的每个实例都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))
也可以看看:
看来您可以将案例类构造函数设为私有!扩展@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
对象,其余的案例类功能按预期工作(平等,哈希码,不适用):
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
or NormalFoo
。
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