在 Scala 中初始化“最终”变量

问题描述

考虑以下 Java 类:

public class C {
  private int n;
  private final int x;
  private final int y;
  public C(int n) {
    this.n = n;
    if (n < 0) {
      x = -1;
      y = -1;
    } else {
      x = 1;
      y = 1;
    }
  }
}

x,y 依赖于 n,设置后无法更改。这如何在 Scala 中实现? private val x 是最终的,但由于它是 val,因此不能在“构造函数”中更改。 private var x 是私有的,但不是最终的,因此虽然它对用户不可见,但对于可能会错误修改它的程序员来说是可见的。

在单个“最终”变量的情况下,可以像 this answer 那样做,但是如果有两个(或更多,就像我实际编码的那样),那么我不确定怎么做。这是一种方法

class C(n: Int) {
  private val x = if (n < 0) -1 else 1
  private val y = if (n < 0) -1 else 1 // code duplication
}

这是另一种方式:

class C(n: Int) {
  private val (x,y) = if (n < 0) (-1,-1) else (1,1)
}

我可以使用后者,但感觉很迂回而且通常很难看,所以我想知道是否还有其他方法?上面的另一个缺点是我不能使用全大写的名称,我想这样做(即使这可能与 Scala 风格背道而驰)。

谢谢!

解决方法

// make the constructor private to avoid setting x,y directly
case class C private(n: Int,x: Int,y: Int) 

// have a "smart constructor" in the companion object
// that implements your rule
object C {
  def apply(n: Int): C = if (n < 0) C(n,-1,-1) else C(n,1,1)
}

// create an instance like this
C(1)

或者,根本不存储 xy,只在需要时计算它们

case class C(n: Int){
   def x: Int = if (n < 0) -1 else 1  
      // could also make it a lazy-val if expensive
   def y: Int = x   // code re-use if the logic is really the same
}
,

我不确定您的解决方案有什么“丑陋”之处,对我来说似乎很好。 如果要使用大写,简单的方法是将它们一分为二:

   val Abs = if (n < 0) -1 else 1
   val Xyz = if (n < 0) -1 else 1

重新。 “代码重复”:如果您出于某种原因想要两个具有相同值的变量,您将不得不复制以一种或另一种方式设置它的代码。这不是语法问题,而是您的设计问题。 这:

      x = -1;
      y = -1;

其实也是在复制代码。 如果您非常想避免代码重复的可见性,那么您可以随时编写 val Xyz = Abc,如果您认为这有帮助的话。