Ja, es ist zunächst ein bisschen rätselhaft.
In Ruby können Methoden einen Codeblock empfangen, um beliebige Codesegmente auszuführen.
Wenn eine Methode einen Block erwartet, ruft sie ihn durch Aufrufen der yield
Funktion auf.
Dies ist beispielsweise sehr praktisch, um eine Liste zu durchlaufen oder einen benutzerdefinierten Algorithmus bereitzustellen.
Nehmen Sie das folgende Beispiel:
Ich werde eine Person
Klasse definieren, die mit einem Namen initialisiert wurde, und eine do_with_name
Methode bereitstellen , die beim Aufrufen nur das name
Attribut an den empfangenen Block übergibt.
class Person
def initialize( name )
@name = name
end
def do_with_name
yield( @name )
end
end
Dies würde es uns ermöglichen, diese Methode aufzurufen und einen beliebigen Codeblock zu übergeben.
Um beispielsweise den Namen zu drucken, würden wir Folgendes tun:
person = Person.new("Oscar")
#invoking the method passing a block
person.do_with_name do |name|
puts "Hey, his name is #{name}"
end
Würde drucken:
Hey, his name is Oscar
Beachten Sie, dass der Block als Parameter eine Variable mit dem Namen empfängt (Hinweis: name
Sie können diese Variable beliebig aufrufen, es ist jedoch sinnvoll, sie aufzurufen name
). Wenn der Code aufgerufen wird yield
, füllt er diesen Parameter mit dem Wert von @name
.
yield( @name )
Wir könnten einen weiteren Block bereitstellen, um eine andere Aktion auszuführen. Kehren Sie beispielsweise den Namen um:
#variable to hold the name reversed
reversed_name = ""
#invoke the method passing a different block
person.do_with_name do |name|
reversed_name = name.reverse
end
puts reversed_name
=> "racsO"
Wir haben genau die gleiche Methode ( do_with_name
) verwendet - es ist nur ein anderer Block.
Dieses Beispiel ist trivial. Interessantere Anwendungen sind das Filtern aller Elemente in einem Array:
days = ["monday", "tuesday", "wednesday", "thursday", "friday"]
# select those which start with 't'
days.select do | item |
item.match /^t/
end
=> ["tuesday", "thursday"]
Oder wir können auch einen benutzerdefinierten Sortieralgorithmus bereitstellen, der beispielsweise auf der Zeichenfolgengröße basiert:
days.sort do |x,y|
x.size <=> y.size
end
=> ["monday", "friday", "tuesday", "thursday", "wednesday"]
Ich hoffe, das hilft Ihnen, es besser zu verstehen.
Übrigens, wenn der Block optional ist, sollten Sie ihn wie folgt aufrufen:
yield(value) if block_given?
Wenn dies nicht optional ist, rufen Sie es einfach auf.
BEARBEITEN
@hmak hat ein repl.it für diese Beispiele erstellt: https://repl.it/@makstaks/blocksandyieldsrubyexample