IT Best Practise/Rust

10. 제네릭, 트레잇, 라이프타임

GilliLab IT 2024. 11. 7. 19:16
728x90
반응형

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: PartialOrdT가 비교 가능한 타입임을 나타냅니다.

제네릭 구조체 예제

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);

      }

728x90
반응형