Несколько точек возврата в scala закрытии/анонимной функции

Насколько я понимаю это, нет никакого способа в 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)
...

который, когда Вы только имеете ifelse доступная структура легко испорчена.

Конечно, в простом примере я дал в начале, легче просто использовать else. Извините, я думал, что это было ясно.

11
задан Debilski 24 May 2010 в 22:08
поделиться

4 ответа

Я думаю, что основная проблема с точками возврата в анонимных функциях заключается в том, что анонимная функция может появиться там, где ее обычно не ожидают. Таким образом, будет неясно, к какому закрытию на самом деле относится оператор возврата. Эта проблема решается явным требованием соответствия def-return*.

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

1
ответ дан 3 December 2019 в 09:19
поделиться

Приведенный вами пример легко решается с помощью оператора 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())

Лично я не думаю, что это яснее (и, конечно, не быстрее), но это возможно.

3
ответ дан 3 December 2019 в 09:19
поделиться

В своем комментарии к коду вы написали, что не хотите использовать ключевое слово else , но ИМХО это делает именно то, что вы хотите, и его даже на два символа короче; -)

someList.map((i) => {
    if (i%2 == 0) i else
    doMoreStuffAndReturnSomething(i)
})
3
ответ дан 3 December 2019 в 09:19
поделиться

Если ваша анонимная функция такая сложная, я бы сделал ее более явной. Анонимные функции не подходят для чего-либо более сложного, чем несколько строк. Вы можете сделать этот метод закрытым, объявив его в методе using

def myF(i:Int):Int = {
    if (i%2 == 0) return i
    doMoreStuffAndReturnSomething(i)
}
someList.map(myF(_))

. Это вариант вашего обходного пути, но он чище. Они оба сохраняют его приватность в области локального метода.

5
ответ дан 3 December 2019 в 09:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: