私は初心者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
およびcount == 0
の場合にtrueを返します。それ以外の場合は、falseを返します。
さて、上記で、scalaにreturnステートメントを追加する必要がないことを読みました。そのため、上記のreturn
を省略しました。ただし、ブール値は返されません。 returnステートメントをreturn true
として追加した場合。完璧に機能します。なぜそうなのですか?
また、なぜscalaでreturnステートメントを使用するのは悪い習慣と見なされますか
return
キーワードを省略することほど単純ではありません。 Scalaでは、return
がない場合、最後の式が戻り値として使用されます。したがって、最後の式が返すものである場合、return
キーワードを省略できます。しかし、返したいものがnot最後の式である場合、Scala あなたがしたいことを知らないそれを返します。
例:
def f() = {
if (something)
"A"
else
"B"
}
ここで、関数f
の最後の式は、文字列に評価されるif/else式です。明示的なreturn
マークが付いていないため、Scalaは、このif/else式の結果:Stringを返したいと推測します。
さて、if(else)式の後にafter何かを追加すると:
def f() = {
if (something)
"A"
else
"B"
if (somethingElse)
1
else
2
}
現在、最後の式は、Intに評価されるif/else式です。したがって、f
の戻り値の型はIntになります。本当に文字列を返すようにしたい場合は、Scalaがアイデアなしを持っているので問題になります。したがって、文字列を変数に格納し、2番目のif/else式の後に返すか、文字列部分が最後に発生するように順序を変更することにより、修正する必要があります。
最後に、あなたのようなif-else式がネストされていてもreturn
キーワードを避けることができます:
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
}
}
これまでの回答で説明したように、このトピックは実際にはもう少し複雑です。これは Rob Norrisのブログ投稿 でさらに詳しく説明し、returnを使用すると実際にコードが破損する(または少なくとも非自明な効果がある)場合の例を示します。
この時点で、投稿の本質を引用させてください。最も重要な声明は、冒頭にあります。これをポスターとして印刷して、壁に置いてください:-)
return
キーワードは「オプション」または「推論」ではありません。プログラムの意味が変わるため、使用しないでください。
関数をインライン化すると、実際に何かを壊す1つの例を示します
// 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のような命令型言語から来たとき、これは最初は奇妙に思えるかもしれませんが、一度このスタイルに慣れると意味があります。別の引用で締めくくりましょう。
早期に戻りたいと思う状況にいる場合、計算を定義した方法を再考する必要があります。
私はScalaをプログラミングしませんが、暗黙の戻り値を持つ別の言語(Ruby)を使用します。 if (elem.isEmpty)
ブロックの後にコードがあります。コードの最後の行は返されたものです。そのため、期待したものが得られません。
編集:関数を記述するより簡単な方法もあります。 isEmptyのブール値とcountを使用して、自動的にtrueまたはfalseを返します。
def balanceMain(elem: List[Char]): Boolean =
{
elem.isEmpty && count == 0
}
対応するif
なしでelse
ステートメントを記述しないでください。フラグメントにelse
を追加すると、true
とfalse
が実際に関数の最後の式であることがわかります。
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....
デフォルトでは、関数の最後の式が返されます。この例では、戻り値が必要なポイントの後に別の式があります。最後の式の前に何かを返したい場合、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
}
}
早期返還のためにユースケースの一致。すべてのリターンブランチを明示的に宣言することを強制し、どこかにreturnを書くのを忘れるという不注意なミスを防ぎます。