뉴타입 패턴
안전성과 명확성을 위해 형식을 감싸 보세요.
뉴타입 패턴은(는) CoddyKit의 무료 Learn Rust Coding 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Learn Rust Coding 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Learn Rust Coding 강의에는 총 4개의 강의가 포함되어 있습니다.
Newtype이란 무엇인가요
newtype은 기존 타입을 감싸서 고유한 정체성을 부여하는 단일 필드 튜플 구조체입니다. struct Meters(f64)는 일반적인 f64를 담고 있어도 완전히 새로운 타입입니다.
래퍼는 실행 시 비용이 0이지만, 원시 타입으로는 표현할 수 없는 의미를 컴파일러가 확인하게 합니다.
struct Meters(f64);
struct Seconds(f64);단위 혼동 방지하기
원시 타입은 서로 혼동하기 쉽습니다. 거리와 시간이 모두 f64라면 호출할 때 둘을 바꿔도 막을 방법이 없습니다.
각 값을 고유한 newtype으로 감싸면 이런 실수가 조용한 버그가 아니라 컴파일 오류가 됩니다.
fn speed(d: Meters, t: Seconds) -> f64 {
d.0 / t.0
}
// speed(Seconds(2.0), Meters(10.0)) -> compile error내부 값에 접근하기
튜플 인덱스 .0을 통해 감싼 값에 접근합니다. 많은 newtype은 편리한 변환을 위해 메서드를 제공하거나 From을 구현하기도 합니다.
struct UserId(u64);
impl UserId {
fn value(&self) -> u64 { self.0 }
}
fn main() {
let id = UserId(42);
println!("id = {}", id.value());
}불변 조건 캡슐화하기
내부 필드를 비공개로 만들고 생성자에서 유효성을 검사하십시오. 그러면 newtype의 모든 값이 유효하다는 보장이 생겨 이후 코드에서 다시 검사할 필요가 없습니다.
pub struct Email(String);
impl Email {
pub fn new(s: &str) -> Option<Email> {
if s.contains('@') {
Some(Email(s.to_string()))
} else {
None
}
}
}고아 규칙
Rust에서는 외부 트레이트를 외부 타입에 구현할 수 없습니다. 트레이트와 타입 중 어느 것도 소유하지 않으므로 impl Display for Vec<T>를 작성할 수 없습니다.
이 규칙은 크레이트 전체에서 트레이트 일관성을 안전하게 유지하지만, 유용한 구현을 막을 수도 있습니다.
Newtype으로 고아 규칙 우회하기
newtype가 사용자의 크레이트에 정의되어 있으므로 이제 로컬 타입을 소유하게 되며, 해당 타입에 어떤 트레이트든 구현할 수 있습니다. 이는 고아 규칙을 우회하는 표준적인 방법입니다.
use std::fmt;
struct Wrapper(Vec<String>);
impl fmt::Display for Wrapper {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}]", self.0.join(", "))
}
}실행 가능한 래퍼 표시
여기서는 이전 장면의 래퍼를 실제로 사용합니다. Wrapper를 소유하고 있으므로 여기에 Display를 구현할 수 있으며, 프로그램은 결합된 목록을 출력합니다.
use std::fmt;
struct Wrapper(Vec<String>);
impl fmt::Display for Wrapper {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}]", self.0.join(", "))
}
}
fn main() {
let w = Wrapper(vec!["a".into(), "b".into()]);
println!("{}", w);
}API 표면 제한하기
강력한 타입을 래핑하면 안전한 일부 기능만 노출할 수 있습니다. NonEmptyVec는 비우는 것을 허용하는 변경 메서드를 숨겨 불변식을 유지할 수 있습니다.
pub struct NonEmptyVec<T>(Vec<T>);
impl<T> NonEmptyVec<T> {
pub fn new(first: T) -> Self {
NonEmptyVec(vec![first])
}
pub fn first(&self) -> &T {
&self.0[0]
}
}비용 없는 추상화
필드가 하나인 newtype은 래핑된 값과 동일한 메모리 배치를 가집니다. 컴파일러가 래퍼를 제거하므로 여기서 얻는 안전성에는 실제 실행 시간 비용이 들지 않습니다.
#[repr(transparent)]를 추가하면 동일한 배치가 보장되며, 이는 FFI에서 중요합니다.
#[repr(transparent)]
struct Celsius(f64);Newtype에서 트레이트 파생하기
newtype은 적절한 경우 내부 값처럼 동작하도록 표준 트레이트를 파생하는 경우가 많습니다. 트레이트를 파생하면 키, 비교, 디버그 출력에 편리하게 사용할 수 있습니다.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct ProductId(u32);
fn main() {
let a = ProductId(7);
let b = a.clone();
println!("{:?} == {:?}: {}", a, b, a == b);
}Newtype과 타입 별칭 비교
newtype을 타입 별칭과 혼동하지 마십시오. type Meters = f64는 단순한 이름일 뿐이며, 여전히 f64이고 추가적인 안전성을 제공하지 않습니다.
newtype인 struct Meters(f64)는 컴파일러가 별도로 구분할 수 있는 완전히 다른 타입입니다.
type Km = f64; // alias: interchangeable with f64
struct Mi(f64); // newtype: distinct from f64빠른 확인
타입 별칭과 달리 newtype이 유용한 이유를 생각해 보십시오.
정리
newtype 패턴은 기존 타입을 필드 하나짜리 튜플 구조체로 래핑하여, 실행 시간 비용 없이 고유한 정체성을 얻습니다. 이를 통해 값이 뒤바뀌는 문제를 방지하고, 비공개 필드 뒤에 불변식을 캡슐화하며, 고아 규칙을 우회하여 외부 트레이트를 구현할 수 있습니다.
타입 별칭과 달리 newtype은 실제로 분리된 타입입니다.
자주 묻는 질문
“뉴타입 패턴” 강의는 무료인가요?
네 — “뉴타입 패턴” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Learn Rust Coding 강의 전체를 잠금 해제할 수 있습니다. Learn Rust Coding 강의에는 총 4개의 강의가 포함되어 있습니다.
“뉴타입 패턴”에서 뭘 배우나요?
안전성과 명확성을 위해 형식을 감싸 보세요. 브라우저에서 직접 실행하는 실습 코드로 Learn Rust Coding을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Learn Rust Coding을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Learn Rust Coding은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“뉴타입 패턴” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Learn Rust Coding 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Learn Rust Coding 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.