10. 제네릭, 트레잇, 라이프타임
10장. 제네릭, 트레잇, 라이프타임
Rust는 제네릭, 트레잇, 라이프타임을 통해 코드의 재사용성과 안전성을 높입니다. 이 세 가지 개념은 Rust의 타입 시스템과 밀접하게 연관되어 있으며, 복잡한 프로그램을 작성할 때 매우 유용합니다.
제네릭 (Generics)
제네릭은 함수, 구조체, 열거형 등을 정의할 때 구체적인 타입을 지정하지 않고, 다양한 타입을 처리할 수 있도록 합니다.
제네릭 함수 예제
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 number_list = vec![34, 50, 25, 100, 65];
let result = largest(&number_list);
println!("The largest number is {}", result);
let char_list = vec!['y', 'm', 'a', 'q'];
let result = largest(&char_list);
println!("The largest char is {}", result);
}
위 예제에서 largest
함수는 제네릭 타입 T
를 사용하여 다양한 타입의 리스트에서 가장 큰 값을 찾습니다. T: PartialOrd
는 T
가 비교 가능한 타입임을 나타냅니다.
제네릭 구조체 예제
struct Point<T> {
x: T,
y: T,
}
fn main() {
let integer = Point { x: 5, y: 10 };
let float = Point { x: 1.0, y: 4.0 };
println!("Point with integers: ({}, {})", integer.x, integer.y);
println!("Point with floats: ({}, {})", float.x, float.y);
}
위 예제에서 Point
구조체는 제네릭 타입 T
를 사용하여 다양한 타입의 좌표를 저장할 수 있습니다.
트레잇 (Traits)
트레잇은 다른 언어의 인터페이스와 유사하며, 특정 동작을 정의하고 이를 구현하도록 강제합니다.
트레잇 정의 및 구현 예제
trait Summary {
fn summarize(&self) -> String;
}
struct Article {
headline: String,
content: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("{}: {}", self.headline, self.content)
}
}
fn main() {
let article = Article {
headline: String::from("Rust is great!"),
content: String::from("Rust is a systems programming language..."),
};
println!("New article available! {}", article.summarize());
}
위 예제에서 Summary
트레잇을 정의하고, Article
구조체에 대해 이를 구현했습니다. summarize
메서드는 Article
의 요약을 반환합니다.
라이프타임 (Lifetimes)
라이프타임은 참조자가 유효한 범위를 명시적으로 지정하여 메모리 안전성을 보장합니다.
라이프타임 예제
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("long string is long");
let string2 = String::from("xyz");
let result = longest(&string1, &string2);
println!("The longest string is {}", result);
}
위 예제에서 longest
함수는 두 문자열 참조를 받아서 더 긴 문자열 참조를 반환합니다. 'a
라이프타임 매개변수는 반환되는 참조가 입력 참조들 중 하나와 동일한 라이프타임을 가짐을 보장합니다.
제네릭, 트레잇, 라이프타임 요약
제네릭 데이터 타입
- 함수 정의
- 예제:
fn largest<T: PartialOrd>(list: &[T]) -> T { ... }
- 예제:
- 구조체 정의
- 예제:
struct Point<T> { x: T, y: T }
- 예제:
- 열거형 정의
- 예제:
enum Option<T> { Some(T), None }
- 예제:
- 메서드 정의
- 예제:
impl<T> Point<T> { fn x(&self) -> &T { &self.x } }
- 예제:
- 함수 정의
트레잇
- 트레잇 정의
- 예제:
trait Summary { fn summarize(&self) -> String; }
- 예제:
- 트레잇 구현
- 예제:
impl Summary for NewsArticle { fn summarize(&self) -> String { ... } }
- 예제:
- 기본 구현
- 예제:
trait Summary { fn summarize(&self) -> String { String::from("읽어보세요!") } }
- 예제:
- 트레잇 바운드
- 예제:
fn notify<T: Summary>(item: T) { ... }
- 예제:
- 트레잇 정의
라이프타임
- 라이프타임 문법
- 예제:
fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str { ... }
- 예제:
- 라이프타임 생략 규칙
- 예제:
fn first_word(s: &str) -> &str { ... }
- 예제:
- 정적 라이프타임
- 예제:
static NAME: &str = "Rust";
- 예제:
- 라이프타임 문법
전체 예제 코드
예제:
// 전체 예제 코드
fn largest<T: PartialOrd>(list: &[T]) -> T {
let mut largest = &list[0]; // T의 참조로 초기화
for item in list {
if item > largest {
largest = item; // 가장 큰 값을 업데이트
}
}
largest.clone() // T를 반환하기 위해 clone 사용
}fn main() {
let numbers = vec![34, 50, 25, 100, 65];
let result = largest(&numbers);
println!("가장 큰 숫자: {}", result);let chars = vec!['y', 'm', 'a', 'q']; let result_char = largest(&chars); println!("가장 큰 문자: {}", result_char);
}