30

次のコードが正常に実行されるのはなぜですか

p (1..1000).inject(0) { |sum, i|
    sum + i
}

ただし、次のコードではエラーが発生します

p (1..1000).inject(0) do |sum, i|
    sum + i
end

warning: do not use Fixnums as Symbols
in `inject': 0 is not a symbol (ArgumentError)

それらは同等であるべきではありませんか?

4

3 に答える 3

36

中括弧を使用して記述されたブロックは、意図したとおりに inject メソッドにバインドされ、正常に動作します。

ただし、do/end ブロックにカプセル化されたブロックは、p メソッドにバインドされます。このため、注入呼び出しには関連するブロックがありません。この場合、inject は引数 (この場合は 0) をすべてのオブジェクトで呼び出すメソッド名として解釈します。Bacuase 0 はメソッド呼び出しに変換できるシンボルではないため、警告が発生します。

于 2010-01-24T16:47:33.947 に答える
7

問題はp冒頭にあります。これらを省略すると、両方とも正常に動作することがわかります。

# Works!
[5, 6, 7].inject(0) do |sum, i| # Correctly binds to `inject`.
  sum + i
end

# Works too!
[5, 6, 7].inject(0) { |sum, i|  # Correctly binds to `inject`.
  sum + i
}

しかし、これはうまくいきません:

# Kablammo! "p" came first, so it gets first dibs on your do..end block.
# Now inject has no block to bind to!
p [5, 6, 7].inject(0) do |sum, i|   # Binds to `p` -- not what you wanted.
  sum + i
end
于 2010-01-24T16:52:53.243 に答える
6

これは、do/end とブラケットの間のバインドの違いの影響のように見えます。

上記のように使用されているブラケットは、チェーンされた最後の関数にバインドされますが、do/end は最初の関数にバインドされます。

ちょっと変な言い方だと思いますが、基本的に最初のインスタンスはブロックを関数 'inject' に渡し、2 番目のインスタンスは実際にブロックを最初のメソッド 'p' に渡そうとしています。

于 2010-01-24T16:47:03.200 に答える