Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Повернення трейтів із dyn

Компілятор Rust має знати, скільки місця потребує тип, що повертається, кожної функції. Це означає, що всі ваші функції мають повертати конкретний тип. На відміну від інших мов, якщо у вас є трейт, як-от Animal, ви не можете написати функцію, яка повертає Animal, тому що його різні реалізації потребуватимуть різної кількості пам’яті.

Однак є простий обхідний шлях. Замість того щоб повертати трейт-об’єкт безпосередньо, наші функції повертають Box, який містить деякий Animal. box — це просто посилання на певну пам’ять у купі. Оскільки посилання має розмір, відомий на етапі компіляції, і компілятор може гарантувати, що воно вказує на Animal, виділений у купі, ми можемо повертати трейт із нашої функції!

Rust намагається бути якомога явнішим щоразу, коли він виділяє пам’ять у купі. Тож якщо ваша функція повертає вказівник-на-трейт-у-купі таким способом, вам потрібно писати тип повернення з ключовим словом dyn, наприклад Box<dyn Animal>.

struct Sheep {}
struct Cow {}

trait Animal {
    // Instance method signature
    fn noise(&self) -> &'static str;
}

// Implement the `Animal` trait for `Sheep`.
impl Animal for Sheep {
    fn noise(&self) -> &'static str {
        "baaaaah!"
    }
}

// Implement the `Animal` trait for `Cow`.
impl Animal for Cow {
    fn noise(&self) -> &'static str {
        "moooooo!"
    }
}

// Returns some struct that implements Animal, but we don't know which one at compile time.
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!("You've randomly chosen an animal, and it says {}", animal.noise());
}