본문 바로가기

Rust

러스트 제네릭(generic) 함수 정의

https://www.yes24.com/Product/Goods/116586619

 

만들면서 배우는 러스트 프로그래밍 - 예스24

고효율, 현대적 프로그래밍 언어 Rust의 결정적 해설서!러스트는 효율적이고 신뢰할 수 있으며 생산성이 높은 언어로, 프로그래머가 가장 배우고 싶어 하는 언어로 꼽힌다. 배울 가치가 높은 언

www.yes24.com

공부한것을 정리한 내용입니다

 

 

제네릭은(generic)은 추상적인 타입을 지정해 다양한 데이터 타입 조작을 가능하게 하는 프로그래밍 기법이다. 러스트는 타입 체크를 엄격하게 해서 타입이 다르면 컴파일 되지 않아 만약 비슷한 함수가 여러개 있으면 실수가 많아져 코드 중복을 줄이고 실수를 방지하고자 이때 제네릭을 사용하게 된다.

 

fn add_i32(a:i32, b: i32) -> i32 {
	a + b 
}


fn add_f32(a:f32, b: f32) -> f32 {
 	a + b
}

 

기능은 같지만 타입이 다르다 이때 추상적인 타입을 사용하는 제네릭을 사용하면 

 

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


fn main() {
    println!("{}", add(10,25)); // 정수 
    println!("{}", add(10.0, 25.0)); // 부동소수점

    // 타입 명시 하고 싶으면 
    println!("{}", add::<i32>(10,25)); 
}

 

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

   a + b

}

덧셈과 관련된 트레잇 std::ops는 오버로드(overload)가능한 연산자 트레잇을 정의한 모듈이고, Add트레잇이 덧셈 트레잇이다.

 

 

 

위에 코드가 길어 보이면 where를 사용해 가독성을 좋게 할 수 있다.

 

fn add <T> (a:T, b: T) -> T 
// 긴 덧셈관련트레잇이면 where을 써서 가독성을 고려한다.
  where T: std::ops::Add<Output=T>
{
	a + b 
} 

fn main() {
    println!("{}", add(10,25));
    println!("{}", add(10.0, 25.0));
}

 

 

 

구조체에도 제네릭을 지정할 수 있다.

 

// Debug 구조체의 각 필드값을  값을 출력할 수 있게해준다. println!()
#[derive(Debug)]
struct Move<T> {
    a: T,
    b: T,
}

// std::ops::AddAssign 트레잇은 덧셈 대입을 구현하도록 강제한다.
impl<T> Move<T>
where
    T: std::ops::AddAssign,
{
    //메서드를 사용하려면 생성자를 만들어야한다.
    fn new(a: T, b: T) -> Self {
        Self { a, b }
    }

    // 구조체 필드 값을 변경하기 위해 &mut self를 지정해 가변변수라는 것을 명시
    fn add(&mut self, go: Move<T>) {
        self.a += go.a;
        self.b += go.b;
    }
}

fn main() {
    // 결과는 {10,15}에 {10,30}을 더한 {20,45}가 나온다
    let mut go = Move::new(10, 15);
    println!("{:?}", go);

    go.add(Move { a: 10, b: 30 });
    println!("{:?}", go);
}