Scalaは常に何かに対して「自然な説明」を持っていることがわかりました。常に「ああ、でもこれとそのオブジェクトでこれとそのパラメータを使って呼び出される関数です」のようなものです。ある意味、他の言語から知っているように、実際にはコンパイラの魔法はありません。
私の質問は、次のコードで使用されている<-演算子に関するものです。
for(i <- 0 to 10) println(i)
この例では、次のように書き換えられていることがわかります。
0.to(10).foreach((i:Int)=>println(i))
しかし、これはiがforeach関数内の無名関数にどのように持ち込まれたかを説明していません。 iと書いた時点では、それはオブジェクトではなく、まだ宣言された変数でもありません。それで、それは何ですか、そしてそれはどのようにforeachの内部に持ち越されますか?
私の推測では、私はついに実際にコンパイラの魔法である何かを発見したと思います
御時間ありがとうございます。
明確にするために私の質問は次のとおりです。iは関数として呼び出すことができるオブジェクトではないため、コードの1行目で<-演算子はどのように機能しますか。
<-
は、=>
と同様に、言語で定義されたキーワードシンボルですが、->
(定義されたシンボル)とは明らかに対照的です。これは基本的なScala文法の一部であるため、ユーザー定義では実行できないバインディング(この例ではi
の場合)を作成するために使用できます。コンストラクト。
Daveの答えを補強するために、ここにScala言語仕様からの 'for-comprehensions'の翻訳スキーマがあります:
内包表記
for (enums) yield e
は、列挙型列挙型によって生成された各バインディングの式e
を評価します。列挙子シーケンスは常にジェネレーターで始まります。この後に、さらにジェネレーター、値定義、またはガードを続けることができます。ジェネレーター_
p <- e
_は、式e
からバインディングを生成します。これは、パターンp
に対して何らかの方法で照合されます。値の定義_val p = e
_は、値の名前p
(またはパターンp
の複数の名前)を式e
の評価結果にバインドします。ガード_if e
_には、列挙されたバインディングを制限するブール式が含まれています。ジェネレーターとガードの正確な意味は、
map
、filter
、flatMap
、およびforeach
の4つのメソッドの呼び出しへの変換によって定義されます。これらのメソッドは、さまざまなキャリアタイプに対してさまざまな方法で実装できます。翻訳スキームは次のとおりです。最初のステップでは、すべてのジェネレーター_
p <- e
_(pはe
のタイプに対して反駁できない(§8.1))は次のように置き換えられます。_p <- e.filter { case p => true; case _ => false }
_次に、すべての理解がなくなるまで、次のルールが繰り返し適用されます。
理解のための
for (p <- e) yield e0
は_e.map { case p => e0 }
_に翻訳されます。理解のための
for (p <- e) e0
は_e.foreach { case p => e0 }
_に翻訳されます。理解のための
for (p <- e; p0 <- e0 . . .) yield e00
、ここで。 。 。ジェネレータまたはガードの(おそらく空の)シーケンスであり、次のように変換されます。e.flatMap { case p => for (p0 <- e0 . . .) yield e00 }
。For-comprehension
for (p <- e; p0 <- e0 . . .) e00
where。 。 。ジェネレータまたはガードの(おそらく空の)シーケンスであり、次のように変換されます。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
_が続くと、値のペアの次のジェネレーターに変換されます。ここで、x
と_x0
_は新しい名前です。_val (p, p0) <- for(x@p <- e) yield { val x0@p0 = e0; (x, x0) }
_
この場合、それは本当にコンパイラの魔法のビットです。 for-comprehensionからfilter/map/flatmap形式への変換は、updateおよびapplyメソッドの特別な形式の変換と同様に、特別な脱糖です。