Rust 트레잇(Trait)과 트레잇 바운드(Trait Bound)
Trait
Trait
은 다른 언어들의 인터페이스, 프로토콜, 추상 클래스와 유사한 역할을 한다.
다양한 타입들이 동일한 기능을 수행할 수 있도록 해주며, 코드 재사용과 추상화를 가능하게 해준다.
trait Car {
fn drive(&self);
}
struct Truck;
impl Car for Truck {
fn drive(&self) {
println!("Truck can drive");
}
}
struct Sedan;
impl Car for Sedan {
fn drive(&self) {
println!("Sedan can drive");
}
}
Car Trait은 drive
라는 메서드를 구현 없이 선언부만 갖고 있다.
Truck과 Sedan Struct는 Car Trait의 drive
를 각각 구현했다.
이 형태를 보면 Java의 Interface 구현과 유사한 것을 알 수 있다.
Trait 메서드는 아래와 같이 기본 구현을 포함해 만들 수 있다.
trait Car {
fn drive(&self) {
println!("can drive");
}
}
이렇게 하면 Car Trait을 구현하는 다른 타입이 drive
를 구현하지 않을 때 기본 구현으로 포함된다.
하지만, 그 타입이 drive
를 구현했다면 해당 타입에 구현한 drive
가 우선한다.
Trait Bound
다양한 프로그래밍 언어는 다형성을 구현하기 위해 상속이라는 개념을 사용한다.
이를 위해 인터페이스나 추상 클래스 등을 제공하기도 한다.
러스트에는 상속의 개념이 없지만, 위에서 설명했듯 인터페이스와 유사한 트레잇(Trait)을 지원한다.
제네릭 타입 파라미터, 트레잇, 트레잇 바운드(Trait Bound)를 활용해 다형적인 특성을 구현할 수 있다.
트레잇 바운드(Trait Bound)는 제네릭 타입 파라미터에 제약 사항을 지정하는 것이다.
fn trait_bound<T: Car>(car: T) {
println!("T implements Car");
}
제네릭 타입을 의미하는 T
뒤에 : Car
부분이 트레잇 바운드를 지정하는 부분이다.
이는 제네릭 타입 T
가 Car Trait을 구현하고 있어야 한다는 제약사항이다.
즉, 위 함수는 Car Trait을 구현하고 있는 모든 타입 T
를 파라미터로 받을 수 있다.
아래 코드에서 trait_bound
함수가 Sedan, Truck 두 타입을 모두 파라미터로 받을 수 있다는 것을 볼 수 있다.
trait Car {
fn drive(&self) {
println!("can drive");
}
}
struct Truck {}
impl Car for Truck {}
struct Sedan {}
impl Car for Sedan {}
fn trait_bound<T: Car>(car: T) {
println!("T implements Car");
}
fn main() {
let truck = Truck {};
trait_bound(truck);
let sedan = Sedan {};
trait_bound(sedan);
}
트레잇 바운드는 다음과 같이 여러 개의 트레잇으로 구성할 수도 있다.
fn trait_bound<T: Car + Debug>(car: T) {
println!("T implements Car");
}
이제 trait_bound
함수의 파라미터 타입 T
는 Car Trait과 Debug Trait을 모두 구현하고 있어야 한다.
어떤 함수는 여러 개의 제네릭 타입 파라미터를 가질 수 있고,
각 제네릭 타입은 여러개의 트레잇을 트레잇 바운드로 구성할 수 있습니다.
이렇게 되면, 함수 선언부의 가독성이 떨어질 수 있는데, 아래는 그 예다.
fn trait_bound<T: Car + Debug, U: Clone + Debug>(car: T, test: U) {
println!("T implements Car");
}
Rust는 가독성 좀 더 좋게 하기 위해, 트레잇 바운드를 위한 다른 문법을 제공한다.
아래 코드는 위의 코드와 동일하지만 where
절을 이용해 Trait Bound를 지정한 내용이다.
fn trait_bound<T, U>(car: T, test: U)
where
T: Car + Debug,
U: Clone + Debug,
{
println!("T implements Car");
}
'Dev > Language' 카테고리의 다른 글
impl Trait과 Box<dyn Trait> - Rust 프로그래밍 (1) | 2022.12.19 |
---|---|
Cell 타입과 RefCell 타입 - Rust 프로그래밍 (1) | 2022.11.26 |
Rc 타입과 Weak 타입 - Rust 프로그래밍 (4) | 2022.10.29 |
소유권(Ownership)과 원시 타입 - Rust 프로그래밍 (0) | 2022.08.29 |
반복문과 루프 레이블 - Rust 프로그래밍 (0) | 2022.08.14 |