2017-04-13 2 views
5

Je comprends queY a-t-il une différence dans l'utilisation de `yield self` dans une méthode avec les paramètres` & block` et `yield self` dans une méthode sans paramètre` & block`?

def a(&block) 
    block.call(self) 
end 

et

def a() 
    yield self 
end 

conduisent au même résultat, si je suppose qu'il ya un tel bloc a {}. Ma question est - depuis que je suis tombé sur un code comme ça, si cela fait une différence ou s'il y a un avantage d'avoir (si je ne pas utiliser la variable/bloc de référence autre):

def a(&block) 
    yield self 
end 

C'est cas concret où je ne comprends pas l'utilisation de &block:

def rule(code, name, &block) 
    @rules = [] if @rules.nil? 
    @rules << Rule.new(code, name) 
    yield self 
end 
+0

La documentation [Bloc Argument] (http://ruby-doc.org/core-2.4.1/doc/syntax/methods_rdoc.html#label-Block+Argument) montre différents cas d'utilisation. – Stefan

+0

@Stefan J'ai ajouté un cas spécifique où je ne comprends pas l'utilisation de & block, peut-être que je manque quelque chose, alors vous pouvez jeter un oeil? En plus de cela, j'ai lu la documentation et cela correspond à ma compréhension. –

+0

Si vous ne l'utilisez pas explicitement, ne l'ajoutez pas à la liste. Cela rend les invocations plus lentes et confuses. – ndn

Répondre

8

l'avantage que je peux penser est à l'introspection:

def foo;  end 
def bar(&blk); end 

method(:foo).parameters #=> [] 
method(:bar).parameters #=> [[:block, :blk]] 

IDEs et documentation les générateurs pourraient en profiter. Cependant, cela n'affecte pas l'argument de Ruby. Lorsque vous appelez une méthode, vous pouvez passer ou omettre un bloc, qu'il soit déclaré ou invoqué.

+1

Au moins pour moi, il ne s'agit pas seulement d'introspection. Je trouve beaucoup plus facile de regarder la signature de la méthode et de voir si le dernier argument a un «&» par rapport à regarder la méthode entière et essayer de trouver «yield» quelque part. –

1

La principale différence entre

def pass_block 
    yield 
end 
pass_block { 'hi' } #=> 'hi' 

et

def pass_proc(&blk) 
    blk.call 
end 
pass_proc { 'hi' } #=> 'hi' 

est que, blk, une instance de Proc, est un objet et peut donc être transmis à d'autres méthodes. En revanche, les blocs ne sont pas des objets et ne peuvent donc pas être transmis.

def pass_proc(&blk) 
    puts "blk.is_a?(Proc)=#{blk.is_a?(Proc)}" 
    receive_proc(blk) 
end 

def receive_proc(proc) 
    proc.call 
end 

pass_proc { 'ho' } 
blk.is_a?(Proc)=true 
    #=> "ho"