コンテンツへスキップ

ブロックのキャプチャ

ブロックはキャプチャしてProcに変換できます。Procは、関連付けられたコンテキスト(クロージャデータ)を持つコードブロックを表します。

ブロックをキャプチャするには、メソッドのブロックパラメータとして指定し、名前を付け、入力と出力の型を指定する必要があります。例えば

def int_to_int(&block : Int32 -> Int32)
  block
end

proc = int_to_int { |x| x + 1 }
proc.call(1) # => 2

上記のコードは、int_to_intに渡されたコードブロックをblock変数にキャプチャし、メソッドから返します。procの型はProc(Int32, Int32)で、単一のInt32引数を受け取り、Int32を返す関数です。

このようにして、ブロックはコールバックとして保存できます。

class Model
  def on_save(&block)
    @on_save_callback = block
  end

  def save
    if callback = @on_save_callback
      callback.call
    end
  end
end

model = Model.new
model.on_save { puts "Saved!" }
model.save # prints "Saved!"

上記の例では、&blockの型は指定されていません。これは、キャプチャされたブロックが引数を取らず、何も返さないことを意味します。

戻り値の型が指定されていない場合、proc呼び出しからは何も返されません。

def some_proc(&block : Int32 ->)
  block
end

proc = some_proc { |x| x + 1 }
proc.call(1) # => nil

何かを返すには、戻り値の型を指定するか、アンダースコアを使用して任意の戻り値の型を許可します。

def some_proc(&block : Int32 -> _)
  block
end

proc = some_proc { |x| x + 1 }
proc.call(1) # 2

proc = some_proc { |x| x.to_s }
proc.call(1) # "1"

break と next

returnbreakは、キャプチャされたブロック内では使用できません。nextは使用でき、ブロックを終了して値を返します。

with ... yield

キャプチャされたブロック内のデフォルトのレシーバは、with ... yieldを使用して変更できません。