2012-09-24 185 views
48

我是一個新手scala程序員,遇到了一個奇怪的行爲。斯卡拉返回

def balanceMain(elem: List[Char]): Boolean = 
    { 
    if (elem.isEmpty) 
     if (count == 0) 
     true; 
     else false; 

    if (elem.head == '(') 
     balanceMain(elem.tail, open, count + 1);.... 

以上基本上我想如果elem.isEmptycount == 0返回true。否則,我想返回false。

上面我已經讀過,沒有必要在scala中添加return語句。所以我省略了上面的return。但它不返回布爾值。如果我添加return語句爲return true。它完美地工作。爲什麼這樣?

而且,爲什麼它被認爲是不好的做法,在斯卡拉

+1

有**通常**不需要return關鍵字,只要您將代碼分解爲足夠小的方法即可。 – mauhiz

+0

@mauhiz謝謝。你能解釋一下嗎?你會怎麼做。 – Jatin

+2

看起來像你正在參加coursera scala課程。所有最好:) – weima

回答

90

它不像只是省略return關鍵字一樣簡單。在斯卡拉,如果沒有return那麼最後一個表達式就是返回值。因此,如果最後一個表達式是您想要返回的內容,那麼您可以省略return關鍵字。但是如果你想要返回的是而不是的最後一個表達式,那麼Scala 不會知道你想要返回它

一個例子:

def f() = { 
    if (something) 
    "A" 
    else 
    "B" 
} 

在這裏,函數f的最後一個表達式是一個if/else表達式計算結果爲一個字符串。由於沒有明確的return標記,Scala會推斷您想要返回此if/else表達式的結果:一個字符串。

現在,如果我們添加的東西後的if/else表達式:

def f() = { 
    if (something) 
    "A" 
    else 
    "B" 

    if (somethingElse) 
    1 
    else 
    2 
} 

現在最後一個表達式是if/else表達式中的一個詮釋。所以f的返回類型將是Int。如果我們真的希望它返回字符串,那麼我們遇到了麻煩,因爲Scala有不知道這就是我們的意圖。因此,我們必須通過將String存儲到變量並在第二個if/else表達式之後返回它,或者通過更改順序以便最後發生String部分來修復它。

最後,我們可以避開return關鍵字,甚至像你這樣一個嵌套的if-else表達式:

def f() = { 
    if(somethingFirst) { 
    if (something)  // Last expression of `if` returns a String 
    "A" 
    else 
    "B" 
    } 
    else { 
    if (somethingElse) 
     1 
    else 
     2 

    "C"    // Last expression of `else` returns a String 
    } 

}

+1

所有的神,謝謝!我在同一個問題上奮戰了幾個小時(同時也在Coursera課程中)並且無法理解爲什麼需要回報。第一個示例爲 –

+0

,如果添加退貨會發生什麼情況。即「返回」一個「'和」返回「B」'? –

+0

@ T.Rex它將返回f()的值爲「A」或「B」的調用者。但正如我在我的回答中解釋的那樣。千萬不要在Scala中使用return。如果Scala中的語句以功能方式工作。他們評估某種類型的東西。就像Java中的三元運算符(?:)。例如:val foo = if(mybool)「A」else「B」 - foo將是包含「A」或「B」的字符串。同樣想到一個函數不會返回一些東西,而是評估其中最後一個表達式的值。 – Grmpfhmbl

3

我沒有編程斯卡拉return語句,但我用隱含回報率(Ruby)的另一種語言。你的代碼在if (elem.isEmpty)塊之後 - 代碼的最後一行是返回的,這就是爲什麼你沒有得到你所期望的。

編輯:這裏有一個更簡單的方法來寫你的功能。只要使用的isEmpty的布爾值和計數,自動返回true或false:

def balanceMain(elem: List[Char]): Boolean = 
{ 
    elem.isEmpty && count == 0 
} 
+0

謝謝。但我只想返回,如果elem.isEmpty &&計數== 0返回true否則繼續該塊。即使它是假的,以上也會返回。 – Jatin

+0

@賈丁:啊,沒有意識到。那麼在這種情況下,早期和明確的回報是適當的。 – jmdeldin

+0

@Frank:它在OP的代碼中也沒有定義。我認爲這是一個方法調用。 – jmdeldin

4

默認情況下,函數的最後一個表達式將被退回。 在你的例子中,在你想要返回值的地方有另一個表達式。 如果您想要在上次表達之前返回任何內容,則仍需使用return

您可以修改您的例子就是這樣,從第一部分

def balanceMain(elem: List[Char]): Boolean = { 
    if (elem.isEmpty) { 
    // == is a Boolean resulting function as well, so your can write it this way 
    count == 0 
    } else { 
    // keep the rest in this block, the last value will be returned as well 
    if (elem.head == "(") { 
     balanceMain(elem.tail, open, count + 1) 
    } 
    // some more statements 
    ... 
    // just don't forget your Boolean in the end 
    someBoolExpression 
    } 
} 
+9

不是「聲明」。 「表達」 –

+1

@ViktorKlang謝謝你的提示,糾正它。 – Tharabas

3

返回Boolean不要寫if語句沒有相應的else。一旦將else添加到片段中,您將看到您的truefalse實際上是該函數的最後一個表達式。

def balanceMain(elem: List[Char]): Boolean = 
    { 
    if (elem.isEmpty) 
     if (count == 0) 
     true 
     else 
     false 
    else 
     if (elem.head == '(') 
     balanceMain(elem.tail, open, count + 1) 
     else.... 
+1

我應用了它,得到了3個嵌套的IF,它看起來很醜。有沒有任何模式讓它看起來更漂亮? – Sergey

9

這個主題實際上是一些複雜的,如迄今爲止的答案所述。這blogpost by Rob Norris更詳細地解釋它,並舉例說明何時使用返回將實際上破壞你的代碼(或至少有非明顯的影響)。

在這一點上,讓我引用這篇文章的精髓。最重要的說法在一開始就是正確的。將其作爲海報打印並放到您的牆上:-)

return關鍵字不是「可選的」或「推斷的」;它會改變你的程序的含義,你永遠不應該使用它。

它提供了一個例子,它實際上打破了東西,當你內聯函數

// Inline add and addR 
def sum(ns: Int*): Int = ns.foldLeft(0)((n, m) => n + m) // inlined add 

scala> sum(33, 42, 99) 
res2: Int = 174 // alright 

def sumR(ns: Int*): Int = ns.foldLeft(0)((n, m) => return n + m) // inlined addR 

scala> sumR(33, 42, 99) 
res3: Int = 33 // um. 

因爲

一個return表達,評估的時候,放棄目前的計算 和回報給出現return的方法的調用者。

這只是鏈接文章中給出的例子之一,它是最容易理解的。還有更多,我非常鼓勵你,去那裏,閱讀和理解。

當你來自像Java這樣的命令式語言時,這可能起初看起來很奇怪,但一旦習慣了這種風格,它就會有意義。讓我關閉另一個報價:

如果您發現自己處於一種您認爲想早點返回的情況,則需要重新考慮您定義計算的方式。

+1

我不同意Rob,IMO你不能只在lambda表達式中使用'return',但這是一種在語言中很糟糕的設計選擇,代碼甚至不應該編譯(在python中,這可以通過使用'lambda'來避免關鍵字沒有return語句)...在其他情況下,如果您想要返回一個值(並且是從方法執行退出是因爲在所有語言中使用了什麼返回值,那麼使用'return'時看不到真正的問題!) – daveoncode

+0

你可以自由發表你的意見,但很多人都認爲在Scala中使用回報至少是不好的風格。我敢於找到使用return的官方Scala文檔示例。 AFAIK甚至沒有在官方文檔中解釋過,僅在規範文檔中(第6.20章)。引用Martin Odersky自己(在Scala中編程)「推薦的方法風格實際上是爲了避免顯式的,尤其是多個返回語句,而是將每個方法看作是一個表達式,它返回一個值。本書第一版可在線免費獲取http://www.artima.com/pins1ed/ – Grmpfhmbl