2 Stimmen

Wie übergebe ich einen Block an eine Methode, deren Name mit einem Gleichheitszeichen endet?

Das klingt seltsam, nicht wahr?

class Dummy
  def foo=(value); end
end

Dummy.new.foo = 1 { |x| x } # => syntax error
Dummy.new.foo=(1) { |x| x } # => syntax error

ich habe jede Permutation von Leerzeichen, Klammern, Kommas ausprobiert; kein Glück. ich bin verwirrt. ich habe nie vermutet, dass Methoden, die mit '=' enden, etwas Besonderes sind. ist es ein Fehler? ist es beabsichtigt? wenn beabsichtigt, warum? ist es dokumentiert? wo? bitte teilen Sie Ihre Erkenntnisse mit.

danke

ps. ruby ist 1.9.2p290 (2011-07-09 Revision 32553) [x86_64-darwin11.0.1]

2voto

Phrogz Punkte 283167

Der Syntaxzucker für Methoden, die auf = macht es zu etwas Besonderem. Sie können immer noch Dinge tun, wie mehrere Argumente an diese Methode übergeben, oder einen Block übergeben, aber nicht in einer hübschen oder bequemen Weise:

class Foo
  def bar=(a,b=nil)
    p [a,b]
    if block_given?
      yield "hi"
    else
      puts "No block"
    end
  end
end

f = Foo.new
f.bar = 42
#=> [42, nil]
#=> No block

f.bar = 42, 17
#=> [[42,17], nil]
#=> No block

f.send(:bar=,42,17) do |x|
  puts "x is #{x.inspect}"
end
#=> [42, 17]
#=> x is "hi"

Eine weitere Besonderheit dieser Methoden besteht darin, dass sie beim Aufruf mit dem Syntaxzucker den rechten Wert und nicht den Rückgabewert der Methode auswerten:

class Foo
  def bar=(a)
    return 17 # really explicit
  end
end

f = Foo.new

x = (f.bar = 42)
p x
#=> 42

x = f.send(:bar=,42)
p x
#=> 17

0voto

matt Punkte 76615

Es geht nicht so sehr darum, dass die Methoden selbst etwas Besonderes sind, sondern eher darum, wie Ruby mit Zuweisungen umgeht (wie foo = bar ). Zuerst wird die rechte Seite ausgewertet, dann wird die linke Seite ausgewertet und die entsprechende Aktion durchgeführt. Handelt es sich bei der linken Seite um ein Objektattribut, so wird die entsprechende Setter-Methode aufgerufen.

In Ihrem Beispiel also:

Dummy.new.foo = 1 { |x| x }

Zunächst versucht Ruby, die Auswertung von 1 { |x| x } was die Ursache für den Syntaxfehler ist.

Dummy.new.foo=something bedeutet eigentlich nicht "Aufruf der Methode namens foo= ", bedeutet aber eigentlich eher etwas wie "evalualate something und bestimmen dann, was `Dummy.new.foo ist, und wenn es wie ein Objektattribut aussieht, fügen Sie = an den Namen anhängen und diese Methode aufrufen". Dies ist der Grund Dummy.new.foo= y Dummy.new.foo = funktionieren beide auf die gleiche Weise.

Sie können diese Methoden aufrufen mit send und kann damit einen Block übergeben:

Dummy.new.send "foo=", 2 do
  puts "HI"
end

Der Grund dafür ist, dass mit send können Sie die aufzurufende Methode explizit benennen.

Das Endergebnis ist natürlich, dass Methoden, die auf = scheinen einige "besondere" Verhaltensweisen zu haben, die Sie beachten müssen, aber es könnte nützlich sein, zu verstehen, was tatsächlich vor sich geht.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X