팬텀 타입은 사용자 정의 타입의 타입 매개변수 중에서, 그 타입의 어떤 값 생성자에서도 사용되지 않는 매개변수를 말해요.
조금 추상적이니 예시를 하나 볼까요?
pub type Length(unit) {
Length(amount: Float)
}
이 예시에서 unit 타입 매개변수는 Length 값 생성자에서 사용되지 않아요. 그래서 unit은 팬텀 타입이에요.
이렇게 사용되지 않는 타입 매개변수는 쓸모없어 보이지만, Length 값을 어떻게 사용할 수 있는지에 제약을 더하는 데 쓸 수 있어요.
예를 들어 길이를 두 배로 만드는 double 함수를 생각해 봐요. 이 함수는 어떤 단위의 길이와도 동작해서, 타입 매개변수가 제네릭 타입 변수가 돼요.
// This function accepts all Length values
pub fn double(length: Length(unit)) -> Length(unit) {
Length(length.amount *. 2.0)
}
add_inch 함수도 만들 수 있어요. 이 함수는 길이가 인치일 때만 동작해요.
// A unit type for inches. It is never constructed so we don't
// define any constructors for it.
pub type Inches
pub fn add_inch(length: Length(Inches)) -> Length(Inches) {
Length(length.amount +. 1.0)
}
add_inch 함수는 다른 단위 매개변수를 가진 길이는 받지 않아요. 팬텀 타입을 이용해 올바른 단위만 사용되도록 보장한 거예요.
두 길이 값이 같은 단위인지 보장하도록, 둘 모두에 같은 타입 변수를 사용하는 함수를 작성할 수도 있어요.
pub fn add(a: Length(unit), b: Length(unit)) -> Length(unit) {
Length(a.amount +. b.amount)
}
let two_meters: Length(Meters) = Length(2.0)
let two_inches: Length(Inches) = Length(2.0)
add(two_meters, two_meters)
// -> Length(4.0): Length(Meters)
add(two_meters, two_inches)
// Type error! The unit type parameters do not match.
팬텀 타입은 불투명 타입과 잘 어울려요. 다른 모듈에서 Length 값을 만들 수 없다면, 잘못된 단위 타입으로 값이 만들어지지 않도록 보장할 수 있고, 위에서 정의한 함수들만 그 값에 사용되도록 할 수 있어요.
Lucy는 온라인 스티커 가게를 운영하며, 누구나 좋아하는 프로그래밍 언어를 담은 귀여운 스티커를 팔아요. 전 세계 사람들이 Lucy의 스티커를 사 가는데, 여러 가지 통화를 다루는 일이 쉽지 않아요.
Lucy가 가격을 계산할 때 언제나 올바른 통화를 쓰고 있는지 확신할 수 있도록 도와주는 프로그램을 만들어 봐요.
Usd, Eur, Jpy 타입 정의하기이 타입들은 Lucy의 고객이 스티커를 살 때 사용하는 서로 다른 통화를 나타내는 데 쓰여요.
이 타입들은 팬텀 타입으로 사용되며, 생성자가 필요하지 않아요.
Money 타입 정의하기Money 타입은 금액을 나타내는 Int 필드와 통화 팬텀 타입 매개변수를 가져야 하고, 불투명 타입이어야 해요.
dollar, euro, yen 함수 정의하기dollar, euro, yen 함수는 Int 인자를 받아 올바른 통화의 Money 값을 반환해요.
total 함수 정의하기total 함수는 Money 값들로 이루어진 배열을 받아 그 배열에 담긴 금액의 합계를 반환해요.
total([euro(120), euro(200), euro(145)])
// -> euro(465)
Exercism에 가입하고 Gleam 트랙을 개념 33개연습 문제 122개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.