#scala
#scala
Вопрос:
Возможно ли добавить функциональность перед вызовом конструктора в дополнительном конструкторе в scala?
Допустим, у меня есть класс User, и я хочу получить одну строку — и разделить ее на атрибуты — чтобы отправить их в конструктор:
class User(val name: String, val age: Int){
def this(line: String) = {
val attrs = line.split(",") //This line is leading an error - what can I do instead
this(attrs(0), attrs(1).toInt)
}
}
Итак, я знаю, что не могу добавить строку перед отправкой в this, потому что все конструкторы должны вызывать другой конструктор в качестве первого оператора конструктора.
Тогда что я могу сделать вместо этого?
Редактировать:
У меня длинный список атрибутов, поэтому я не хочу повторять line.split(",")
Ответ №1:
Я думаю, что это место, где сопутствующий объект и apply()
метод прекрасно вступают в игру:
object User {
def apply(line: String): User = {
val attrs = line.split(",")
new User(attrs(0), attrs(1).toInt)
}
}
class User(val name: String, val age: Int)
Затем вы просто создаете свой объект следующим образом:
val u1 = User("Zorro,33")
Кроме того, поскольку вы предоставляете name
и age
в любом случае, вы можете рассмотреть возможность использования класса case вместо стандартного класса и иметь согласованный способ построения User
объектов (без new
ключевого слова):
object User {
def apply(line: String): User = {
val attrs = line.split(",")
new User(attrs(0), attrs(1).toInt)
}
}
case class User(name: String, age: Int)
val u1 = User("Zorro,33")
val u2 = User("Zorro", "33")
Комментарии:
1. вам не нужно создавать класс case исключительно для сокрытия new: используйте private для конструктора и еще один метод apply в companion
Ответ №2:
Уродливое, но рабочее решение # 1:
class User(val name: String, val age: Int){
def this(line: String) = {
this(line.split(",")(0), line.split(",")(1).toInt)
}
}
Уродливое, но рабочее решение # 2:
class User(val name: String, val age: Int)
object User {
def fromString(line: String) = {
val attrs = line.split(",")
new User(attrs(0), attrs(1).toInt)
}
}
Который можно использовать как:
val johny = User.fromString("johny,35")
Вы могли бы использовать apply
вместо fromString
, но это приведет к путанице (в одном случае вы должны использовать new
, в другом вы должны отказаться от него), поэтому я предпочитаю использовать другое имя
Комментарии:
1. Я думаю, что буду использовать ваше второе решение, если нет лучшего… Я вижу, что scala немного разочаровывает
2. Вы можете сделать второе решение красивее с помощью patmat:
line.split('.') match { case Array(a, b) => new User(a, b.toInt) }
3. @AlexIv Я предпочитаю
val Array(a, b) = line.split(","); new User(a, b.toInt)
🙂
Ответ №3:
Еще одно уродливое решение:
class User(line: String) {
def this(name: String, age: Int) = this(s"$name,$age")
val (name, age) = {
val Array(nameStr,ageStr) = line.split(",")
(nameStr,ageStr.toInt)
}
}
Но использование метода сопутствующего объекта, вероятно, лучше.