C.W.K.
Stream
Lesson 03 of 07 · published

제네릭 함수

~11 min · traits, generics, monomorphization

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

Types 트랙에서 제네릭 struct 를 만났어. 제네릭 함수 는 같은 아이디어를 동작에 적용한 거야: 로직을 한 번 쓰고, 맞는 모든 타입에 돌려.

함수의 타입 파라미터

fn first<T>(list: &[T]) -> &T 는 아무 타입 T 의 슬라이스에 통해. 이름 뒤의 <T> 가 타입 파라미터를 도입해, lifetime 이나 제네릭 struct 랑 정확히 똑같이. 각 호출에서 컴파일러가 인자로부터 T 가 뭔지 알아내 — 명시적으로 쓸 일은 드물어.

또 monomorphization

제네릭은 런타임 비용이 없어. 컴파일러가 네가 실제로 부르는 각 구체 타입마다 특화 복사본을 생성해 — i32 용 하나, &str 용 하나, 각각 손으로 쓴 것만큼 빨라. 제네릭의 재사용성을 특화 함수의 속도로, 런타임 디스패치 없이 얻어.

제네릭 코드는 컴파일러가 채우는 템플릿 코드야. 네가 쓰는 각 구별되는 타입이 자기 기계어를 찍어내. 그게 Rust 제네릭이 'zero-cost' 인 이유야 — 추상화는 컴파일 타임에만 존재하고; 실행 바이너리엔 구체적이고 특화된 함수들이 들어 있어.

trait 이 필요한 함정

T 는 거의 쓸모없어 — move 는 되는데 비교, 더하기, 출력은 못 해, 모든 타입이 그 연산을 지원하진 않으니까. '이 T 는 비교 가능해' 라고 말하려면 trait bound 로 제약해 — 바로 다음 레슨. 제네릭은 파라미터를 주고; trait 은 거기에 능력을 줘.

Code

제네릭 함수는 타입을 넘나든다·rust
// 값을 MOVE/반환만 하는 제네릭은 bound 불필요:
fn first<T>(list: &[T]) -> &T {
    &list[0]
}

// 이건 컴파일 안 됨 — 맨 T 는 > 로 비교 못 함:
// fn largest<T>(list: &[T]) -> &T {
//     let mut biggest = &list[0];
//     for item in list {
//         if item > biggest { biggest = item; } // error: T 가 > 미지원일 수
//     }
//     biggest
// }

fn main() {
    println!("{}", first(&[10, 20, 30])); // T = i32
    println!("{}", first(&["a", "b"]));   // T = &str — 같은 코드, 새 T
}

External links

Exercise

제네릭 fn first<T>(list: &[T]) -> &T 를 쓰고 정수 슬라이스랑 문자열 슬라이스에 불러봐. 그다음 > 로 원소를 비교하는 fn largest<T> 를 쓰려 하고 에러를 읽어. bound 없이 first 는 컴파일되는데 largest 는 왜 안 돼?
Hint
first 는 참조만 반환해 — 값을 들여다보지 않으니 아무 T 나 통해. largest> 를 써서 모든 타입이 지원하진 않으니 T: PartialOrd 가 필요해. 다음 레슨이 정확히 그걸 더해.

Progress

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

댓글 0

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

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