如果你看過我的完整說明下面再回答你的三個問題都應該是明確的,但這裏有一個簡短,明確的總結爲了大家的方便:
- 爲什麼打印0?這是因爲方法調用返回
count
,其默認值爲0
- 因此它返回0
並且您打印0
。如果你用count=5
調用它,那麼它會打印5
。 (請參閱下面使用println
的示例。)
- 爲什麼遞歸甚至沒有「返回」(當它處於函數中間,而不是最後)時工作?您正在進行遞歸調用,因此遞歸發生,但您沒有返回遞歸調用的結果。
- 爲什麼不返回1?當我明確使用「返回」?它的確如此,但只有在
list
爲空的情況下。如果list
非空,則返回count
。 (再次,見下文使用println
的例子)
這裏是由Odersky的從編程報價在斯卡拉(第一版可在線):
的推薦樣式方法實際上是爲了避免顯式的,尤其是多個返回語句。相反,將每個方法看作一個產生一個返回值的表達式。這個理念會鼓勵你使方法很小,把更大的方法分解成多個小方法。另一方面,設計選擇取決於設計上下文,而Scala可以很容易地編寫具有多個明確回報的方法,如果這符合您的需求。 [link]
Scala裏你很少使用return
關鍵字,而是利用一切都在表達傳播的返回值回升到方法的頂級表現,而結果是再用作返回值。你可以將return
看作更像break
或goto
的東西,它會破壞正常的控制流程,並可能使你的代碼難以理解。
Scala沒有像Java這樣的語句,而是一切都是表達式,這意味着一切都會返回一個值。這就是爲什麼Scala擁有Unit
而不是void
的原因之一 - 因爲即使是Java中的void
,也需要在Scala中返回一個值。下面是幾個關於表達式如何與您的代碼相關的示例:
- 在Java中表達式的東西在Scala中的表現相同。這意味着
1+1
的結果是2
,並且x.y()
的結果是方法調用的返回值。
- Java如果陳述,但斯卡拉如果表達式。這意味着斯卡拉
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
。
給你的編輯:看到我的答案的第一句話。 – Hiura
你想做什麼?或者你的預期輸出是什麼? – KyelJmD
@Hiura對於我來說,你的最後一句話比第一句更有價值。這導致了我的簡單規則,如:*「最後一行贏」*就返回值而言。但是這並不完全正確,因爲「返回foo()」會贏,事實上它不是最後的。 – ses