블록 캡처

블록 캡처 (Capturing blocks)

블록은 캡처되어 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를 써도 캡처된 블록 안의 기본 수신자(receiver)는 바꿀 수 없어요.

출처: Crystal 공식 문서

더 알아보기 (Learn more)

  • 블록을 Proc으로 캡처하는 더 자세한 내용은 Proc와 블록 문서를 확인해 보세요.