How in Scala I can define local variable in primary constructor?
I need to solve this exercise from Scala for the impatient
book:
Write a class Person with a primary constructor that accepts a string containing a first name, a space, and a last name, such as new Person("Fred Smith"). Supply read-only properties firstName and lastName. Should the primary constructor parameter be a var, a val, or a plain parameter? Why?
And for now my solution looks like this:
class Person(firstLast: String) {
private[this] val firstLastAsArr = firstLast.trim.split(" ")
val firstName = firstLastAsArr (0)
val lastName = firstLastAsArr (1)
}
How I can restrict firstLastAsArr
variable visibility to primary constructor scope (now it have class scope)?
One solution is to initialize firstName
and lastName
at once, thereby allowing to turn firstLastAsArr
into a local temporary value inside your initialization block:
class Person(firstLast: String) {
val (firstName, lastName) = {
val firstLastAsArr = firstLast.trim.split(" ")
(firstLastAsArr(0), firstLastAsArr(1))
}
}
It is not a general answer, but in this particular way you may write:
val Array(firstName, lastName) = firstLast.trim.split(" ")
You don't strictly need the intermediate variable:
class Person(firstLast: String) {
val (firstName, lastName) =
firstLast.trim.split(" ") match {case Array(first, last) => (first, last)}
}
However, if your transformation from firstLast
to firstName
and lastName
grows a big longer, for example, because you check that there is exactly one first and one last name, then I would encapsulate the whole splitting-business in a dedicated method:
class Person(firstLast: String) {
val (firstName, lastName) = split(firstLast)
private def split(firstLast: String): (String, String) = {
val firstLastAsArr = firstLast.trim.split(" ")
...
(first, last)
}
}
Pattern matching in constructor works just fine, but you should consider moving such logic from constructor to factory method:
case class Person(firstName: String, lastName: String)
object Person{
def apply(firstLast: String) = {
val firstLastAsArr = firstLast.trim.split(" ")
new Person(firstLastAsArr(0), firstLastAsArr(1))
}
}
val p = Person("My Title")
Pattern maching in primary constructor works well
class Person(_fullName:String) {
val (firstName, lastName) = _fullName.split(" ") match {
case Array(x:String, y:String, _*) => (x,y)
case _ => (null,null)
}
}
See my github for full answer https://github.com/BasileDuPlessis/scala-for-the-impatient/blob/master/src/main/scala/com/basile/scala/ch05/Ex07.scala
来源:https://stackoverflow.com/questions/17211077/scala-local-variable-inside-primary-constructor