Насколько я понимаю это, нет никакого способа в Scala иметь несколько точек возврата в анонимной функции, т.е.
someList.map((i) => {
if (i%2 == 0) return i // the early return allows me to avoid the else clause
doMoreStuffAndReturnSomething(i) // thing of this being a few more ifs and returns
})
повышения error: return outside method definition
. (И если бы это не должно было повышать это, то код не работал бы, поскольку я хотел бы, чтобы это работало.)
Одно обходное решение, из которого я мог вещь, будет следующим
someList.map({
def f(i: Int):Int = {
if (i%2 == 0) return i
doMoreStuffAndReturnSomething(i)
}
f
})
однако, я хотел бы знать, существует ли другой 'принятый' способ сделать это. Возможно, возможность обойтись без помощи названия внутренней функции?
(Вариант использования состоял бы в том, чтобы эмулировать некоторых оцененных continue
создайте в цикле.)
Править
Полагайте мне, что еще существует потребность в предотвращении оператор, потому что, doMoreStuff
часть могла бы на самом деле быть похожей:
val j = someCalculation(i)
if (j == 0) return 8
val k = needForRecalculation(i)
if (k == j) return 9
finalRecalc(i)
...
который, когда Вы только имеете if
–else
доступная структура легко испорчена.
Конечно, в простом примере я дал в начале, легче просто использовать else
. Извините, я думал, что это было ясно.
Я думаю, что основная проблема с точками возврата в анонимных функциях заключается в том, что анонимная функция может появиться там, где ее обычно не ожидают. Таким образом, будет неясно, к какому закрытию на самом деле относится оператор возврата. Эта проблема решается явным требованием соответствия def
-return*
.
В качестве альтернативы можно использовать защитные экраны вокруг оператора, из которого осуществляется возврат. breakable
-break
, но, к сожалению, при этом нельзя вернуть значение. Некоторые решения на основе продолжений могли бы достичь этой цели, хотя я хотел бы дождаться общего признания и библиотек.
Приведенный вами пример легко решается с помощью оператора if. За это нет никаких штрафов за исполнение или других штрафов.
Но у вас может быть другая ситуация, которая примерно похожа на
if (test) {
if (anotherTest) {
val a = someComputation()
if (testOf(a)) return otherComputation()
}
else if (yetAnotherTest) return whatever()
}
bigComputation()
Есть несколько способов справиться с такой ситуацией, если вы хотите избежать путаницы операторов if и / или дублирования кода, необходимых для преобразования этого бланку без возврата.
Есть разные хитрые вещи, которые вы можете сделать с помощью Option
или Либо
, чтобы сохранить текущее состояние (с или Else
и свернуть
) так что вы делаете только необходимые вычисления.
Вам действительно лучше создать деф, как вы предлагаете. Но для сравнения рассмотрим стиль упаковки Option:
i => {
( if ((i%2)==0) Some(i)
else None
).getOrElse(doStuffAndReturn(i))
}
В большом примере, приведенном выше, этот стиль дал бы
( if (test) {
if (anotherTest) {
val a = someComputation()
if (testOf(a)) Some(otherComputation()) else None
}
else if (yetAnotherTest) Some(whatever())
else None
}).getOrElse(bigComputation())
Лично я не думаю, что это яснее (и, конечно, не быстрее), но это возможно.
В своем комментарии к коду вы написали, что не хотите использовать ключевое слово else
, но ИМХО это делает именно то, что вы хотите, и его даже на два символа короче; -)
someList.map((i) => {
if (i%2 == 0) i else
doMoreStuffAndReturnSomething(i)
})
Если ваша анонимная функция такая сложная, я бы сделал ее более явной. Анонимные функции не подходят для чего-либо более сложного, чем несколько строк. Вы можете сделать этот метод закрытым, объявив его в методе using
def myF(i:Int):Int = {
if (i%2 == 0) return i
doMoreStuffAndReturnSomething(i)
}
someList.map(myF(_))
. Это вариант вашего обходного пути, но он чище. Они оба сохраняют его приватность в области локального метода.