
제네릭은 타입을 일반화(generalize)하여 동일한 로직을 여러 타입에 재사용할 수 있게 해주는 기능입니다.
Rust에서 제네릭은 컴파일 타임에 모노모피제이션(monomorphization) 을 통해 구체적인 타입으로 치환되어 런타임 오버헤드 없이 최적화됩니다.
C++의 템플릿, Java/C#의 제네릭과 유사하지만, Rust는 zero-cost abstraction을 지향 → 성능 손실 없음.
1. 함수 제네릭
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list {
if item > largest {
largest = item;
}
}
largest
}
fn main() {
let numbers = vec![34, 50, 25, 100, 65];
let result = largest(&numbers);
println!("The largest number is {}", result);
let chars = vec!['y', 'm', 'a', 'q'];
let result = largest(&chars);
println!("The largest char is {}", result);
}
결과는 직접 확인해보세요...
2.구조체 제네릭
#[derive(Debug)]
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn new(x: T, y: T) -> Self {
Point { x, y }
}
}
fn main() {
let integer = Point::new(5, 10);
let float = Point::new(1.0, 4.0);
println!("{:?}", integer); // Point { x: 5, y: 10 }
println!("{:?}", float); // Point { x: 1.0, y: 4.0 }
}
결과는 직접 확인해보세요...
3. 열거형 제네릭
enum Option<T> {
Some(T),
None,
}
enum Result<T, E> {
Ok(T),
Err(E),
}
// Option<T>와 Result<T, E>는 이미 Rust 표준 라이브러리에 정의되어 있음
// → 직접 재정의하지 않고, std의 것을 사용 (재정의하면 충돌!)
fn main() {
// ============ Option<T> 예제 ============
println!("=== Option<T> Examples ===");
let some_number: Option<i32> = Some(42);
let some_string: Option<String> = Some("Hello, Rust!".to_string());
let none_value: Option<f64> = None;
println!("some_number: {:?}", some_number); // Some(42)
println!("some_string: {:?}", some_string); // Some("Hello, Rust!")
println!("none_value: {:?}", none_value); // None
// match로 분기 처리
match some_number {
Some(x) => println!("Got a number: {}", x),
None => println!("Got nothing!"),
}
match none_value {
Some(x) => println!("Got a float: {}", x),
None => println!("Got nothing! (as expected)"),
}
// ============ Result<T, E> 예제 ============
println!("\n=== Result<T, E> Examples ===");
let ok_result: Result<i32, &str> = Ok(200);
let err_result: Result<String, i32> = Err(404);
let another_ok: Result<&str, String> = Ok("Success!");
println!("ok_result: {:?}", ok_result); // Ok(200)
println!("err_result: {:?}", err_result); // Err(404)
println!("another_ok: {:?}", another_ok); // Ok("Success!")
// match로 분기 처리
match ok_result {
Ok(value) => println!("Operation succeeded with value: {}", value),
Err(e) => println!("Operation failed with error: {}", e),
}
match err_result {
Ok(value) => println!("Got value: {}", value),
Err(code) => println!("Error code: {}", code),
}
// ============ 실제 함수에서 사용 예시 ============
println!("\n=== Practical Usage ===");
let result1 = divide(10, 2);
let result2 = divide(10, 0);
println!("10 / 2 = {:?}", result1); // Ok(5)
println!("10 / 0 = {:?}", result2); // Err("Division by zero")
match result1 {
Ok(val) => println!("Division result: {}", val),
Err(e) => println!("Error: {}", e),
}
match result2 {
Ok(val) => println!("Division result: {}", val),
Err(e) => println!("Error: {}", e),
}
}
// 예제 함수: Result<T, E> 반환
fn divide(a: i32, b: i32) -> Result<i32, &'static str> {
if b == 0 {
Err("Division by zero")
} else {
Ok(a / b)
}
}
결과는 직접 확인해보세요... 코드를 하나씩 따라가보세요...
4. 메서드 제네릭
struct Point<T, U> {
x: T,
y: U,
}
impl<T, U> Point<T, U> {
fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
Point {
x: self.x,
y: other.y,
}
}
}
fn main() {
let p1 = Point { x: 5, y: 10.4 };
let p2 = Point { x: "Hello", y: 'c' };
let p3 = p1.mixup(p2);
println!("p3.x = {}, p3.y = {}", p3.x, p3.y); // 5, 'c'
}
결과는 직접 확인해보세요... 코드를 하나씩 따라가보세요...
5. 제네릭 사용 시 주의점
트레이트 바운드 누락 → 컴파일 에러
너무 많은 타입 인스턴스 → 바이너리 크기 증가
라이프타임과의 조합 → 복잡도 증가
where 절을 사용해 가독성 향상
6. 메모리 확인
use std::mem;
fn main() {
println!("Option<i32>: {} bytes", mem::size_of::<Option<i32>>());
println!("Option<bool>: {} bytes", mem::size_of::<Option<bool>>());
println!("Option<String>: {} bytes", mem::size_of::<Option<String>>());
}
메모리 타입별 바이트 수 확인
Glossary - The Rust Reference
An ‘abstract syntax tree’, or ‘AST’, is an intermediate representation of the structure of the program when the compiler is compiling it. The alignment of a value specifies what addresses values are preferred to start at. Always a power of two. Ref
doc.rust-lang.org
★ 모노모피제이션(monomorphization)
상세한 내용은 참고자료를 보시면 좋습니다.
어렵습니다. 중급부터는 용어도 그렇고 메모리에 어떻게 보여지는 지 그리고 어떤 타입을 해야 등등 개념을 잘 익히시길 바랍니다.