25

私は、Scala が常に何に対しても「自然な説明」を持っていることを発見しました。常に「ああ、でもそれは、これとそのパラメーターを使用して、このオブジェクトとそのオブジェクトで呼び出されている関数にすぎません」のようなものです。ある意味で、他の言語からわかるように、実際にコンパイラー・マジックと呼ばれるものはありません。

私の質問は、次のコードで使用されている<-演算子です。

for(i <- 0 to 10) println(i)

この例では、次のように書き換えられていることがわかります。

0.to(10).foreach((i:Int)=>println(i))

しかし、これはiが foreach 関数内の匿名関数にどのように運ばれたかを説明していません。iを書いた時点では、それはオブジェクトではなく、宣言された変数でもありません。では、それは何であり、どのように foreach の内部に引き継がれているのでしょうか?

私の推測では、実際にはコンパイラの魔法である何かをついに発見したということです

御時間ありがとうございます。

明確にするために、私の質問は次のとおりです。 <- 演算子は、コードの1行目でどのように機能しますか? i は、関数として呼び出すことができるオブジェクトではないためです。

4

3 に答える 3

63

Dave の回答を補うために、Scala 言語仕様の「for-comprehensions」の翻訳スキーマを次に示します。

内包表記は、列挙子の列挙によって生成された各バインディングのfor (enums) yield e式を評価します。e列挙子シーケンスは常にジェネレーターで始まります。この後に、さらにジェネレーター、値の定義、またはガードを続けることができます。

ジェネレーターは、 pattern に対して何らかの方法で一致p <- eする式からバインディングを生成します。値の定義は、値の名前(またはパターン内の複数の名前) を式の評価結果にバインドします。ガードには、列挙されたバインディングを制限するブール式が含まれています。epval p = eppeif e

mapジェネレーターとガードの正確な意味は、 、filterflatMap、およびの 4 つのメソッドの呼び出しへの変換によって定義されますforeach。これらの方法は、キャリアの種類ごとに異なる方法で実装できます。

翻訳スキームは次のとおりです。最初のステップでは、すべての generator p <- e、ここで p は反駁不可能 (§8.1) のタイプでeはありません。

 p <- e.filter { case p => true; case _ => false }

次に、すべての内包表記がなくなるまで、次の規則が繰り返し適用されます。

  • for-comprehensionfor (p <- e) yield e0は に変換されe.map { case p => e0 }ます。

  • for-comprehensionfor (p <- e) e0は に変換されe.foreach { case p => e0 }ます。

  • for-comprehension for (p <- e; p0 <- e0 . . .) yield e00、ここで . . . ジェネレーターまたはガードの (場合によっては空の) シーケンスであり、次のように変換されます
    e.flatMap { case p => for (p0 <- e0 . . .) yield e00 }

  • 理解のためのfor (p <- e; p0 <- e0 . . .) e00場所。. . ジェネレーターまたはガードの (場合によっては空の) シーケンスであり、次のように変換されます
    e.foreach { case p => for (p0 <- e0 . . .) e00 }

  • p <- eガードが続くジェネレーターif gは、単一のジェネレーターに変換され
    p <- e.filter((x1, . . . , xn) => g )
    ますx1。. . 、xnの自由変数ですp

  • p <- e値の定義が続くジェネレーターval p0 = e0は、次の値のペアのジェネレーターに変換されます。ここで、xx0は新しい名前です。

    val (p, p0) <- 
      for(x@p <- e) yield { val x0@p0 = e0; (x, x0) }
    
于 2010-09-20T18:59:33.313 に答える
18

<-は言語で定義されたキーワードシンボルです=>が、(定義されたシンボルである)とは明らかに対照的->です。iこれは基本的なScala文法の一部であるため、ユーザー定義の構成では実行できないバインディング(この例では)を作成するために使用できます。

于 2010-09-20T19:37:35.343 に答える
7

この場合、これは実際にはちょっとしたコンパイラの魔法です。for-comprehension から filter/map/flatmap 形式への変換は、update および apply メソッドの特殊な形式の変換によく似た、特殊な desugar です。

于 2010-09-20T18:23:31.357 に答える