How do you define a local var/val in the primary c

2019-01-10 16:30发布

问题:

In Scala, a class's primary constructor has no explicit body, but is defined implicitly from the class body. How, then, does one distinguish between fields and local values (i.e. values local to the constructor method)?

For example, take the following code snippet, a modified form of some sample code from "Programming in Scala":

class R(n: Int, d: Int) {
   private val g = myfunc
   val x = n / g
   val y = d / g
}

My understanding is that this will generate a class with three fields: a private "g", and public "x" and "y". However, the g value is used only for calculation of the x and y fields, and has no meaning beyond the constructor scope.

So in this (admittedly artificial) example, how do you go about defining local values for this constructor?

回答1:

E.g.

class R(n: Int, d: Int) {
  val (x, y) = {
    val g = myfunc
    (n/g, d/g)
  }
}


回答2:

There are a few ways to do that. You can declare such temporary variables inside private definitions, to be used during construction time. You can use temporary variables inside blocks which return expressions (such as in Alaz's answer). Or, finally, you can use such variables inside alternate constructors.

In a manner similar to the alternate constructors, you could also define them inside the object-companion's "apply" method.

What you can't do is declare a field to be "temporary".

Note also that any parameter received by the primary constructor is a field also. If you don't want such parameters to become fields, and don't want to expose the actual fields in a constructor, the usual solution is to make the primary constructor private, with the actual fields, and use either an alternate constructor or an object-companion's apply() as the effective "primary" constructor.



回答3:

Another option we have is to make the primary object constructor private and use a companion object's apply method as a builder. If we apply (pun is not intended) this approach to your example it will look like this:

class R private (val x: Int, val y: Int);

object R {
  def apply(n: Int, d: Int): R = {
    val g = myfunc;
    new R(n / g, d / g);
  }
}

To create an R instance instead of:

val r = new R(1, 2);

write:

val r = R(1, 2);

This is a little bit verbose, but it could be worse, I think :). Let's hope that private[this] vals will be treated as temporary variables in future releases of Scala. Martin himself hinted that.



回答4:

Some discussion on this topic, including Martin Odersky's comments, is here