Proc

Proc

함수를 값으로 넘기고 싶을 때가 있죠. C의 함수 포인터처럼, Crystal의 Proc는 함수 포인터에 선택적 컨텍스트(클로저 데이터)를 담은 것이라고 생각하면 돼요.

출처: Crystal 공식 문서

본문

Proc는 선택적 컨텍스트(클로저 데이터)를 가진 함수 포인터를 나타내요. 보통 proc 리터럴로 만들어요.

# A proc without parameters
-> { 1 } # Proc(Int32)

# A proc with one parameter
->(x : Int32) { x.to_s } # Proc(Int32, String)

# A proc with two parameters
->(x : Int32, y : Int32) { x + y } # Proc(Int32, Int32, Int32)

매개변수의 타입은 필수예요. 단, C 바인딩에서 proc 리터럴을 lib fun에 직접 보낼 때는 예외예요.

반환 타입은 proc의 본문에서 추론되지만, 명시적으로 지정할 수도 있어요.

# A proc returning an Int32 or String
-> : Int32 | String { 1 } # Proc(Int32 | String)

# A proc with one parameter and returning Nil
->(x : Array(String)) : Nil { x.delete("foo") } # Proc(Array(String), Nil)

# The return type must match the proc's body
->(x : Int32) : Bool { x.to_s } # Error: expected Proc to return Bool, not String

new 메서드도 제공되는데, 캡처된 블록에서 Proc를 만들어요. 이 형태는 주로 별칭(alias)과 함께 쓸 때 유용해요.

Proc(Int32, String).new { |x| x.to_s } # Proc(Int32, String)

alias Foo = Int32 -> String
Foo.new { |x| x.to_s } # same proc as above

Proc 타입

Proc 타입을 나타낼 때는 이렇게 쓸 수 있어요.

# A Proc accepting a single Int32 argument and returning a String
Proc(Int32, String)

# A proc accepting no arguments and returning Nil
Proc(Nil)

# A proc accepting two arguments (one Int32 and one String) and returning a Char
Proc(Int32, String, Char)

타입 제한, 제네릭 타입 인자 같은 타입이 기대되는 자리에서는 더 짧은 문법을 쓸 수 있어요. 이는 타입 문서에서 설명하죠.

# An array of Proc(Int32, String, Char)
Array(Int32, String -> Char)

호출

Proc를 호출하려면 그 위에서 call 메서드를 호출해요. 인자의 개수는 proc의 타입과 일치해야 해요.

proc = ->(x : Int32, y : Int32) { x + y }
proc.call(1, 2) # => 3

메서드에서 만들기

기존 메서드에서 Proc를 만들 수 있어요.

def one
  1
end

proc = ->one
proc.call # => 1

메서드에 매개변수가 있으면 그 타입을 지정해야 해요.

def plus_one(x)
  x + 1
end

proc = ->plus_one(Int32)
proc.call(41) # => 42

proc는 선택적으로 수신자(receiver)를 지정할 수 있어요.

str = "hello"
proc = ->str.count(Char)
proc.call('e') # => 1
proc.call('l') # => 2

더 알아보기

  • -> 리터럴이 Proc의 기본 생성 방식이고, 매개변수 타입은 필수예요.
  • ->str.count(Char)처럼 수신자를 지정할 수도 있어요. 이렇게 하면 그 객체의 메서드가 묶인 proc가 만들어져요.