제네릭 함수
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)를 반환합니다
제네릭 함수를 사용하면 재사용 가능한 로직을 한 번만 작성하여 여러 타입에 적용할 수 있으므로, 타입 안전성을 유지하면서 코드 중복을 줄일 수 있습니다.
챌린지
쉬움어떤 타입과도 함께 작동할 수 있는 제네릭 함수를 포함한 유틸리티 모듈을 만들어 봅시다! 특정 구조체에 얽매이지 않고 제네릭이 코드를 얼마나 유연하고 재사용 가능하게 만드는지 보여주는 독립형 함수들을 작성하게 됩니다.
코드는 두 개의 파일로 구성됩니다:
utils.rs: 공개 제네릭 유틸리티 함수 모음을 만듭니다:wrap_in_pair<T>— 단일 값을 받아 해당 값을 두 번 포함하는 튜플(value, value)를 반환합니다. 이 함수는 타입이Clone이어야 하므로,<T: Clone>을 사용하세요.swap<T, U>— 잠재적으로 서로 다른 타입의 두 값을 받아 튜플(U, T)와 같이 역순으로 반환합니다.
main.rs: 유틸리티 모듈을 임포트하고 이러한 제네릭 함수가 서로 다른 타입에서 작동하는 것을 보여줍니다. 동일한 함수 정의가 정수, 부동 소수점 및 문자열을 어떻게 원활하게 처리하는지 보여주세요.
메인 파일에서 다음을 수행하여 유틸리티 함수를 시연하세요:
- 정수(첫 번째 입력,
i32로 파싱됨)와 함께wrap_in_pair를 사용하고 두 요소를 모두 출력합니다. - 문자열(두 번째 입력)과 함께
wrap_in_pair를 사용하고 두 요소를 모두 출력합니다. - 정수(세 번째 입력,
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})
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.