17

関数リテラルを使用すると、複数のステートメントであっても中括弧を無視できることがあるのはなぜだろうかといつも思っていました。これを説明するために、複数行の関数リテラルの構文では、ステートメントを中かっこで囲みます。そのようです、

val fl = (x: Int) => {
  println("Add 25 to "+x)
  x + 25
}

ただし、引数が 1 つの関数に渡す場合は、関数リテラルに必要な中かっこを無視できます。

したがって、与えられた関数 f に対して、

def f( fl: Int => Int ) {
  println("Result is "+ fl(5))
}

このように f() を呼び出すことができます。

f( x=> {
  println("Add 25 to "+x)
  x + 25
})
-------------------------
Add 25 to 5
Result: 30

または、関数呼び出しで括弧の代わりに中括弧を使用する場合、関数リテラルから内側の中括弧を削除できます。したがって、次のコードも機能します。

f{ x=>
  println("Add 25 to "+x)
  x + 25
}

上記のコードはより読みやすく、多くの例でこの構文が使用されていることに気付きました。ただし、これが意図したとおりに機能する理由を説明するために、私が見逃した可能性のある特別なルールはありますか?

4

2 に答える 2

29

簡単な構文規則がいくつかあります。仕様の付録は熟読する価値があります。

関数リテラルまたは無名関数 (6.23) は、コンテキストが Expr であるか ResultExpr であるかに応じて、それぞれのx => Exprように見えます。x => Block

関数適用 (6.6) はf(Expr, Expr)or f BlockExpr、つまり のようになりますf{ Block }。つまり、BlockExpr は 内の一連のブロック ステートメントにすぎません{...}

を呼び出すf(g)と、g は Expr なので、関数リテラルとしてx => Expr. Expr は BlockExpr にすることができますx => { ... }

を呼び出すとf{ Block }f { x => ... }ブロックの ResultExpr に関数リテラルが含まれます (これは一連のステートメントであり、中括弧は必要ありません)。

ここでは、anon func がブロックの下部にあることは明らかです。

scala> def m(x: Int=>Int) = x(5)
m: (x: Int => Int)Int

scala> m {
     | val y = 7
     | x => // no brace
     | x+y+1
     | }
res0: Int = 13
于 2012-12-14T06:40:29.033 に答える
14

これは、私にとって Scala を美しいものにしているものの 1 つです。

あなたの質問に対する簡単な答えは次のとおりです。

括弧 ( ) は、単一行の構造を意味します。たとえば、これは機能します:

  def f(fl: Int => Int) {
    println("Result is " + fl(5))
  }

  f(
   x =>
    x + 25)

  f(x => x + 25) // single line

および中括弧 { } は、複数行のステートメント用です。たとえば、これは機能します:

 f { 
   x =>
     println("Add 25 to " + x)
     x + 25
 }   

しかし、このコードは機能しません:

f ( 
  x =>
    println("Add 25 to " + x)
    x + 25
)

コンパイラは次のメッセージを表示します。

値 x は Unit のメンバーではありません 考えられる原因: おそらく「値 x」の前にセミコロンがありませんか?

セミコロンを追加すると、括弧が一致しないために構文エラーが発生します。

これを行おうとすると:

f { x => println("Add 25 to " + x) x + 25 }

コンパイラから次のメッセージが返されます。

value x is not a member of unit

彼が unit のメンバーとして x を見つけようとしていることがわかりますか? お気に入り:

f { println("Add 25 to " + x).x.+(25) }

これは明らかに間違っています。

内側の中括弧を追加すると、次のようになります。

f ( 
  x => {
    println("Add 25 to " + x)
    x + 25 
  }
)

これも機能しますが、中括弧の使用によって通知される複数行のステートメントがまだあります。したがって、コンパイラは、最初に出力してから x に 25 を追加する必要があることを認識しています。

私は以前にそれらの微妙さに噛まれたことがあります。それ以来、主にマップ、flatMaps、foreachs、fors、カリー化を使用しているときに、これらの多くをコーディングして読むことになるため、これらのコーディング方法に注意を払ってきました。

乾杯!

于 2012-12-14T04:34:31.683 に答える