2016-04-20 9 views
1

あるメソッドから別のメソッドにブロックを渡す必要があります(私のメソッドにブロックが渡されたRails.cache.fetchを呼び出したい)。ブロックをあるメソッドから別のメソッドに渡す

&blockをパラメータリストに追加し、それを次のメソッドに渡すか、新しいブロックを作成してその内部にyieldをコールすることができます。 { yield }アプローチははるかに高速であるように

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) 

が見える:私は簡単な例とベンチマークを書いてきました。それは正しい方法ですか?新しく作成されたブロックの中にyieldを呼び出すことで、私が気付いていない問題はありますか?

+0

あなたには 'Proc'と特殊な' Proc'があり、これも 'lambda'で使えます。 メソッドもブロックですが、最初はオブジェクトではありません。メソッドを 'Method'オブジェクトに変換することができます。 ブロックを渡す2つの方法以外にも選択肢があります。だから私はあなたの質問は多少不完全だと思う。 Procsとlambdaの両方が「匿名」と考えられていますが、名前でアクセスしている以外は(匿名ブロック以外の)匿名ブロックを渡すことは特にありません。 – vgoff

+0

'yield 'は実際より速いです。正確には機能が少ないからです。渡されたブロックのみを呼び出すことができます。たとえば、次のメソッドに渡すことはできません。あなたのテストは意味がありません、btw。 'do_something'はブロックを使用しません。 –

+0

@SergioTulentsevあなたはそれを呼び出して渡すことができます。 'class Array; def my_map;マップ{| e |収量(e)}終了点。 – sawa

答えて

3

短い答え:&blockを明示的に参照する正当な理由がない限り、常にyieldを使用してください。

参照:&blockWhy blocks make ruby methods 439% slower

は、あなたがstuffのすべての種類を行うことができますし、あなたの周りに移動することができるその上で具体化さPROCを取得します。ただし、yieldと暗黙のブロックの場合、ブロックの呼び出しのみに制限されます。

yieldを使用することにより、インタープリタは、開発者がそれを使用できないことを知っているので、すべてのProcの認証をバイパスすることができます。したがって、Rubyレベルのオブジェクトを設定する必要はなく、Cレベルの構造だけを保持することができます。

+0

私はyieldが '&block'を明示的に参照するよりも速い理由を理解しています。あるメソッドから別のメソッドにブロックを渡すより良い方法がありますか?新しいブロックから 'yield'を呼び出すことを期待していますか? – xx77aBs

+0

パフォーマンスヒットの正当な理由がある場合は、明示的に '&block'を参照できます。 (あなたは 'yield'の代わりに' block.call'を使用します)。あるいは、あなたが使うことができる別のトリックは 'Kernel#block_given? 'です:http://apidock.com/ruby/Kernel/block_given%3F - - 明示的な '&block'宣言なしで使うことができます。 –

関連する問題