2010-01-24 8 views
28

Warum ist es, dass der folgende CodeRuby-Print Inject Do Syntax

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

fein läuft, aber der folgende Code einen Fehler gibt

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) 

Sollten sie nicht gleichwertig sein?

Antwort

34

Der mit den geschweiften Klammern geschriebene Block bindet sich an die inject-Methode, was Ihre Absicht ist, und es wird gut funktionieren.

Der Block, der im do/end-Block gekapselt ist, wird jedoch an die p-Methode gebunden. Aus diesem Grund hat der inject-Aufruf keinen zugeordneten Block. In diesem Fall interpretiert inject das Argument, in diesem Fall 0, als einen Methodennamen, der jedes Objekt aufruft. Bacuase 0 ist kein Symbol, das in einen Methodenaufruf umgewandelt werden kann. Dies wird zu einer Warnung führen.

6

Dies sieht aus wie eine Wirkung der Differenz zwischen do/end und Klammern in der Bindung:

Klammern, verwendet, wie Sie oben sind, auf die letzte Funktion gekettet, während tun binden/Ende mit dem ersten binden.

Ich denke, das ist eine Art eine seltsame Art, es zu sagen, aber im Grunde die erste Instanz übergibt den Block an die Funktion 'inject', während der zweite versucht, den Block auf die erste Methode 'p' zu übergeben.

+1

„, während die zweite tatsächlich versucht, den Block auf die erste Methode zu übergeben (1 ..1000). " Machen Sie das "zur ersten Methode' p' "und Sie sind richtig. – sepp2k

+0

Ich habe es korrigiert. übersehen, dass in dem Code oben auf den ersten Blick! – Pete

6

Das Problem ist mit dem am Anfang. Wenn Sie diese weglassen werden Sie sehen, dass beide gut funktionieren:

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

Aber das wird nicht funktionieren:

# 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