1. ホーム
  2. scala

[解決済み] Scalaでループから抜け出すにはどうしたらいいですか?

2022-02-07 14:17:48

質問

ループを解除するにはどうしたらいいですか?

var largest=0
for(i<-999 to 1 by -1) {
    for (j<-i to 1 by -1) {
        val product=i*j
        if (largest>product)
            // I want to break out here
        else
           if(product.toString.equals(product.toString.reverse))
              largest=largest max product
    }
}

ネストされたforループを末尾再帰にするにはどうしたらいいですか?

FOSDEM 2009でのScalaトークより http://www.slideshare.net/Odersky/fosdem-2009-1013261 を22ページ目に掲載しました。

ブレークとコンティニュー Scalaにはありません。なぜでしょうか? ちょっと命令形になってしまうので、もっと小さな関数をたくさん使ったほうがいい。 クロージャとの付き合い方を問題視する。 必要ない!

どのような説明でしょうか?

どのように解決するのですか?

ループから抜け出すには、3つ(程度)の選択肢があります。

合計が1000より大きくなるまで数字を合計したいとします。 そこで

var sum = 0
for (i <- 0 to 1000) sum += i

ただし、(sum > 1000)で停止させたい場合。

どうすればいいのでしょうか? いくつかの選択肢があります。

(1a) テストする条件を含む何らかの構成物を使用する。

var sum = 0
(0 to 1000).iterator.takeWhile(_ => sum < 1000).foreach(i => sum+=i)

(警告--これは、takeWhileテストとforeachが評価中にどのように交信されるかの詳細に依存し、おそらく実際には使用すべきではありません!)。

(1b) Scalaでは新しいメソッドを簡単に書けることを利用して、forループの代わりに末尾再帰を使用します。

var sum = 0
def addTo(i: Int, max: Int) {
  sum += i; if (sum < max) addTo(i+1,max)
}
addTo(0,1000)

(1c) whileループの使用にフォールバックする

var sum = 0
var i = 0
while (i <= 1000 && sum <= 1000) { sum += 1; i += 1 }

(2)例外を投げる。

object AllDone extends Exception { }
var sum = 0
try {
  for (i <- 0 to 1000) { sum += i; if (sum>=1000) throw AllDone }
} catch {
  case AllDone =>
}

(2a) Scala 2.8+では、これはすでにあらかじめ scala.util.control.Breaks この構文は、C/Javaでおなじみの古いブレークによく似ています。

import scala.util.control.Breaks._
var sum = 0
breakable { for (i <- 0 to 1000) {
  sum += i
  if (sum >= 1000) break
} }

(3) メソッドにコードを入れ、returnを使用する。

var sum = 0
def findSum { for (i <- 0 to 1000) { sum += i; if (sum>=1000) return } }
findSum

このように意図的に簡単でないようにしているのは、少なくとも3つの理由が考えられる。 まず、大きなコードブロックでは "continue" と "break" を見落としたり、実際よりも多くまたは少なく脱落していると考えたり、とにかく簡単にできない2つのループを脱落させる必要があったりしがちです--したがって標準の使用法は便利ですが問題があり、したがってコードを別の方法で構成するようにすべきです。 第二に、Scalaには、おそらくあなたが気づかないようなあらゆる種類の入れ子構造があって、もしあなたが物事を断ち切ることができたら、おそらくコードフローが行き着く先に驚くことでしょう(特にクロージャの場合はそうです)。 第三に,Scala の "loops" のほとんどは,実は普通のループではありません。それ自体がループになっているメソッド呼び出しであったり,ループであるかどうかわからない再帰であったりしますが,それらは 行為 ループのように、"break" などはどうすればいいのか、一貫した方法を思いつくのは難しいです。 ですから、一貫性を保つためには、"break"を全く持たない方が賢明です。

備考 : の値を返すような、これらすべての関数に相当するものがあります。 sum その場で変異させるのではありません。 これらはよりScalaらしいイディオムです。 しかし、ロジックは同じです。 ( returnreturn x など)。