Я думаю, что вижу преимущество в определении вспомогательных конструкторов таким образом, чтобы основной конструктор был единственной точкой входа в класс. Но почему я не могу сделать что-то подобное?
class Wibble(foo: Int, bar: String) {
def this(baz: List[Any]) = {
val bazLength = baz.length
val someText = "baz length is " ++ bazLength.toString
this(bazLength, someText)
}
}
Может быть, это способ гарантировать, что вспомогательный конструктор не имеет побочных эффектов и / или не может вернуться раньше?
1 ответ
Вспомогательные конструкторы могут содержать более одного вызова другого конструктора, но их первый оператор должен называться вызовом.
Как объясняется в Программирование на Scala , гл. 6.7:
В Scala каждый вспомогательный конструктор должен вызывать другой конструктор того же класса, что и его первое действие. Другими словами, первое утверждение в каждом вспомогательный конструктор в каждом классе Scala будет иметь вид
this(. . . )
. Вызванный конструктор является либо основным конструктором (как вRational
) example) или другой вспомогательный конструктор, который идет текстуально перед вызывающий конструктор. Чистый эффект этого правила заключается в том, что каждый вызов конструктора в Scala в конечном итоге вызовет основной конструктор класс. Таким образом, первичный конструктор является единственной точкой входа в класс.Если вы знакомы с Java, вы можете задаться вопросом, почему правила Scala для конструкторов немного более строгие, чем правила Java. В Java конструктор должен либо вызывать другой конструктор того же класса, либо напрямую вызывать конструктор суперкласса в качестве своего первого действия. В классе Scala только основной конструктор может вызывать конструктор суперкласса. Повышенные ограничения в Scala на самом деле являются компромиссом при проектировании, который необходимо было заплатить в обмен на большую лаконичность и простоту конструкторов Scala по сравнению с конструкторами Java.
Как и в Java, это ограничение можно обойти, выделив код, который будет выполняться перед вызовом основного конструктора, в отдельный метод. В Scala это немного сложнее, чем в Java, поскольку, очевидно, вам нужно переместить этот вспомогательный метод в сопутствующий объект, чтобы иметь возможность вызывать его из конструктора.
Более того, ваш конкретный случай неудобен, поскольку у вас есть два параметра конструктора и - хотя можно возвращать кортежи из функции - этот возвращенный кортеж не принимается в качестве списка аргументов для основного конструктора. Для обычных функций вы можете использовать tupled
, но, увы, для конструкторов это не работает. Обходной путь - добавить еще один вспомогательный конструктор:
object Wibble {
private def init(baz: List[Any]): (Int, String) = {
val bazLength = baz.length
val someText = "baz length is " ++ bazLength.toString
println("init")
(bazLength, someText)
}
}
class Wibble(foo: Int, bar: String) {
println("Wibble wobble")
def this(t: (Int, String)) = {
this(t._1, t._2)
println("You can execute more code here")
}
def this(baz: List[Any]) = {
this(Wibble.init(baz))
println("You can also execute some code here")
}
}
Это, по крайней мере, работает, даже если это немного сложно.
scala> val w = new Wibble(List(1, 2, 3))
init
Wibble wobble
You can execute more code here
You can also execute some code here
w: Wibble = Wibble@b6e385
Обновить
Как отметил @ sschaef в своем комментарии, это можно упростить, используя фабричный метод в сопутствующем объекте:
object Wobble {
def apply(baz: List[Any]): Wobble = {
val bazLength = baz.length
val someText = "baz length is " ++ bazLength.toString
println("init")
new Wobble(bazLength, someText)
}
}
class Wobble(foo: Int, bar: String) {
println("Wobble wibble")
}
Таким образом, нам больше не нужно new
для создания объекта:
scala> val w = Wobble(List(1, 2, 3))
init
Wobble wibble
w: Wobble = Wobble@47c130
apply
.
Похожие вопросы
Связанные вопросы
Новые вопросы
scala
Scala - это язык программирования общего назначения, в основном предназначенный для виртуальной машины Java. Разработанный для краткого, элегантного и безопасного для типов представления общих шаблонов программирования, он сочетает в себе как императивный, так и функциональный стили программирования. Его ключевые особенности: продвинутая система статического типа с выводом типа; типы функций; сопоставления с образцом ; неявные параметры и преобразования; перегрузка оператора; полная совместимость с Java; совпадение