1

是否可以交换构造函数的参数?考虑以下示例:

case class Foo(a:Int, b:Int) {
  if (a > b) {
    val tmp = a
    a = b
    b = tmp
  }
}

编译器会抛出一个错误,因为我a在第 4 行重新分配给 val,这非常好。但是,我需要不可变的对象。因此,将aand声明b为变量不是一种选择。

是否有已知的模式来解决这个问题?

4

4 回答 4

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)

如果您想保持不变性,那么要更改状态,您需要在每次修改时返回新实例,或者使用一些硬核方式,如LensesStateRecords等......正如 Odersky 教授在 SD'13 演讲中所说的那样,有你不应该害怕的情况vars

于 2013-07-17T11:23:53.410 回答
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))

也可以看看:

于 2013-07-17T13:18:51.597 回答
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为更有意义的名称,例如OrderedFooor NormalFoo

于 2013-07-18T04:56:03.060 回答
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
于 2013-07-17T11:49:42.620 回答