2

一部のアルゴリズムは、条件 true で while ループを実行し、(確かに) while ループの本体内の return ステートメントのある時点で終了します。例えば:

def foo: Int = {
  while(true) {
    // At some time, the while loop will do a return statement inside its body
    if( ... )
      return 0
  }
}

簡単な例 (セマンティックなし):

def foo: Int = {
  var i = 0
  while(true) {
    i += 1
    if(i == 10)
      return 0
  }
}

while ループの型が Unit であり、コンパイラは while ループがある時点で値を返すことを認識していないため、Scala コンパイラは型の不一致について警告します。次のような回避策でこれを修正できます。

def foo: Int = {
  var i = 0
  while(true) {
    i += 1
    if(i == 10)
      return 0
  }
  0 // !
}

しかし、これは醜く見えます。より良い回避策はありますか? または、この種の問題に対するより良い解決策はありますか?

4

4 に答える 4

14

例外をスローする可能性があります。

def foo: Int = {
  var i = 0
  while(true) {
    i += 1
    if(i == 10)
      return 0
  }
  throw new IllegalStateException("This should never happen")
}

コンパイラは型の不一致について文句を言うのをやめ、whileループは常に何かを返すので、例外がスローされることはありません。もしそうなら、あなたはあなたが何か間違ったことをした場所をすぐに見つけるでしょう:)。

このループを作成する方法は他にもありますが、より理想的でScala風ですが、提供したコードを考えると、これにより、明確で単純な方法で作業が完了します。

于 2012-08-22T09:41:14.067 に答える
8

代わりに末尾再帰を使用する必要があるかもしれません。非常によく似たバイトコードにコンパイルされるはずです。

import scala.annotation.tailrec

def foo: Int = {
  @tailrec def bar(i: Int): Int = {
    val j = i + 1
    if (j == 10) return 0
    else bar(j)
  }
  bar(0)
}

デフォルトのパラメータ値のサポートを利用したい場合もあります:

@tailrec def foo(i: Int = 0): Int = {
  val j = i + 1
  if (j == 10) return 0
  else foo(j)
}

この方法では、引数があるため、関数をfoo()notとして呼び出す必要があることに注意してください。foo

于 2012-08-22T09:50:46.623 に答える
3

より慣用的な方法は、再帰を使用することです。このようなもの:

  def foo: Int = { 
    import scala.annotation.tailrec
    @tailrec def whileUnderTen(i: Int):Int = if ( i < 10) whileUnderTen(i+1) else 0
    whileUnderTen(0)
  }
于 2012-08-22T09:56:07.540 に答える
1

まさにこれらの機会のために、私は個人的な標準ライブラリで定義された「永遠に」の構造を持っています。

forever{
}

はすべての点で同等です

while(true){
}

ただし、それforeverは typeNothingを持ちますが、同等のwhile構成要素は typeを持ちUnitます。Scala をとても楽しいものにする小さな拡張機能の 1 つにすぎません。

于 2012-08-22T23:37:22.027 に答える