Chirlo Chirlo - 10 days ago 8
Scala Question

Constructor-local variables in Scala

I'm on exercise 5.7 of "Scala for the Impatient", where i need to create a class Person that takes a name:String on constructor and has 2 properties firstName and lastName filled from name split by whitespace. My first trial was :

class Person(name:String) {
private val nameParts = name.split(" ")

val firstName = nameParts(0)
val lastName = nameParts(1)
}


The problem is, that now nameParts remains as a private field always visible within the class, when in fact should only exist within the constructor's local environment. The Java equivalent of what I want would be:

class Person{
private final String firstName;
private final String lastName;

Person(String name){
final String[] nameParts = name.split(" ");
firstName = nameParts[0];
lastName = nameParts[1];
}
}


Here, nameParts exists only withing the constructor, which is what i'm aiming for. Any hints on how this can be done in Scala?

NOTE: I ended up finding a more "Scalesque" way:

class Person(name:String) {
val firstName::lastName::_ = name.split(" ").toList
}


but I still would like to get an answer to my question.

Answer

There is a way to avoid the private val. Just use the extractor of Array:

class Person(name: String) {
  val Array(first, last) = name.split(" ")
}

edit:

What you want to do can be achieved through a factory method on the companion and a default constructor that takes first and last as param:

class Person(val first: String, val last: String)

object Person {
  def apply(name: String) = {
    val splitted = name.split(" ")
    new Person(splitted(0), splitted(1))
  }
}

scala> Person("Foo Bar")
res6: Person = Person@37e79b10

scala> res6.first 
res7: String = Foo

scala> res6.last
res8: String = Bar

But for this simple case I would prefer my first suggestion.

The example in your link would also work, but it's kind of the same as my first example. Afaik there is no way to create a temporary variable in the constructor.

Comments