Хранить данные, которые реализуют черту в векторе - PullRequest
0 голосов
/ 20 февраля 2019

Я очень плохо знаком с Rust и системными языками в целом.И я сейчас играю с Rust, чтобы изучить язык.У меня проблема, которую я не могу решить самостоятельно.И я думаю, что понимаю проблему, которая происходит.

Я не хочу хранить объекты, которые реализуют trait BaseStuff в векторе.В Rust не простая задача для меня: -).

Вот мой пример кода, который не будет компилироваться.

trait BaseStuff {}

struct MyStuff {
    value: i32,
}

struct AwesomeStuff {
    value: f32,
    text: String,
}

impl BaseStuff for MyStuff {}

impl BaseStuff for AwesomeStuff {}

struct Holder {
    stuff: Vec<BaseStuff>,
}

impl Holder {
    fn register(&mut self, data: impl BaseStuff) {
        self.stuff.push(data);
    }
}

fn main() {
    let my_stuff = MyStuff { value: 100 };

    let awesome_stuff = AwesomeStuff {
        value: 100.0,
        text: String::from("I'm so awesome!"),
    };

    let mut holder = Holder { stuff: vec![] };

    holder.register(my_stuff);
}

error [E0277]: размер для значенийтипа (dyn BaseStuff + 'static) невозможно знать во время компиляции -> src \ main.rs: 17: 5 |17 |
материал: Vec, // неизвестный размер |^^^^^^^^^^^^^^^^^^^^^ размер не известен во время компиляции |= help: черта std::marker::Sized не реализована для (dyn BaseStuff + 'static) = примечание: чтобы узнать больше, посетите https://doc.rust -lang.org / book / second-edition / ch19-04-advanced-types.html #признак динамических размеров-типов-и-размеров = примечание: требуется std::vec::Vec

ошибка: прерывание из-за предыдущей ошибки

Для получения дополнительной информации об этой ошибке,попробуйте rustc --explain E0277.ошибка: не удалось скомпилировать playground.

Сообщение компилятора ясно, и я понимаю сообщение.Я могу реализовать свойство BaseStuff в любой структуре, которую я хочу, поэтому неясно, какой у нее размер.Кстати, ссылка не полезна, потому что она указывает на устаревший сайт ...

Размер String также неизвестен, но String реализует черту std::marker::Sized, и поэтому Vec<String> будетработать без проблем.Это правильно?

В книге о ржавчине, которую я читал для типов данных с неизвестным размером, я должен хранить эти данные в куче, а не в стеке.Я изменил свой код следующим образом.

struct Holder {
    stuff: Vec<Box<BaseStuff>>,
}

impl Holder {
    fn register(&mut self, data: impl BaseStuff) {
        self.stuff.push(Box::new(data));
    }
}

Теперь я сталкиваюсь с новой проблемой компилятора:

Ошибка [E0310]: тип параметра impl BaseStuff может не жить долгодостаточно -> src \ main.rs: 22: 25 |21 |fn register (& mut self, data: impl BaseStuff) {|
--------------- help: рассмотрите возможность добавления явной границы времени жизни impl BaseStuff: 'static ... 22 |self.stuff.push (Box :: new (data));
|^^^^^^^^^^^^^^ |примечание: ... чтобы тип impl BaseStuff соответствовал требуемым границам времени жизни -> src \ main.rs: 22: 25 |22 |self.stuff.push (Box :: new (data));
|^^^^^^^^^^^^^^

ошибка: прерывание из-за предыдущей ошибки

Для получения дополнительной информации об этой ошибке, попробуйте rustc --explain E0310.ошибка: не удалось скомпилировать playground.

И знаю, что меня нет ... Я прочитал в книге о времени жизни и много изменил свой код с помощью 'a здесь и 'a влюбая комбинация, но без удачи ... Я не хочу записывать любую комбинацию определения жизни, которую я пробовал.Я не понимаю, почему мне нужно определение продолжительности жизни.Владение перемещается на любом этапе, поэтому, насколько я понимаю, ясно, что структура Holder является владельцем всех данных.

Как я могу исправить свой код для компиляции?

Спасибо за помощь.

1 Ответ

0 голосов
/ 20 февраля 2019

Вы почти получили его - проблема здесь в том, что тип, для которого реализован BaseStuff, может быть ссылкой (например, impl BaseStuff for &SomeType).Это означает, что даже если вы передаете data по значению, это значение может быть ссылкой, которая будет изжита вашим Box.

. Чтобы исправить это, добавьте ограничение таким образом, чтобыОбъект имеет время жизни 'static, что означает, что это будет либо тип значения, либо статическая ссылка.Вы можете применить это ограничение к признаку или методу, принимающему признак, в зависимости от вашего варианта использования.

Применение ограничения к признаку:

trait BaseStuff: 'static {}

Применение ограничения к методу:

impl Holder {
    fn register(&mut self, data: impl BaseStuff + 'static) {
        self.stuff.push(Box::new(data));
    }
}

Если вы добавите ограничение 'static к методу, я бы порекомендовал также добавить его к Vec, чтобы избежать потери информации о типе, например:

struct Holder {
    stuff: Vec<Box<dyn BaseStuff + 'static>>,
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...