러스트에서는 type 키워드를 사용하여 기존 타입에 대한 별칭을 만들 수 있습니다. 예:
type Kilometers = i32; fn add_distance(x: Kilometers, y: Kilometers) -> Kilometers { x + y }
Kilometers는 i32의 또 다른 이름일 뿐이며, 컴파일러는 이 타입들을 구별하지 않고 완전히 상호 교환이 가능합니다.
Newtype pattern은 기존 타입에 대한 새로운 구조체 래퍼를 만드는 것입니다:
struct Kilometers(i32); // 별도의 새로운 타입 fn add_distance(x: Kilometers, y: Kilometers) -> Kilometers { Kilometers(x.0 + y.0) }
이제 Kilometers와 i32는 서로 다른 타입으로, 혼동할 수 없습니다.
이러한 접근 방식 간의 선택은 안전성과 가독성 요구 사항에 따라 달라집니다. 공개 API 및 특히 타입 안전한 단위를 위해서는 newtype을 사용하는 것이 좋습니다.
러스트에서
type별칭과 newtype 패턴의 차이는 무엇인가? 타입 별칭의 연산을 제한하는 것이 가능한가?
종종 별칭을 사용하여 접근 제어 및 연산 제한을 할 수 있다고 답하지만, 이는 사실이 아닙니다. 별칭은 새로운 타입을 생성하지 않기 때문에 고유한 트레이트를 구현할 수 없습니다. 오직 newtype 패턴만이 별도의 타입으로, 고유한 동작을 구현할 수 있습니다.
type UserId = u64; struct UserIdNew(u64); trait Foo { fn foo(&self); } // UserId에 대해 Foo를 구현할 수 없습니다. 이는 단순히 u64입니다. // UserIdNew에 대해서는 가능합니다.
이야기
프로젝트에서 서로 다른 단위를 사용하기 위해 별칭으로 미터와 밀리미터를 측정했습니다:
type Millimeters = u32; type Meters = u32;최종 코드에서 실수로 밀리미터와 미터를 더해 계산 오류가 발생했습니다. 타이핑이 작동하지 않았고, 컴파일러는 이를 감지하지 못했습니다. newtype으로 변경하자 문제가 해결되었습니다.
이야기
공개 API에서 서로 다른 엔티티의 식별자를 위해 별칭을 사용했습니다 (
type UserId = u64;,type OrderId = u64;). 혼란이 생겨 누군가가 매개변수를 혼동하여 버그가 프로덕션에 발생했습니다. 이들은 타입으로 구별할 수 없었습니다.
이야기
개발자가 타입 별칭에 대한 Display 트레이트의 고유한 동작을 구현하려고 했습니다:
type MyType = String; impl Display for MyType { ... }컴파일러는 오류를 발생시켰습니다: "cannot implement trait for type alias". 문제는 newtype 패턴을 통해 해결되었습니다.