프로그래밍백엔드 개발자

러스트에서 '타입 별칭'(type alias)은 어떻게 구현되며, 새로운 타입(newtype pattern)과는 무엇이 다른가, API 설계 시 이러한 차이를 이해하는 것이 왜 중요한가?

Hintsage AI 어시스턴트로 면접 통과

답변.

러스트에서는 type 키워드를 사용하여 기존 타입에 대한 별칭을 만들 수 있습니다. 예:

type Kilometers = i32; fn add_distance(x: Kilometers, y: Kilometers) -> Kilometers { x + y }

Kilometersi32의 또 다른 이름일 뿐이며, 컴파일러는 이 타입들을 구별하지 않고 완전히 상호 교환이 가능합니다.

Newtype pattern은 기존 타입에 대한 새로운 구조체 래퍼를 만드는 것입니다:

struct Kilometers(i32); // 별도의 새로운 타입 fn add_distance(x: Kilometers, y: Kilometers) -> Kilometers { Kilometers(x.0 + y.0) }

이제 Kilometersi32는 서로 다른 타입으로, 혼동할 수 없습니다.

  • 별칭은 가독성이 높거나 일반화된 API를 위해 유용합니다.
  • Newtype 패턴은 타입 안전성을 제공하며, 새로운 타입에 대해 고유한 트레이트를 구현할 수 있게 해줍니다.

이러한 접근 방식 간의 선택은 안전성과 가독성 요구 사항에 따라 달라집니다. 공개 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 패턴을 통해 해결되었습니다.