2016-08-17 2 views
1

Ich schreibe eine einfache Methode, die num zum Rückgabewert des Blocks hinzufügt, der an es übergeben wird, und ich bemerkte, dass & Block und & prc beide funktionieren. Ich weiß, dass ein Proc ein Objekt ist und einer Variablen zugewiesen werden kann, die nützlich sein könnte. Ist das der einzige Unterschied? Gibt es einen Unterschied zwischen diesen beiden, wenn es um Leistung, Konvention oder Vielseitigkeit geht? Ist es besser, & Block statt & prc zu verwenden?Ruby - Ist & prc anders als & blockieren?

def adder(num = 1, &block) 
    yield + num 
end 

gegen

def adder(num = 1, &prc) 
    yield + num 
end 

Antwort

3

Gibt es einen Unterschied zwischen diesen beiden, wenn es um Leistung, Konvention oder Vielseitigkeit?

Es gibt keinen Unterschied zwischen diesen, Sie können es benennen, wie Sie wollen, es ist nur ein Name. Einige Entwickler nennen es &blk einige &block oder &b oder &foo ...

>> def foo &foo 
>> yield 
>> end 
=> :foo 
>> foo do 
?> puts '1' 
>> end 
1 

Streng sagen & ist ein Operator, der Sie auf jedes Objekt anwenden können, und es kümmert sich um das Objekt zu einem Proc Umwandlung durch den Aufruf to_proc().

>> def bar(&some_proc) 
>> some_proc 
>> end 
=> :bar 
>> p = bar { puts 'Call proc' } 
=> #<Proc:[email protected](irb):4> 
>> p.call 
=> Call proc 
>> p.class 
=> Proc 

Nur das einzige, was wichtig ist, sollte der Name informativ sein.

+0

'method' ist ein reservierter Name, und das Definieren einer Methode mit diesem Namen kann problematisch sein. – tadman

0

In Ihrem Beispiel gibt es keinen Unterschied zwischen &block und &prc, weil Sie jeweils nur einen Block übergeben, um in die Methode gerufen zu werden.

Block und Proc sind ähnlich, da sie beide Code-Blöcke sind.

[1,2,3].each {|x| puts x } 

alles innerhalb der {} ist der Block.

Ein Proc ist nur ein Codeblock, den Sie benennen können und der zu einem späteren Zeitpunkt aufgerufen werden kann.

put_element = Proc.new {|x| puts x} 

Dann verwenden Sie put_element als Argument in Ihrer Funktion.

1

Zeile irgendein Argument zu Ihrer Methode der Name ist weitgehend subjektiv. Normalerweise wird &block nur nach Konvention verwendet, aber der Name selbst kann beliebig sein, solange es sich um einen gültigen Variablennamen handelt.

In Ihrem Beispiel deklarieren Sie einen Blocknamen, verwenden den Namen aber nicht. Denken Sie daran, dass beliebig Ruby-Methode einen Block gegeben werden kann, gibt es keine Möglichkeit, dies zu beschränken, aber es ist an der Methode selbst, den Block zu verwenden, wenn es will. Dieser Block kann null oder mehrmals entweder sofort oder irgendwann in der Zukunft genannt werden. Geben Sie den Block der Methode, die Kontrolle übergibt, so achten Sie darauf, die Dokumentation zu jeder gegebenen Methode sorgfältig zu lesen. Es kann Überraschungen geben.

Wenn Sie an die Kette durch einen Block benötigen, erklären es mit einem Namen:

def passes_through(&block) 
    [ 1, 2, 3, 4 ].each(&block) 
end 

Wenn Sie yield auf den Block gehen, gibt es keine Notwendigkeit hier:

def direct_call 
    [ 1, 2, 3, 4 ].each do |n| 
    yield n 
    end 
end 

Wenn Sie‘ re geht um den Anruf zu bewahren und es später verwenden, das ist auch ein Fall für die Namensgebung:

def preserved_call(&block) 
    @callback = block 
end 

def make_callback 
    @callback and @callback.call 
end 

Jeder m ethode kann überprüfen, ob ein Block geliefert wurde:

def tests_for_block 
    if (block_given?) 
    yield 'value' 
    else 
    'value' 
    end 
end 

Es gibt ein klein, aber messbar Kosten um einen Block zu erfassen, indem sie es in der Methodensignatur erklärt, eine Menge Berechnung getan werden muss, richtig die Variablen alle das könnte erfassen in einer Verschlusssituation verwendet werden. Im leistungssensitiven Code sollten Sie dies vermeiden.

Sie können dynamisch einen Block erstellen:

def captures_conditionally 
    if (block_given?) 
    @callback = Proc.new 
    end 
end 

Die Proc.new Methode Kontrolle über nehmen wird, was auch immer Block dem Verfahren zugeführt worden ist, wenn man gewesen ist.