95

私は初心者の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.isEmpty上記の場合、基本的にtrueを返したいと思いcount == 0ます。それ以外の場合は、falseを返します。

上記で、scalaにreturnステートメントを追加する必要がないことを読みました。だから私はreturn上記を省略しました。ただし、ブール値は返されません。returnステートメントをとして追加した場合return true。それは完璧に動作します。なんでそうなの?

また、scalaでreturnステートメントを使用することが悪い習慣と見なされるのはなぜですか

4

6 に答える 6

152

returnキーワードを省略するほど簡単ではありません。Scalaでは、存在しない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
}

これで、最後の式は、Intに評価されるif/else式になります。したがって、の戻り型はfIntになります。文字列を返すことを本当に望んでいた場合、Scalaはそれが意図したものであるとは知らないため、問題が発生します。したがって、文字列を変数に格納して2番目のif / else式の後に返すか、文字列部分が最後に発生するように順序を変更することによって、これを修正する必要があります。

最後に、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
  }

}

于 2012-09-24T07:24:54.387 に答える
25

これまでの回答で説明したように、このトピックは実際にはもう少し複雑です。Rob Norrisによるこのブログ投稿では、それをより詳細に説明し、returnを使用すると実際にコードが破損する(または少なくとも非自明な効果がある)場合の例を示しています。

この時点で、投稿の本質を引用させてください。最も重要なステートメントは最初にあります。これをポスターとして印刷して壁に貼ってください:-)

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ます。

これは、リンクされた投稿に示されている例の1つにすぎず、最も理解しやすいものです。もっとたくさんあります、そして私はあなたがそこに行き、読んで理解することを強くお勧めします。

Javaのような命令型言語から来た場合、これは最初は奇妙に思えるかもしれませんが、このスタイルに慣れれば、それは理にかなっています。別の引用で締めくくります:

早く戻りたいと思う状況に陥った場合は、計算を定義した方法を再考する必要があります。

于 2016-08-17T10:12:00.077 に答える
5

私はScalaをプログラムしていませんが、暗黙のリターン(Ruby)を持つ別の言語を使用しています。ブロックの後にif (elem.isEmpty)コードがあります。コードの最後の行が返されるものであるため、期待したものが得られません。

編集:関数を書く簡単な方法もあります。isEmptyとcountのブール値を使用して、trueまたはfalseを自動的に返します。

def balanceMain(elem: List[Char]): Boolean =
{
    elem.isEmpty && count == 0
}
于 2012-09-24T07:22:35.593 に答える
5

デフォルトでは、関数の最後の式が返されます。あなたの例では、ポイントの後に、戻り値が必要な別の式があります。最後の式の前に何かを返したい場合でも、を使用する必要がありますreturn

このように例を変更してBoolean、最初の部分からを返すことができます

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
  }
}
于 2012-09-24T07:29:50.930 に答える
4

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....
于 2012-09-24T18:35:26.587 に答える
1

早期返品を目的としたユースケースの一致。これにより、すべてのreturnブランチを明示的に宣言する必要があり、returnをどこかに書き込むのを忘れるという不注意な間違いを防ぐことができます。

于 2019-03-01T20:52:10.970 に答える