2011-09-08 7 views
9

"Scala for the Impatient"の途中で私は自分自身が不思議に思っていました:シーケンスなしでループのためにScalaを使用できますか?シーケンスのないスケーラのループの場合は?

たとえば、Integer.MAX_VALUEを超えて増やすことができないカウンタオブジェクトを作成するよう練習しています。私のソリューションをテストするために、私は次のコードを書いた:

var c = new Counter 
for(i <- 0 to Integer.MAX_VALUE) c.increment() 

これはエラーをスローする:シーケンスはInt.MaxValue以上の要素を含むことはできません。 それは、Scalaが0からInteger.MaxValueまでの値を持つシーケンスオブジェクトを最初に割り当てて配置してから、そのシーケンスオブジェクトに対してforeachループを実行するということです。

私は私が代わりにこれを行うことができることを実現:

var c = new Counter 
while(c.value < Integer.MAX_VALUE) c.increment() 

しかしための文でループのための伝統的なCスタイルを実行する方法はありますか?

答えて

17

0 to Nは実際に0からNに整数では何も移入されません。代わりにscala.collection.immutable.Rangeのインスタンスを作成し、そのメソッドをその場で生成されたすべての整数に適用します。

lengthメソッドの契約を維持するために、(実際に存在するかどうかにかかわらず)要素の数をIntの正の部分に合わせる必要があるためです。 0 until Int.MaxValueのように、1 to Int.MaxValueは正常に動作します。後者はあなたのwhileループがやっていることです(toには右のエンドポイントが含まれています、untilは省略しています)。

とにかく、Scala forはC forとは非常に異なる(はるかに一般的な)クリーチャーであるため、短い答えはいいえ、まったく同じことをすることはできません。しかし、あなたはおそらくfor(あなたが望むほど高速ではないかもしれないが、いくつかのパフォーマンス上のペナルティがあるので)で望むことをやることができます。

4

はい、いいえ、それはあなたが求めているものによって異なります。あなたは[はいあなたは、インスタンスのストリームを使用することができ、最初にそのシーケンスを構築することなく、整数のシーケンスを反復処理できるかどうかを尋ねている場合:

def fromTo(from : Int, to : Int) : Stream[Int] = 
    if(from > to) { 
    Stream.empty 
    } else { 
    // println("one more.") // uncomment to see when it is called 
    Stream.cons(from, fromTo(from + 1, to)) 
    } 

その後:

あなたを書く
for(i <- fromTo(0, 5)) println(i) 

をhasNextを定義してイテレータを作成し、nextは別のオプションです。

「for」構文を使用して「ネイティブ」ループ、つまりオブジェクトのインスタンスによって生成された値を反復処理するのではなく、ネイティブ整数をインクリメントして動作するループを記述できるかどうかを尋ねる場合は、答えは、私が知る限り、いいえです。皆さんが知っているように、 'for'内包は、ジェネレータとその型のネストに応じて、flatMap、filter、map、foreach(いずれもFilterMonadicの特性で定義されています)への呼び出しの構文的な砂糖です。いくつかのループをコンパイルし、そのコンパイラ中間表現をどのように展開するかは、

scalac -Xprint:refchecks 

で表示することができます。

+0

うわー、挑戦的な答えですが、良いものです。私はScalaを学んでいるだけなので、あなたはほとんど慣れていない言葉をたくさん使いましたが、感謝します。 –

+0

'fromTo'の定義は、' Stream'(または 'Iterator')コンパニオンオブジェクトに対して' iterate'メソッドを使うことでさらに単純化できます。 'def fromTo(from:Int、to:Int)= Stream.iterate(from、to-from)(_ + 1)'の行に沿ったものです。しかし、「to to to」を使用することは、より慣用的であり、同じことを達成する。 –

2

そこにはたくさんのものがありますが、私は現時点でそれらをグーグルで見つけられません。次はかなり標準的な次のとおりです。実際には

@scala.annotation.tailrec 
def loop(from: Int, until: Int)(f: Int => Unit): Unit = { 
    if (from < until) { 
    f(from) 
    loop(from + 1, until)(f) 
    } 
} 

loop(0, 10) { i => 
    println("Hi " + i) 
} 
5

うわー、簡単な質問(良いです!)のためのいくつかの素晴らしい技術的な答えしかし、場合には、誰もが単純な答えを探しています:レックスは、右を含む「する」、指摘したように

//start from 0, stop at 9 inclusive 
for (i <- 0 until 10){ 
    println("Hi " + i) 
} 

//or start from 0, stop at 9 inclusive 
for (i <- 0 to 9){ 
    println("Hi " + i) 
} 

エンドポイント、 "それが省略されるまで"。