Menu
Coddy logo textTech

제네릭 함수

Coddy Rust 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 27번째.

제네릭은 구조체에만 국한되지 않습니다. 어떤 타입과도 작동하는 독립형 함수를 작성할 수도 있습니다. 이는 특정 구조체에 속하지 않으면서도 유연성을 유지해야 하는 유틸리티 함수가 필요할 때 유용합니다.

이 문법은 구조체에서 보았던 것과 유사합니다. 함수 이름 뒤의 꺾쇠괄호 안에 제네릭 매개변수를 선언하고, 이를 매개변수와 반환 타입에서 사용하세요:

fn identity<T>(value: T) -> T {
    value
}

identity 함수는 모든 타입의 값을 받아 변경 없이 반환합니다. <T>는 제네릭을 선언하고, value: T는 이를 매개변수로 받으며, -> T는 반환 타입을 지정합니다. 함수를 호출할 때, Rust는 구체적인 타입을 추론합니다:

let num = identity(42);        // T는 i32입니다
let text = identity("hello");  // T는 &str입니다

구조체에서와 마찬가지로 함수에서도 여러 개의 제네릭 매개변수를 사용할 수 있습니다:

fn make_pair<T, U>(first: T, second: U) -> (T, U) {
    (first, second)
}

let pair = make_pair(10, "ten");  // (i32, &str)를 반환합니다

제네릭 함수를 사용하면 재사용 가능한 로직을 한 번만 작성하여 여러 타입에 적용할 수 있으므로, 타입 안전성을 유지하면서 코드 중복을 줄일 수 있습니다.

challenge icon

챌린지

쉬움

어떤 타입과도 함께 작동할 수 있는 제네릭 함수를 포함한 유틸리티 모듈을 만들어 봅시다! 특정 구조체에 얽매이지 않고 제네릭이 코드를 얼마나 유연하고 재사용 가능하게 만드는지 보여주는 독립형 함수들을 작성하게 됩니다.

코드는 두 개의 파일로 구성됩니다:

  • utils.rs: 공개 제네릭 유틸리티 함수 모음을 만듭니다:
    • wrap_in_pair<T> — 단일 값을 받아 해당 값을 두 번 포함하는 튜플 (value, value)를 반환합니다. 이 함수는 타입이 Clone이어야 하므로, <T: Clone>을 사용하세요.
    • swap<T, U> — 잠재적으로 서로 다른 타입의 두 값을 받아 튜플 (U, T)와 같이 역순으로 반환합니다.
  • main.rs: 유틸리티 모듈을 임포트하고 이러한 제네릭 함수가 서로 다른 타입에서 작동하는 것을 보여줍니다. 동일한 함수 정의가 정수, 부동 소수점 및 문자열을 어떻게 원활하게 처리하는지 보여주세요.

메인 파일에서 다음을 수행하여 유틸리티 함수를 시연하세요:

  1. 정수(첫 번째 입력, i32로 파싱됨)와 함께 wrap_in_pair를 사용하고 두 요소를 모두 출력합니다.
  2. 문자열(두 번째 입력)과 함께 wrap_in_pair를 사용하고 두 요소를 모두 출력합니다.
  3. 정수(세 번째 입력, i32로 파싱됨)와 문자열(네 번째 입력)과 함께 swap을 사용한 다음, 바뀐 결과를 출력합니다.

출력은 다음 형식을 따라야 합니다:

Pair of ints: ({value}, {value})
Pair of strings: ({value}, {value})
Swapped: ({string}, {int})

예를 들어, 입력값이 5, hello, 42, world인 경우:

Pair of ints: (5, 5)
Pair of strings: (hello, hello)
Swapped: (world, 42)

wrap_in_pair가 정수와 문자열 모두에 대해 동일하게 작동하고, swap이 완전히 다른 두 타입을 어떻게 처리하는지 확인해 보세요. 이것이 바로 제네릭 함수의 유연성입니다!

정수 하나, 문자열 하나, 또 다른 정수 하나, 그리고 또 다른 문자열 하나까지 총 네 개의 입력을 받게 됩니다.

치트 시트

제네릭 함수를 사용하면 모든 타입에서 작동하는 독립형 유틸리티 함수를 작성할 수 있습니다. 함수 이름 뒤의 꺾쇠괄호 안에 제네릭 매개변수를 선언하세요:

fn identity<T>(value: T) -> T {
    value
}

<T>는 제네릭 타입 매개변수를 선언하며, 이는 함수 매개변수와 반환 타입에서 사용할 수 있습니다. Rust는 함수를 호출할 때 구체적인 타입을 추론합니다:

let num = identity(42);        // T is i32
let text = identity("hello");  // T is &str

단일 함수에서 여러 제네릭 매개변수를 사용할 수 있습니다:

fn make_pair<T, U>(first: T, second: U) -> (T, U) {
    (first, second)
}

let pair = make_pair(10, "ten");  // returns (i32, &str)

제네릭 타입에 특정 기능이 필요한 경우, 트레이트 바운드(trait bounds)를 사용하세요:

fn duplicate<T: Clone>(value: T) -> (T, T) {
    (value.clone(), value)
}

직접 해보기

mod utils;

use std::io;

fn main() {
    // 네 개의 입력을 읽습니다
    let mut input1 = String::new();
    io::stdin().read_line(&mut input1).expect("Failed to read line");
    let num1: i32 = input1.trim().parse().expect("Invalid integer");

    let mut input2 = String::new();
    io::stdin().read_line(&mut input2).expect("Failed to read line");
    let str1 = input2.trim().to_string();

    let mut input3 = String::new();
    io::stdin().read_line(&mut input3).expect("Failed to read line");
    let num2: i32 = input3.trim().parse().expect("Invalid integer");

    let mut input4 = String::new();
    io::stdin().read_line(&mut input4).expect("Failed to read line");
    let str2 = input4.trim().to_string();

    // TODO: num1과 함께 wrap_in_pair를 사용하고 결과를 출력하세요
    // 형식: Pair of ints: ({value}, {value})

    // TODO: str1과 함께 wrap_in_pair를 사용하고 결과를 출력하세요
    // 형식: Pair of strings: ({value}, {value})

    // TODO: num2와 str2에 swap을 사용한 다음, 바뀐 결과를 출력하세요
    // 형식: Swapped: ({string}, {int})
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Object Oriented Programming의 모든 레슨