如果您阅读了下面我的完整解释,那么您的三个问题的答案应该都很清楚,但为了方便大家,这里有一个简短而明确的摘要:
-
为什么打印 0? 这是因为方法调用返回
count,它的默认值是 0——所以它返回 0,而你打印 0。如果你用count=5 调用它,那么它将打印5。 (请参阅下面使用 println 的示例。)
-
为什么即使没有“return”,递归也能工作(当它在函数中间,但不是在最后)?你正在进行递归调用,所以递归发生了,但你没有t 返回递归调用的结果。
-
为什么不返回 1?当我明确使用“return”时?确实如此,但仅限于
list为空的情况。如果list 不为空,则返回count。 (同样,请参见下面使用 println 的示例。)
这里引用了 Odersky 的 Scala 编程(第一版可在线获取):
推荐的方法风格实际上是避免使用显式的,尤其是多个返回语句。相反,可以将每个方法视为产生一个值并返回的表达式。这种理念将鼓励您将方法制作得非常小,将较大的方法分解为多个较小的方法。另一方面,设计选择取决于设计上下文,如果您愿意,Scala 可以轻松编写具有多个显式返回的方法。 [link]
在 Scala 中,您很少使用 return 关键字,而是利用 表达式 中的所有内容将返回值传播回方法的顶级表达式,并且然后将结果用作返回值。您可以将return 视为更像break 或goto,它会破坏正常的控制流程,并可能使您的代码更难推理。
Scala 没有像 Java 这样的语句,而是一切都是表达式,这意味着一切都返回一个值。这就是为什么 Scala 使用 Unit 而不是 void 的原因之一——因为即使是 Java 中的 void 也需要在 Scala 中返回一个值。以下是一些与您的代码相关的表达式如何工作的示例:
- Java 中的表达式在 Scala 中的行为相同。也就是说
1+1的结果是2,x.y()的结果是方法调用的返回值。
- Java 有 if 语句,但 Scala 有 if 表达式。这意味着 Scala
if/else 结构的行为更像 Java ternary operator。因此,if (x) y else z 等价于 Java 中的 x ? y : z。像您使用的单独的if 与if (x) y else Unit 相同。
- Java 中的代码块是由一组语句组成的语句,但在 Scala 中,它是由一组表达式组成的表达式。代码块的结果是块中最后一个表达式的结果。因此,{ o.a(); 的结果o.b(); o.c() } 是
o.c() 返回的任何内容。您可以使用the comma operator in C/C++:(o.a(), o.b(), o.c()) 进行类似的构造。 Java 没有这样的东西。
-
return 关键字打破了表达式中的正常控制流,导致当前方法立即返回给定值。你可以把它想象成抛出一个异常,既是因为它是正常控制流的异常,也是因为(如throw 关键字)结果表达式的类型为Nothing。 Nothing 类型用于指示从不返回值的表达式,因此在类型推断期间基本上可以忽略。下面是一个简单示例,显示 return 的结果类型为 Nothing:
def f(x: Int): Int = {
val nothing: Nothing = { return x }
throw new RuntimeException("Can't reach here.")
}
基于这一切,我们可以看看你的方法,看看发生了什么:
def foo(list:List[Int], count:Int = 0): Int = {
// This block (started by the curly brace on the previous line
// is the top-level expression of this method, therefore its result
// will be used as the result/return value of this method.
if (list.isEmpty) {
return 1 // explicit return (yuck)
}
foo(list.tail, count + 1) // recursive call
count // last statement in block is the result
}
现在您应该能够看到 count 被用作您的方法的结果,除非您使用 return 破坏了正常的控制流。您可以看到return 正在工作,因为foo(List(), 5) 返回1。相反,foo(List(0), 5) 返回 5,因为它使用块的结果 count 作为返回值。试一试就能看清楚:
println(foo(List())) // prints 1 because list is empty
println(foo(List(), 5)) // prints 1 because list is empty
println(foo(List(0))) // prints 0 because count is 0 (default)
println(foo(List(0), 5)) // prints 5 because count is 5
您应该重新构造您的方法,使主体的值是一个表达式,而返回值只是该表达式的结果。看起来您正在尝试编写一个返回列表中项目数的方法。如果是这样的话,我会这样改变它:
def foo(list:List[Int], count:Int = 0): Int = {
if (list.isEmpty) count
else foo(list.tail, count + 1)
}
以这种方式编写时,在基本情况下(列表为空),它返回当前项目计数,否则返回列表尾部的递归调用结果,并带有count+1。
如果您真的希望它始终返回1,您可以将其更改为if (list.isEmpty) 1,它将始终返回1,因为基本情况将始终返回1。