형 제한
형 제한 (as)
as 의사 메서드(pseudo-method)는 표현식의 타입을 특정 타입으로 좁혀 주는 역할을 해요. 어떤 상황에서 필요해지는지 예시로 볼게요.
if some_condition
a = 1
else
a = "hello"
end
# a : Int32 | String
위 코드에서 a의 타입은 Int32 | String 유니온이에요. 그런데 if가 끝난 뒤에 a가 무조건 Int32라고 확신할 수 있는 상황이라면, 컴파일러에게 그렇게 다루라고 강제할 수 있어요.
a_as_int = a.as(Int32)
a_as_int.abs # works, compiler knows that a_as_int is Int32
출처: Crystal 공식 문서
본문
as 의사 메서드는 런타임 검사를 수행해요. 만약 a가 실제로 Int32가 아니었다면 예외가 발생하죠.
이 표현식의 인자는 타입이에요.
어떤 타입이 다른 타입으로 제한될 수 없는 상황이라면 컴파일 타임에 오류가 발생해요.
1.as(String) # Compile-time error
참고
as로 서로 관련 없는 타입으로 변환할 수는 없어요. 다른 언어의cast와는 달라요. 정수·부동소수점·문자 타입에는 이런 변환을 위한 메서드가 따로 있어요. 아니면 아래에서 설명할 포인터 캐스트를 쓰는 방법도 있어요.
포인터 타입 간 변환
as 의사 메서드는 포인터 타입 간에도 캐스트할 수 있어요.
ptr = Pointer(Int32).malloc(1)
ptr.as(Int8*) # :: Pointer(Int8)
이 경우에는 런타임 검사가 일어나지 않아요. 포인터는 안전하지 않기 때문인데, 이런 캐스팅은 보통 C 바인딩이나 저수준 코드에서만 필요해요.
포인터 타입과 다른 타입 간 변환
포인터 타입과 Reference 타입 사이의 변환도 가능해요.
array = [1, 2, 3]
# object_id returns the address of an object in memory,
# so we create a pointer with that address
ptr = Pointer(Void).new(array.object_id)
# Now we cast that pointer to the same type, and
# we should get the same value
array2 = ptr.as(Array(Int32))
array2.same?(array) # => true
이 경우에도 포인터가 관여하기 때문에 런타임 검사가 수행되지 않아요. 이런 캐스팅이 필요한 경우는 앞선 경우보다도 더 드물지만, String 같은 핵심 타입 일부를 Crystal 자체로 구현할 수 있게 해 주고, Reference 타입을 void 포인터로 캐스팅해 C 함수에 넘겨 주는 것도 가능하게 해요.
더 큰 타입으로 캐스팅하기
as 의사 메서드는 표현식을 더 "큰" 타입으로 캐스팅할 수도 있어요.
a = 1
b = a.as(Int32 | Float64)
b # :: Int32 | Float64
위 코드는 크게 쓸모 있어 보이지 않을 수 있는데요, 예를 들어 배열의 원소들을 매핑할 때 유용해요.
ary = [1, 2, 3]
# We want to create an array 1, 2, 3 of Int32 | Float64
ary2 = ary.map { |x| x.as(Int32 | Float64) }
ary2 # :: Array(Int32 | Float64)
ary2 << 1.5 # OK
Array#map 메서드는 블록의 타입을 배열의 제네릭 타입으로 사용해요. 여기서 as 의사 메서드가 없었다면 추론된 타입이 Int32가 되어 Float64를 추가할 수 없었을 거예요.
컴파일러가 블록의 타입을 추론하지 못할 때
때로는 컴파일러가 블록의 타입을 추론하지 못할 때가 있어요. 서로 의존하는 재귀 호출에서 이런 일이 생길 수 있는데, 그럴 때 as로 타입을 알려 줄 수 있어요.
some_call { |v| v.method.as(ExpectedType) }
더 알아보기
- 타입 문법:
as의 인자로 쓰이는 타입 표현 - 예외 처리:
as의 런타임 검사가 실패할 때 발생하는 예외 - C 바인딩: 포인터 캐스팅이 주로 쓰이는 저수준 영역