dyn으로 트레이트 반환하기
Rust 컴파일러는 모든 함수의 반환 타입이 얼마나 많은 공간을 필요로 하는지 알아야 합니다. 이는 여러분의 모든 함수가 구체적인 타입을 반환해야 함을 의미합니다. 다른 언어와 달리, Animal과 같은 트레이트가 있을 때 Animal을 반환하는 함수를 작성할 수 없는데, 그 이유는 서로 다른 구현체들이 서로 다른 양의 메모리를 필요로 하기 때문입니다.
하지만 쉬운 해결 방법이 있습니다. 트레이트 객체를 직접 반환하는 대신, 우리 함수는 어떤 Animal을 포함하는 Box를 반환합니다. Box는 단지 힙 메모리에 대한 참조일 뿐입니다. 참조는 정적으로 알려진 크기를 가지며, 컴파일러는 그것이 힙에 할당된 Animal을 가리키고 있음을 보장할 수 있으므로, 우리 함수에서 트레이트를 반환할 수 있게 됩니다!
Rust는 힙에 메모리를 할당할 때마다 가능한 한 명시적이려고 노력합니다. 따라서 여러분의 함수가 이런 방식으로 힙상의 트레이트에 대한 포인터를 반환한다면, 반환 타입에 dyn 키워드를 사용해야 합니다. 예: Box<dyn Animal>.
struct Sheep {}
struct Cow {}
trait Animal {
// 인스턴스 메서드 시그니처
fn noise(&self) -> &'static str;
}
// `Sheep`에 대해 `Animal` 트레이트를 구현합니다.
impl Animal for Sheep {
fn noise(&self) -> &'static str {
"메에에에!"
}
}
// `Cow`에 대해 `Animal` 트레이트를 구현합니다.
impl Animal for Cow {
fn noise(&self) -> &'static str {
"음메~!"
}
}
// `Animal`을 구현하는 어떤 구조체를 반환하지만, 컴파일 타임에는 그것이 무엇인지 알 수 없습니다.
fn random_animal(random_number: f64) -> Box<dyn Animal> {
if random_number < 0.5 {
Box::new(Sheep {})
} else {
Box::new(Cow {})
}
}
fn main() {
let random_number = 0.234;
let animal = random_animal(random_number);
println!("동물을 무작위로 선택했고, 그 동물은 {}라고 말합니다.", animal.noise());
}