2016-07-07 7 views
1

おそらくこれを行う簡単な方法があるだろう。匿名ブロックへの2つの機能をもたらす。

は私が

def foo(baz) 
    baz.update_first 
    bar(baz) {|i| yield i if block_given? }   
end 

def bar(baz) 
    if baz.has_condition? 
     yield baz.val if block_given? 
     baz.a 
    else 
     baz.b 
    end 
end 

することを仕事のようなものに

foo(baz) {|b| b.modify} 

のように呼ばれ、次の

def foo(baz) 
    baz.update_first 
    if baz.has_condition? 
     yield baz.val if block_given? 
     baz.a 
    else 
     baz.b 
    end 
end 

のようなものをリファクタリングしようとしていますか?どうやって?

私はブロック内の降伏がどのように機能するのかを明確に説明していただきたいと思います... proc.cとvm.cとrelevant git commit in the ruby source codeを読むと、barがfooで呼び出されたときに実行されると思います結果が得られるまでフレームスタックを歩き、fooで定義されたブロックのローカル環境ポインタへフレームスタックを歩きます。これは、yieldがブロックfooに向かって歩いて実行され、次に実行されます。あれは正しいですか?これを行うより良い方法はありますか?

これは制御を反転するのと同じように私にはちょっと変わった感じがしますし、fooにはもっと多くのバズについて知ってもらいたいのですが、このコードでprocやlambdaを渡すことはできません。

答えて

3

ブロックをproc引数に変換している別の構文を見れば、yieldという概念がより明確になると思います。例えば

yieldを使用する場合は、以下の実施例は、同じ

def my_each(arr) 
    arr.each { |x| yield x } 
end 

def my_each(arr, &blk) 
    arr.each { |x| blk.call(x) } 
end 

# Both are called the same way 
my_each([1,2,3]) { |x| print x } 
# => 123 

あり、変数、パラメータのリストでそれを宣言することなく、本方法に使用可能です。パラメータに&符号を前置すると、それがprocに変換されるので、このメソッドでは.callで実行できます。あなたが好きな変数に名前を付けることができます - blkは魔法の言葉ではないことを

def method_a(number, &blk) 
    method_b do 
    method_c do 
     blk.call(number) 
    end 
    end 
end 

def method_b(&blk) 
    blk.call 
end 

def method_c(&blk) 
    blk.call 
end 

method_a(1) { |num| puts num + 1 } 
# => 2 

注:ここでは

はその後に2つのスコープ、それを実行する1つの方法にブロックを提供する例です。ここで

は歩留まりと同じことだ:

def method_a(number) 
    method_b do 
    method_c do 
     yield number 
    end 
    end 
end 

def method_b 
    yield 
end 

def method_c 
    yield 
end 

method_a(1) { |num| puts num + 1 } 
# => 2 

私はそれがPROCに変数を割り当てるので、&blk構文を使用することが明確だと思います。このメソッドでprocが使用されているからといって、Proc.newを実行する必要はありません。ブロックは自動的にprocに変換されます。

関連する問題