Как вернуть связанные итераторы в rust

У меня есть простая структура, которая определяет какое-то сообщение для отправки по сети.

struct Message {
    message_type: u32,
    user_id: u32,
    message: Vec<u8>,
}

И где-то еще я хочу сериализовать его в простую последовательность байтов. Поэтому я определил итератор для байтов сообщения следующим образом:

impl Message {
    fn iter(&self) -> std::iter::Chain<std::iter::Chain<std::slice::Iter<'_, u8>, std::slice::Iter<'_, u8>>, std::slice::Iter<'_, u8>> {
        self.message_type
            .to_be_bytes()
            .iter()
            .chain(self.user_id.to_be_bytes().iter())
            .chain(self.message.iter())
    }

    fn data(&self) -> Vec<u8> {
        self.iter().cloned().collect()
    }
}

Да, число итераторов в цепочке растет, и это немного обидно

Но я получаю 2 ошибки компилятора, когда пытаюсь запустить его.

cannot return value referencing temporary value

returns a value referencing data owned by the current function. rustc(E0515)

Думаю, я недостаточно разбираюсь в системе владения ржавчиной.


person Link0    schedule 17.05.2020    source источник
comment
советы: вы можете написать impl Iterator<Item=u8> в качестве возвращаемого типа. (может быть, не для вашего случая, но запомните это как ярлык)   -  person Stargateur    schedule 17.05.2020


Ответы (1)


Проблема, на которую жалуется средство проверки заимствования ржавчины, заключается в том, что функции to_be_bytes() возвращают массив, который хранится в стеке. Код пытается создать итератор для объекта, выделенного в стеке, и этот итератор пережил объект.

self.message_type.to_be_bytes()

Например:
Это создает массив в стеке, и .iter() действует только до тех пор, пока этот объект существует.

Есть несколько способов исправить это. Сделайте iter и возможное преобразование в байты в одной и той же функции.

fn data(&self) -> Vec<u8> {
    self.message_type
        .to_be_bytes()
        .iter()
        .chain(self.user_id.to_be_bytes().iter())
        .chain(self.message.iter()).map(|x| *x).collect()
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=129af6e7da3d1e3a9454fffbb124e170

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

person apatniv    schedule 17.05.2020
comment
Проблема, на которую жалуется средство проверки заимствования ржавчины, заключается в том, что функции to_be_bytes() возвращают массив, который хранится в стеке. это ложно, стек или нет, поэтому ржавчина жалуется. Вы не должны думать о стеке на таком языке, как ржавчина. Ответ больше, потому что никто не владеет массивом, поэтому было бы недопустимо иметь ссылку на него. - person Stargateur; 17.05.2020