C.W.K.
Stream
Lesson 05 of 05 · published

제네릭 첫 맛보기

~11 min · types, generics, structs

Level 0Rust 호기심러
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

지금까진 한 타입에만 통하는 코드를 썼어. 제네릭은 한 번 써서 여러 타입에 통하게 해줘 — Rust 의 컴파일 타임 타입 안전을 포기하지 않고.

제네릭이 푸는 문제

i32 좌표 둘짜리 Point 를 상상해. 이제 f64 좌표짜리가 필요해. 타입만 다르게 struct 를 복붙하는 게 제네릭이 죽이려고 존재하는 그 중복이야. 제네릭 파라미터 T 는 '나중에 고를 어떤 타입' 을 대신하고, 컴파일러가 네가 실제로 쓰는 각 구체 타입마다 특화된 버전을 찍어내.

제네릭 struct 와 메서드

struct Point<T> { x: T, y: T } 는 어떤 타입 T 에든 통해. 메서드는 impl<T> Point<T> 에 들어가고. 각 사용 지점에서 Point<i32>Point<f64> 는 구별되고 완전히 타입 검사된 타입이야. 런타임 비용은 없어: 제네릭은 monomorphize 돼 — 컴파일러가 타입마다 구체 코드를 생성하니, 각 버전을 손으로 쓴 것만큼 빠르게 돌아.

제네릭은 zero-cost 야. Java 의 type erasure 나 Python 의 duck typing 과 달리 Rust 는 monomorphize 해: 각 구체 인스턴스화가 자기 컴파일된 코드가 돼. 제네릭의 재사용성을 손으로 특화한 타입의 속도로 얻어 — boxing 도, 런타임 디스패치도 없이.

한계, 그리고 다음에 올 것

T 는 저장하고 move 할 순 있지만 많은 걸 해 — T 둘을 더하거나 하나를 출력 못 해, 모든 타입이 그걸 지원하진 않으니까. 'T 는 더할 수 있어야 해' 나 'T 는 출력 가능해야 해' 라고 말하려면 trait bound 가 필요해 — 그리고 trait 이 다음 트랙 전부야. 제네릭과 trait 은 한 아이디어의 두 반쪽이야; 방금 첫 반쪽을 만난 거야.

Code

제네릭 struct 하나, 구체 타입 여럿·rust
#[derive(Debug)]
struct Point<T> {
    x: T,
    y: T,
}

impl<T> Point<T> {
    fn new(x: T, y: T) -> Self {
        Self { x, y }
    }
}

fn main() {
    let ints = Point::new(1, 2);        // Point<i32>
    let floats = Point::new(1.5, 2.5);  // Point<f64> — 같은 struct, 다른 T
    println!("{ints:?} {floats:?}");
}

External links

Exercise

new 생성자가 있는 Point<T> 를 정의하고 Point<i32>Point<f64> 둘 다 만들어. 그다음 x + y 를 더하는 메서드를 쓰려 하고 컴파일러 에러를 읽어. 맨 T 는 왜 + 로 못 더해?
Hint
모든 타입이 + 를 지원하진 않으니, 컴파일러가 제약 없는 Tx + y 를 거부해. T: std::ops::Add 같은 trait bound 가 필요해 — 바로 Traits 트랙이 다음에 가르치는 거야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고
💛 by 똘이warm

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.