0

このコードがコンパイルされないのはなぜでしょうか?

val files = (new java.io.File(".")).listFiles
for (file <- files if file.getName.endsWith(".scala")) {
  yield file
}
4

4 に答える 4

10

簡単に言えば、コードに構文エラーが含まれており、yieldキーワードが for-comprehension に渡されるコード ブロック内に含まれているということです。コンパイラがforの直後に中括弧に遭遇すると、それを for 内包表記の副作用として扱い、 yieldの意味を理解できません。

長い答えを得るには、for-comprehension についてもう少し理解する必要があります。

for 内包表記には多くの可能な表現があり、それぞれの一見些細な違いが for 内包表記の動作を大幅に変更します。

最も単純な構文を見てみましょう

for(generator1) { code_block }

generator1code_blockはシンボルであり、リテラル コードではないことに注意してください。ジェネレーターの構文は次のとおりです...

identifier <- expression

どんな表現でもうまくいかないことに注意してください。上記の構文の例では、式はforeachメソッドを定義する何らかのオブジェクトに評価される必要があります。これは、この for 内包表記の構文がcode_blockが副作用のあるコードであることを示しているためです (つまり、外部スコープの変数を変更したり、データベースに書き込みます)。 、または何でも...)、および for 内包表記自体は値に評価されるべきではありません (実際、for 式を変数に代入しようとすると、取得される値は Unit になります)。

あなたの場合、あなたが書くつもりだったのは、次の少し複雑な構文でした。

for(generator1 guard1) yield { code_block }

この構文では、いくつかの新しい構文要素が導入されており、舞台裏ではいくつかの新しい要件も導入されています。まず、少し分解してみましょう。

前と同じように、guard1は実際にはシンボルであり、実際の構文は実際にはもっと似ています...

if boolean_expression

ガード式がある場合、これは前にgenerator1について説明した式も、フィルターメソッドを定義したオブジェクトに評価される必要があることを意味します。特定の trait/interface/abstract クラスについて話していないことに特に注意してください。Scala の "for-comprehensions" はダック タイピングを利用しているため、使用する特定の構文で必要なメソッドを実装するオブジェクトはすべて for-comprehension 構造内で許容されます。これは信じられないほど強力です。

とにかく、新しい構文に戻ると、もう 1 つの重要な違いはyieldsキーワードです。このキーワードは、ジェネレーター式にさらに別の制​​限を課します。つまり、ジェネレーターはmapメソッドを定義する必要があります。ただし、同じ for-comprehension でyieldキーワードが存在する場合と存在しない場合の両方を持つことはできないため、これによりforeachメソッドを持つという制限も解除されます。

そこにyieldsキーワードがあると、code_blockは副作用のないコードではなく、何らかの形の変換であることが期待されます。また、for 内包表記は値に評価されるようになりました (同様に、ジェネレーターに使用される式の出力型に型付けされます)。これは、舞台裏で for-comprehension が実際には単にmapを呼び出しているためです。

これはあなたの質問に答えるのに十分な情報であるはずですが、ここで取り上げなかった多くの情報があるため、map/flatmap/foreach および for-comprehensions を読むことを強くお勧めします。

于 2013-09-05T05:43:00.707 に答える
2

これはあなたにはどう見えますか?

if (flag) {
  // some code
} { else
  // other code
}

else適切な場所にあるように見えますか? for-comprehensions と同じです:yield最初の括弧 (または中括弧) と生成される式の間にある必要があります。

于 2013-09-05T05:20:48.833 に答える
1

聖書が次のように述べているのはそのためです。

Avoid the temptation to write things like this:

  for (file <- filesHere if file.getName.endsWith(".scala")) {
    yield file  // Syntax error!
  }

このアンカーの直前の章と節

これが役立つことを願っています: forforeach の手段の後の expr; for 平均マップの後の yield expr。SOへのその影響に対する答えは確かにあります。

于 2013-09-05T05:06:47.043 に答える
1

中かっこに出力を出す

scala> val r = for (file <- files if file.getName.endsWith(".scala")) yield file

r: Array[java.io.File] = Array()

必要に応じて、yield の後に中かっこを記述できます。yield {file}

于 2013-09-05T05:23:45.710 に答える