2010-01-24 17 views
28

Dlaczego jest to, że następujący kod działa poprawnieRuby Drukuj Inject Do Składnia

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

Ale poniższy kod daje błąd

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) 

Powinny one nie być równoważne?

Odpowiedz

34

Blok napisany za pomocą nawiasów klamrowych wiąże się z metodą wstrzykiwania, co jest twoim zamiarem i będzie działał dobrze.

Jednak blok zamknięty w bloku do/end będzie wiązał się z metodą p. Z tego powodu wywołanie iniekcji nie ma powiązanego bloku. W takim przypadku inject będzie interpretował argument, w tym przypadku 0, jako nazwę metody do wywołania każdego obiektu. Bacuase 0 nie jest symbolem, który można przekształcić w wywołanie metody, spowoduje to ostrzeżenie.

6

To wygląda jak efekt różnicy w wiązaniu pomiędzy DO/koniec i wsporniki:

wsporniki, używane jak jesteś wyżej, będzie wiązać się z ostatniej funkcji przykuty podczas zrobić/końcowy będzie wiązać się z pierwszym.

Myślę, że jest to rodzaj dziwnego sposobu, aby to powiedzieć, ale w zasadzie pierwszy przypadek przechodzi blok do funkcji "wstrzyknąć", podczas gdy drugi faktycznie próbuje przekazać blok do pierwszej metody "p".

+1

„, podczas gdy drugi jest w rzeczywistości stara się przekazać bloku do pierwszej metody (1 ..1000). " Ustaw "na pierwszą metodę" p "i masz rację. – sepp2k

+0

Poprawiłem to. przeoczyłem to w powyższym kodzie na pierwszy rzut oka! – Pete

6

Problem polega na tym, że na początku jest p. Jeśli pominąć te zobaczysz, że oba działają dobrze:

# 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 
} 

Ale to nie będzie działać:

# 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