2016-04-20 9 views
1

Ich muss einen Block von einer Methode zu einer anderen übergeben (Ich möchte Rails.cache.fetch mit Block an meine Methode übergeben).Block von einer Methode zur anderen übergeben

Ich kann &block entweder zur Parameterliste hinzufügen und diese verwenden, um sie an die nächste Methode zu übergeben, oder ich kann einen neuen Block erstellen und Ausbeute in ihm aufrufen. Ich habe geschrieben ein kurzes Beispiel und Benchmark:

require "benchmark" 

def with_block(&block) 
    do_something 'Test', &block 
end 

def with_yield 
    do_something('Test') { yield } 
end 

def do_something(string) 
    "#{yield} #{string}" 
end 

n = 5_000_000 
Benchmark.bmbm do |x| 
    x.report("&block") do 
    n.times { with_block { "Yo" } } 
    end 
    x.report("yield") do 
    n.times { with_yield { "Yo" } } 
    end 
end 


&block 3.320000 0.010000 3.330000 ( 3.340438) 
yield 1.670000 0.000000 1.670000 ( 1.669504) 
--------------------------------- total: 5.000000sec 

      user  system  total  real 
&block 3.270000 0.010000 3.280000 ( 3.275914) 
yield 1.680000 0.000000 1.680000 ( 1.682768) 

Sieht aus wie { yield } Ansatz viel schneller. Ist es der richtige Weg? Gibt es irgendwelche Probleme, die ich nicht kenne, weil ich in einem neu erstellten Block yield aufgerufen habe?

+0

Sie haben 'Proc', und das spezialisierte' Proc', das 'Lambda' ist, das Sie auch verwenden können. Eine Methode ist auch ein Block, aber zunächst kein Objekt. Sie können eine Methode in ein 'Method'-Objekt konvertieren. Sie haben mehr Möglichkeiten als nur die zwei Möglichkeiten, einen Block zu übergeben. Also ich denke deine Frage ist etwas unvollständig. Es gibt keine besonderen Überlegungen bei der Weitergabe eines anonymen Blocks, außer dass nicht auf den Namen zugegriffen wird (außerhalb der Methode), obwohl Procs und Lambdas beide als "anonym" betrachtet werden, denke ich. – vgoff

+0

'Ausbeute' ist in der Tat schneller. Gerade weil es weniger funktional ist. Sie können den übergebenen Block nur aufrufen. Sie können es beispielsweise nicht an die nächste Methode weitergeben. Dein Test macht keinen Sinn, übrigens. 'do_something' verwendet den Block nicht. –

+0

@SergioTulentsev Sie können es übergeben, indem Sie es aufrufen. 'Klasse Array; def meine_map; Karte {| e | Ausbeute (e)} Ende ende. – sawa

Antwort

3

Kurze Antwort: Verwenden Sie immer yield, es sei denn, Sie haben einen guten Grund, explizit auf &block zu verweisen.

See: Why blocks make ruby methods 439% slower

Mit &block, erhalten Sie eine verdinglichte Proc, auf dem Sie alle Arten von stuff tun können und welche Sie können sich frei bewegen. Mit einem yield und einem impliziten Block können Sie jedoch nur den Block aufrufen.

Mithilfe von yield kann der Interpreter die gesamte Proc-Verifikation umgehen, da er weiß, dass der Entwickler ihn nicht verwenden kann. Daher kann es nur eine C-Level-Struktur beibehalten, anstatt ein Objekt auf Ruby-Ebene einzurichten.

+0

Ich verstehe, warum die Ausbeute schneller ist als ein expliziter Verweis auf '& block'. Gibt es einen besseren Weg, um einen Block von einer Methode zur nächsten zu übergeben, erwarten Sie von einem neuen Block 'Ausbeute' zu ​​nennen? – xx77aBs

+0

Wenn Sie einen Performance-Treffer gut begründen können, können Sie explizit auf & Blockieren verweisen. (Sie verwenden dann nur 'block.call' anstelle von' yield'.) Oder ein anderer Trick, den Sie in Betracht ziehen könnten, ist 'Kernel # block_given?': Http://apidock.com/ruby/Kernel/block_given%3F - - die ohne explizite '& block' Deklaration verwendet werden kann. –

Verwandte Themen