where 절
Coddy Rust 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 42번째.
트레이트 바운드(trait bound)를 더 많이 추가할수록, 함수 시그니처는 읽기 어려워질 수 있습니다. 여러 개의 제네릭 매개변수를 가지고 있으며, 각각 여러 개의 트레이트를 요구하는 함수를 생각해 봅시다:
fn complex_operation<T: Display + Clone, U: Debug + Summary>(first: T, second: U) {
// ...
}
이 방식도 작동하지만, 시그니처가 복잡해지고 있습니다. where 절은 트레이트 바운드(trait bounds)를 매개변수 목록 뒤로 옮김으로써 더 깔끔한 대안을 제공합니다:
fn complex_operation<T, U>(first: T, second: U)
where
T: Display + Clone,
U: Debug + Summary,
{
// ...
}
두 버전은 기능적으로 동일합니다. where 절은 순전히 가독성을 위한 것입니다. 각 타입의 요구 사항이 별도의 줄에 표시되어, 각 제네릭 매개변수에 무엇이 필요한지 쉽게 훑어볼 수 있게 해줍니다.
where 절은 바운드(bounds)가 복잡하거나 제네릭 매개변수가 많을 때 특히 유용합니다. 이는 함수 이름과 매개변수를 한눈에 볼 수 있게 유지하면서, 제약 조건은 아래에 별도로 나열합니다. 이는 바운드가 단순한 T: Trait를 넘어설 때 대부분의 Rust 코드베이스에서 선호되는 스타일입니다.
챌린지
쉬움복잡한 트레이트 바운드(trait bounds)를 가독성 있게 유지하기 위해 where 절을 사용하는 데이터 처리 시스템을 구축해 봅시다! 여러 개의 타입 매개변수를 가진 제네릭 함수를 만들고, 각 타입에 필요한 서로 다른 트레이트들을 where 구문을 사용하여 깔끔하게 정리하게 됩니다.
코드는 두 개의 파일로 구성됩니다:
processor.rs: 두 개의 공개(public) 트레이트와 이를 모두 사용하는 제네릭 함수를 정의합니다:Summarize—&self를 매개변수로 받고String을 반환하는summary메서드를 가진 트레이트Validate—&self를 매개변수로 받고bool을 반환하는validate메서드를 가진 트레이트
process_items라는 공개 제네릭 함수를 만듭니다.where절을 사용하여 첫 번째 타입은Clone과Summarize를 모두 구현해야 하며, 두 번째 타입은Validate를 구현해야 함을 명시하세요. 이 함수는 첫 번째 항목의 요약(summary)을 출력한 다음, 두 번째 항목의 유효 여부를 출력해야 합니다.main.rs: 필요한 트레이트를 구현하는 두 개의 공개 구조체를 만듭니다:Article— 공개된title필드(String)를 가집니다.Summarize를 구현하여"Article: {}"형식으로 반환하도록 하고,Clone을 파생(derive)시킵니다.Form— 공개된filled필드(bool)를 가집니다.Validate를 구현하여filled의 값을 반환하도록 합니다.
process_items를 호출하세요.
where 절은 모든 바운드를 꺾쇠괄호(angle brackets) 안에 밀어 넣는 것보다 함수 시그니처를 훨씬 깔끔하게 만들어 줍니다. 각 타입의 요구 사항이 별도의 줄에 표시되므로 각 제네릭 매개변수에 무엇이 필요한지 쉽게 확인할 수 있습니다.
출력은 요약 내용과 그 뒤에 이어지는 유효성 검사 결과를 보여주어야 합니다:
Article: {title}
Valid: {true/false}예를 들어, 입력값이 Rust Tips와 true인 경우:
Article: Rust Tips
Valid: true그리고 입력값이 Breaking News와 false인 경우:
Article: Breaking News
Valid: false두 개의 입력을 받게 됩니다: 기사 제목(article title)과 양식 작성 여부(bool로 파싱)입니다.
치트 시트
where 절은 제약 조건을 매개변수 목록 뒤로 이동시켜 제네릭 함수에 대한 트레이트 바운드를 지정하는 더 깔끔한 방법을 제공합니다:
fn complex_operation<T, U>(first: T, second: U)
where
T: Display + Clone,
U: Debug + Summary,
{
// ...
}
이것은 인라인 트레이트 바운드와 기능적으로 동일하지만 가독성을 향상시킵니다:
fn complex_operation<T: Display + Clone, U: Debug + Summary>(first: T, second: U) {
// ...
}
where 절은 특히 다음과 같은 경우에 유용합니다:
- 여러 개의 제네릭 매개변수가 있는 경우
- 각 매개변수가 여러 개의 트레이트 바운드를 필요로 하는 경우
- 함수 시그니처를 깔끔하고 훑어보기 좋게 유지하고 싶은 경우
각 타입의 요구 사항이 별도의 줄에 표시되어 각 제네릭 매개변수에 무엇이 필요한지 쉽게 확인할 수 있습니다. 이는 바운드가 단순한 T: Trait를 넘어설 때 대부분의 Rust 코드베이스에서 선호되는 스타일입니다.
직접 해보기
mod processor;
use processor::{Summarize, Validate, process_items};
use std::io;
// TODO: 공개 필드 title (String)을 가진 공개 구조체 Article을 정의하세요.
// Article에 대해 Clone을 파생(Derive)하세요.
// TODO: Article에 대해 Summarize를 구현하세요.
// summary 메서드는 "Article: {title}"을 반환해야 합니다.
// TODO: 공개 필드 filled (bool)를 가진 공개 구조체 Form을 정의하세요.
// TODO: Form에 대해 Validate를 구현하세요.
// validate 메서드는 filled의 값을 반환해야 합니다.
fn main() {
let mut title = String::new();
io::stdin().read_line(&mut title).expect("Failed to read line");
let title = title.trim().to_string();
let mut filled_input = String::new();
io::stdin().read_line(&mut filled_input).expect("Failed to read line");
let filled: bool = filled_input.trim().parse().expect("Failed to parse bool");
// TODO: 주어진 title로 Article을 생성하세요.
// TODO: 주어진 filled 값으로 Form을 생성하세요.
// TODO: article과 form을 사용하여 process_items를 호출하세요.
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.