如何在没有退货声明的情况下提早退货?

Mic*_*ini 4 functional-programming scala return

如何在scala中编写没有返回/中断的早期返回代码?

例如

for i in 0..10000000
  if expensive_operation(i)
     return i
return -1
Run Code Online (Sandbox Code Playgroud)

Thi*_*ilo 8

怎么样

 input.find(expensiveOperation).getOrElse(-1)
Run Code Online (Sandbox Code Playgroud)


pme*_*pme 5

您可以使用 dropWhile

这里是一个例子:

Seq(2,6,8,3,5).dropWhile(_ % 2 == 0).headOption.getOrElse(default = -1) // -> 8
Run Code Online (Sandbox Code Playgroud)

在这里您可以找到更多scala-takewhile-示例

以你的例子

(0 to 10000000).dropWhile(!expensive_operation(_)).headOption.getOrElse(default = -1)`
Run Code Online (Sandbox Code Playgroud)


Lui*_*rez 4

既然您要求直觉来一般​​性地解决这个问题。让我从基础开始。

Scala (除其他外)是一种函数式编程语言,因此对我们来说有一个非常重要的概念。就是我们通过组合expressions而不是通过statements.

因此,返回值的概念对我们来说意味着对 的评估expression(注意这与引用透明度
的概念有关)

val a = expr   // a is bounded to the evaluation of expr,
val b = (a, a) // and they are interchangeable, thus b === (expr, expr)
Run Code Online (Sandbox Code Playgroud)

这与你的问题有何关系。从某种意义上说,我们实际上没有控制结构,只有复杂的表达式。例如一个if

val a = if (expr) exprA else exprB // if itself is an expression, that returns other expressions.
Run Code Online (Sandbox Code Playgroud)

因此,不要做这样的事情:

def foo(a: Int): Int =
  if (a != 0) {
    val b = a * a
    return b
  }
  return -1
Run Code Online (Sandbox Code Playgroud)

我们会做类似的事情:

def foo(a: Int): Int =
  if (a != 0)
    a * a
  else
   -1
Run Code Online (Sandbox Code Playgroud)

因为我们可以将所有表达式if本身绑定为 foo 的主体。


现在,回到你的具体问题。怎样才能早点归还呢cycle
答案是,你不能,至少在没有突变的情况下不能。但是,您可以使用更高的概念,而不是迭代,您可以遍历某些东西。您可以使用recursion.

因此,让我们将find@Thilo 的提议作为一个tail-recursive函数来实现。
(非常重要的是,该函数是尾递归的,因此编译器将其优化为相当于 while 循环的东西,这样我们就不会炸毁堆栈)

def find(start: Int, end: Int, step: Int = 1)(predicate: Int => Boolean): Option[Int] = {
  @annotation.tailrec
  def loop(current: Int): Option[Int] =
    if (current == end)
      None // Base case.
    else if (predicate(current))
      Some(current) // Early return.
    else
      loop(current + step) // Recursive step.
  loop(current = start)
}

find(0, 10000)(_ == 10)
// res: Option[Int] = Some(10)
Run Code Online (Sandbox Code Playgroud)

或者我们可以更概括一点,让我们实现对任何类型元素的列表的查找。

def find[T](list: List[T])(predicate: T => Boolean): Option[T] = {
  @annotation.tailrec
  def loop(remaining: List[T]): Option[T] =
    remaining match {
      case Nil                      => None
      case t :: _ if (predicate(t)) => Some(t)
      case _ :: tail                => loop(remaining = tail)
    }
  loop(remaining = list)
}
Run Code Online (Sandbox Code Playgroud)