まず、それは間違っている何が起こっているのか確認するために簡単になりましたように、のは少しそれをクリーンアップしてみましょう:
def call_block(n)
return 0 if n == 1
return 1 if n == 2
yield
call_block(n-1) + call_block(n-2)
end
puts call_block(10) { puts 'Take this' }
今度はそれを通じトレースしてみましょう。
私たちは
call_block(10) { puts 'Take this' }
を呼び出すことによって開始し、n
は10
で、ブロックは、{プットが 'これを取る'}です。 n
は1
でも2
でもないので、ブロックに制御を移すyield
に到着します。
は今、我々はブロックとそれを呼び出していません
call_block(9)
お知らせです
call_block(n-1)
を呼んでいます。したがって、この新しい呼び出しでは、n
は9
であり、ブロックはありません。再び、最初の2行をスキップしてyield
に来ます。
しかし、yield
にはブロックがありません。そのため、ここでコードが爆発的になります。
解決策は明らかで微妙です。明らかな部分は、問題はブロックを通過していないということです。したがって、解決策はブロックを渡す必要があることです。微妙な部分は、どうすればいいのでしょうか?
Rubyブロックを構文的に軽量にするのは、それらが匿名であることです。しかし、ブロックに名前がなければ、それを参照することはできません。参照できない場合は、それを渡すことはできません。
これに対する解決策は、基本的にはブロックよりも「コードの塊」というアイデアのためのより重い抽象化であるRubyの別の構造を使用することです:Proc
。あなたが見ることができるように
def call_block(n, blk)
return 0 if n == 1
return 1 if n == 2
blk.()
call_block(n-1, blk) + call_block(n-2, blk)
end
puts call_block(10, ->{ puts 'Take this' })
、このは少し重い構文的ですが、私たちはProc
に名前を付けるため、再帰呼び出しに沿って、それを渡すことができます。
しかし、このパターンは実際にはRubyの特別なサポートがあるほど一般的です。パラメータリストのパラメータ名の前に&
sigilを置くと、Rubyは引数として渡されたブロックをProc
オブジェクトに「パッケージ化」し、その名前にバインドします。そして、あなたは引数リストの引数の式の前に&
印章を置けば、逆に、それはブロックにProc
ことを「解凍」します:それ以外の場合は、空のブロックの内部
def call_block(n, &blk)
return 0 if n == 1
return 1 if n == 2
yield # or `blk.()`, whichever you prefer
call_block(n-1, &blk) + call_block(n-2, &blk)
end
puts call_block(10) { puts 'Take this' }
それらの「歩留まり」文 - どのブロックは彼らに降伏ですか?私は混乱しています。私は、call_blockメソッド内の異なるyield文のために、それらのブロック自体が呼び出されたと考えました。 – Bruce
'yield'は、現在実行中のメソッドのブロック/ proc引数スロットに渡されたブロックまたはprocを呼び出します。 – yfeldblum
もっと正確に言えば、 'yield'はブロック/ proc引数スロットのメソッドに渡されたブロックまたはprocを呼び出します。このメソッドでは' yield'が字句的に表示されます。 – yfeldblum