<제네릭(generic)>
: 중복되는 개념을 효율적으로 처리하기 위한 도구입니다. 제네릭은 구체(concrete) 타입 또는 기타 속성에 추상화된 대역입니다. Option<T>, Vec<T>, HashMap<K, T>, Result<T, E> 등등이 모두 제네릭을 사용한 것입니다(T).
제네릭을 사용해서 함수, 구조체, 열거형, 메서드를 각각 정의하는 방법을 알아보겠습니다.
1) 제네릭 함수
슬라이스에서 가장 큰 값을 참조하는 함수입니다.
fn largest<T: std::cmp::PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list {
if item > largest {
largest = item;
}
}
largest
}
* 트레이트 : 타입들이 공통적으로 갖는 동작을 추상화해줍니다. 트레이트에 대해서는 다음 챕터에서 이어서 배워보겠습니다.
* std::cmp::PartialOrd 트레이트 : 크기를 비교하는 것은 i32, char같은 값을 정렬하는 타입에 대해서만 가능하기 때문에 위에서 구현한 largest함수는 T는 std::cmp::PartialOrd trait를 구현한 것일 때만 유효합니다.
2) 제네릭 구조체
함수와 마찬가지로 <T> 를 써서 정의합니다. 예시로 든 Point의 x, y필드의 타입은 같은 T이며, 만약 다른 타입을 입력해서 정의하려 할 경우 wont_work 변수와 같이 에러가 출력됩니다.
#[derive(Debug)]
struct Point<T> {
x: T,
y: T,
}
fn main() {
let position = Point { x:5, y:10 };
println!("{:?}",position); // Point { x: 5, y: 10 } 출력
let wont_work = Point { x: 5, y: 4.0 }; // error[E0308]: mismatched types 출력
}
만약 x, y 필드의 타입을 서로 달라질 수 있게 분리하고 싶다면 다음과 같이 Point 구조체를 정의해야 합니다.
struct Point<T, U> {
x: T,
y: U,
}
3) 제네릭 열거형
이전에 배운 열거형에서 나온 enum Option<T> 도 T 타입에 대한 제네릭입니다.
enum Option<T> {
Some(T),
None,
}
바로 이전 포스팅에서 배운 에러를 처리하는 Result 열거형도 마찬가지입니다.
enum Result<T, E> {
Ok(T),
Err(E),
}
4) 제네릭 메서드
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
let p = Point{x:1, y:2};
println!("{}", p.x()); // 1 출력
러스트는 컴파일 타임에 제네릭을 사용하는 코드를 단형성화(monomorphization)합니다. 즉 컴파일러는 제네릭 코드가 호출된 곳을 찾아서 구체 타입으로 코드를 생성해줍니다. 따라서 제네릭 타입은 런타임 비용이 발생하지 않습니다.
* 단형성화 : 제네릭 코드를 실제 구체 타입으로 채워진 특정 코드로 바꾸는 과정
출처 : https://rust-kr.github.io/doc.rust-kr.org/ch10-01-syntax.html
'[Rust]' 카테고리의 다른 글
[Rust] 라이프타임(lifetime) (0) | 2023.08.19 |
---|---|
[Rust] 트레이트(trait) (0) | 2023.08.18 |
[Rust] 에러 처리 (0) | 2023.08.16 |
[Rust] match 연산자 (0) | 2023.08.15 |
[Rust] 컬렉션(Collection) (0) | 2023.08.14 |