rust
에서 확장 트레이트 구현하기
확장 트레이트를 구현하여 편리한 기능을 제공할 수 있다.
futures
크레이트를 사용하며 select!
매크로를 활용할 때 fuse
메서드에 대해서 어떻게 사용할 수 있는지 고민하며 해결한 내용을 작성해보겠다.
trait Thing {
fn do_core(&self);
}
trait ThingExt: Thing {
fn do_extra(&self) {
println!("extra");
self.do_core();
}
}
impl<T: Thing + ?Sized> ThingExt for T{}
위처럼 확장 트레이트를 구현하게되면 Thing
trait를 구현한다면 ThingExt
trait에서 제공해주는 기본 메서드를 사용할 수 있다.
struct Test {
name: String,
}
impl Thing for Test {
fn do_core(&self) {
println!("{}", self.name);
}
}
fn main() {
let t = Test { name: "홍길동".to_string()};
t.do_core();
t.do_extra();
}
Thing
trait하나만 구현했지만, ThingExt
가 제공하는 메서드 또한 사용할 수 있는것을 확인할 수 있다.
Rust
에서 자주사용하는 Future
trait의 경우 FutureExt
가 구현이 되어있어서 여러가지 확장 메서드를 사용할 수 있다.
futures
크레이트의 select
매크로를 사용하기위해서는 fuse
메서드를 사용해 future
객체가 단 한번만 사용이 가능하도록 안전성을 부여해야한다.
// fuse()를 이용한 select! 예시
#[tokio::main]
async fn main() {
let fut1 = async {
tokio::time::sleep(Duration::from_secs(2)).await;
println!("fut1이 종료되었습니다.");
};
let fut2 = async {
tokio::time::sleep(Duration::from_secs(4)).await;
println!("fut2이 종료되었습니다.");
};
select! {
_ = fut1.fuse() => {
println!("fut1");
},
_ = fut2.fuse() => {
println!("fut2");
}
};
println!("program end ============");
}
let fut = async {
println!("안녕하세요?");
};
fut.await;
fut.await;
평소에 사용 시 기본적으로 .await
을 하게되면 move가 일어나기 때문에 fuse(0)
를 사용하지 않아도 괜찮은 것 같다.
확장 트레이트 패턴은 rust에서 많이 사용되는 패턴이다. 잘 알고 있으면 다른 라이브러리를 분석할 때 유용할 것 같다.