Thinking Different




제너릭(Generic)

동일한 기능을 여러 타입으로 구현해야 될때 코드가 중복되는 것이 문제가 된다. 제너릭은 타입과 코드를 분리시켜 하나의 코드로 다양한 타입에 맞게 동작할 수 있는 기능을 구현할 수 있다. C언어의 템플릿과 같다.

 

 

제너릭을 알아 보기위해 간단히 덧샘 함수를 만드는 예제로 들어보자. 

실수형 덧샘과 정수형 덧샘을 따로 따로 만들어서 구현해야 되는 것을 간단히 제너릭 타입 정의로 하나의 코드로 만들 수 있다.

 

fn main() 
{
    println!("{}", add(3, 2));
    println!("{}", add2(3.2, 2.4));
}

// int 형 덧셈
fn add(a: i32, b: i32) -> i32 { a + b }

// float형 덧셈
fn add2(a: f32, b: f32) -> f32 { a + b }

이런식으로 데이터 타입만 다를 뿐 코드가 똑같이 중복된다. 이를 제너릭으로 간단히 해결하면 아래와 같다.

 

fn main() 
{
    println!("{}", add(3, 2));
    println!("{}", add(3.2, 2.4));
}

fn add<T: std::ops::Add<Output = T>>(a: T, b: T) -> T { a + b }

코드는 같으며 데이터 타입만 제너릭 T로 설정하여 컴파일시에 입력된 값의 데이터 타입으로 결정되어 컴파일 된다.

 

 

구조체 정의 제너릭 타입

구조체를 정의 할때 데이터 타입을 제너릭으로 설정 가능하다.

struct Point<T>
{
    x: T,
    y: T
}
 
fn main() 
{
    let pt1 = Point { x: 1, y: 1 };
    let pt2 = Point { x: 2.0, y: 2.0 };
}

 

서로 다른 타입을 설정하고 싶으면 제너릭 타입을 다르게 설정하면 된다.

struct Point<T, U> 
{
    x: T,
    y: U,
}

fn main() 
{
    let pt1 = Point { x: 3, y: 5 };
    let pt2 = Point { x: 2, y: 3.5 };
}

 

제너릭을 활용하면 중복되는 코드를 줄임으로써 복잡성 해결에 도움이 된다. 혹자는 제너릭(템플릿) 프로그래밍이 가독성이 떨어져서 추천하지 않는 개발자들도 있다. 너무 제너릭하게 하는것도 별로지만 적당하게 개인의 취향에 맞게 쓰면 될거 같다는게 개인적 의견이다.