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)
您可以使用 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)
既然您要求直觉来一般性地解决这个问题。让我从基础开始。
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)