コンテンツにスキップ

ブロックの捕捉

ブロックを捕捉して 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 という変数に捕捉し、それをメソッドの戻り値としています。The type of proc is Proc(Int32, Int32), a function that accepts a single Int32 argument and returns an 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を使って変更することはできません。