Ранний возврат из конструктора Scala

Я пишу конструктор для своего "основного" класса. Первое, что он делает, это вызывает метод использования commons-cli для разбора командной строки. Если метод parseOptions возвращает false, произошла ошибка, и конструктор должен выйти.

Я попытался написать следующий код

if (!parseOptions(args)) return

но компилятор жалуется, что у меня есть «оператор возврата вне определения метода».

Если не считать вызова System.exit(1) или инвертирования логического значения (и размещения всей остальной логики внутри оператора if, есть ли способ вернуть «рано» из конструктора?

Я полагаю, что я мог бы заставить метод parseOptions генерировать IllegalArgumentException и перехватывать его в моем объекте Main.

Спасибо.


person Ralph    schedule 23.08.2010    source источник
comment
Хотя я согласен с другими ответами, что ни один конструктор не должен нормально возвращаться, если он не может привести экземпляр в состояние, удовлетворяющее инвариантам его класса, мне интересно, почему вы против использования if?   -  person Randall Schulz    schedule 23.08.2010
comment
Если у меня есть несколько условий, которые могут привести к раннему возврату, я получу каскад if на много уровней в глубину.   -  person Ralph    schedule 23.08.2010
comment
Так? Если это логика вашего конструктора, то это логика вашего конструктора. Также обычно рекомендуется не иметь много сложной логики в ваших конструкторах. В идеале они просто записывают значения, составляющие состояние/значение экземпляра.   -  person Randall Schulz    schedule 24.08.2010
comment
@Randall: я согласен с последним пунктом (несложные конструкторы).   -  person Ralph    schedule 25.08.2010


Ответы (3)


есть ли способ вернуть "рано" из конструктора

Нет. Но в вашем случае это все равно звучит как плохой дизайн.

Если метод parseOptions возвращает false, произошла ошибка

В этом случае конструктор должен генерировать исключение, а не возвращаться нормально.

person Alexey Romanov    schedule 23.08.2010
comment
После переосмысления (и реализации с использованием IllegalArgumentException) я согласен с тем, что плохой синтаксический анализ командной строки заслуживает исключения. - person Ralph; 23.08.2010

Не пытайтесь сделать ранний/преждевременный возврат, это усложнит ваш код, поскольку побочные эффекты возврата могут быть трудными для понимания. Вместо этого используйте исключение, чтобы сигнализировать о том, что что-то не так.

Вы можете использовать require в конструкторе. Это не возвращается. Но похоже, что создание исключения на самом деле лучше подходит для его ситуации.

As in:

class MyTest(
private var myValue: Int ){

    require(myValue > 0) // Connected to constructor

}

defined class MyTest

scala> val x = new  MyTest(10)
x: MyTest = MyTest@49ff4282

scala> val y = new MyTest(-10)
java.lang.IllegalArgumentException: requirement failed
        at scala.Predef$.require(Predef.scala:133)
person oluies    schedule 23.08.2010
comment
Это не возвращается. Но похоже, что создание исключения на самом деле лучше подходит для его ситуации. - person Alexey Romanov; 23.08.2010

Конструктор всегда должен либо завершиться полностью, либо прерваться (сгенерировать исключение). Все остальное оставляет ваш объект «наполовину построенным» и, следовательно, невозможным для рассуждений.

Если в вашем случае объект действителен даже при ошибке parseOptions, то вы можете изменить условие и продолжить:

if (parseOptions(args)) {
  // rest of constructor
}
person IttayD    schedule 23.08.2010
comment
тот факт, что Scala не поддерживает возврат из конструктора, не означает, что об этом «невозможно рассуждать». Замените if (X) return;... на if (!x) {...}, и вы сможете рассуждать сколько угодно. - person Elazar Leibovich; 23.08.2010
comment
Хм? Разве вы не видели, что я предложил поменять местами «если»? То, что я сказал, что конструктор должен завершить или откатиться, выдав исключение. Он не может вернуться, оставив вещи незавершенными. - person IttayD; 24.08.2010