제네릭 구조체
Coddy Rust 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 61개 중 24번째.
지금까지 만든 모든 struct에는 구체적이고 명확한 type의 field가 있었습니다. Pet에는 String name이 있고, Rectangle에는 f64 dimensions가 있습니다. 하지만 any type의 data를 hold할 수 있는 struct를 만들고 싶다면 어떻게 해야 할까요?
여기서 제네릭이 사용됩니다. 제네릭을 사용하면 여러 타입에서 작동하는 유연하고 재사용 가능한 코드를 작성할 수 있습니다. 특정 타입을 하드코딩하는 대신, 일반적으로 T인 플레이스홀더를 사용하며, 이 플레이스홀더는 struct를 사용할 때 구체적인 타입으로 대체됩니다.
어떤 타입이든 담을 수 있는 간단한 래퍼 구조체입니다:
struct Wrapper<T> {
value: T,
}
구조체 이름 뒤의 <T>는 generic type parameter를 선언합니다. 구조체 내부에서 T는 실제로 사용하게 될 type을 대신하는 역할을 합니다. 인스턴스를 생성하면 Rust가 구체적인 type을 추론합니다:
let int_wrapper = Wrapper { value: 42 }; // T는 i32
let float_wrapper = Wrapper { value: 3.14 }; // T는 f64
let text_wrapper = Wrapper { value: "hello" }; // T는 &str
이들은 각각 서로 다른 구체적인 타입인 Wrapper<i32>, Wrapper<f64>, Wrapper<&str>이지만, 모두 동일한 struct 정의를 공유합니다. 따라서 본질적으로 동일한 작업을 수행하는 IntWrapper, FloatWrapper, StringWrapper struct를 별도로 작성할 필요가 없습니다.
T라는 문자는 단지 관례일 뿐입니다("Type"의 약어). 유효한 식별자라면 무엇이든 사용할 수 있지만, T는 Rust 및 제네릭을 사용하는 대부분의 다른 언어에서 표준입니다.
챌린지
쉬움모든 type의 값을 hold할 수 있는 generic container를 만들어 봅시다! generic이 코드를 유연하고 재사용 가능하게 만드는 방법을 보여 주는 Container struct를 만들 것입니다.
코드를 두 파일에 걸쳐 구성합니다:
container.rs:Container<T>라는 public generic struct를 Define하고,Ttype의 single public fielditem을 포함하도록 합니다. 이 container는 integer, float, string 또는 그 밖의 모든 type을 hold할 수 있어야 합니다.main.rs: container module을 불러오고, 서로 다른 type의 data를 hold하는 containers를 Create하여 유연성을 보여 줍니다. 세 개의 containers를 Create하고 각각 무엇을 hold하는지 표시합니다.
main 파일에서 다음 containers를 Create합니다:
- integer 값을 hold하는 container (첫 번째 input을
i32로 구문 분석) - float 값을 hold하는 container (두 번째 input을
f64로 구문 분석) - string을 hold하는 container (세 번째 input을
String으로 유지)
출력에는 각 container의 contents가 다음 format으로 표시되어야 합니다:
Integer container: {value}
Float container: {value}
String container: {value}예를 들어 inputs가 42, 3.14, hello인 경우:
Integer container: 42
Float container: 3.14
String container: hello동일한 Container<T> Define이 세 가지 서로 다른 type 모두에서 작동한다는 점에 주목하세요. 이것이 바로 generics의 power입니다!
세 개의 inputs를 받습니다: integer 값, float 값, string 값입니다.
직접 해보기
mod container;
use container::Container;
fn main() {
// 세 개의 입력을 읽기
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let int_value: i32 = input1.trim().parse().expect("Failed to parse integer");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let float_value: f64 = input2.trim().parse().expect("Failed to parse float");
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let string_value = input3.trim().to_string();
// TODO: Create three containers using Container<T>
// 1. An integer container holding int_value
// 2. A float container holding float_value
// 3. A string container holding string_value
// TODO: 각 컨테이너의 내용을 필요한 형식으로 출력
// Integer container: {value}
// Float container: {value}
// String container: {value}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 Rust 컴파일러