제네릭 함수
Coddy Rust 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 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이 서로 완전히 다른 두 타입을 처리하는 것을 확인해 보세요. 이것이 바로 제네릭 함수의 유연성입니다!
정수, 문자열, 또 다른 정수, 또 다른 문자열, 총 네 개의 입력을 받습니다.
직접 해보기
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})
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 Rust 컴파일러