LINUX.ORG.RU

Rust. Lifetimes и mem::replace.

 


0

3

Привет, ЛОР! Есть у меня код чтобы доставать данные примитивных типов из буфера. Хочу написать аналогичный макрос чтобы писать в буфер примитивные типы. Первая попытка написать что-то разбилась о borrow checker. Я по подсказке компилятора проставил одинаковые лайфтамы и это сработало, но так можно записать только одно значение. Мне объяснили, что так получается из-за попытки взять мутабельную ссылку на мутабельную ссылку. И предложили такой вариант. (Сам я додумался только заменить мутабельную ссылку на мутабельный указатель, но это unsafe) Однако, даже без лайфтаймов всё работает благодаря трюку с mem::replace. У меня 2 вопроса. Действительно ли нельзя без трюка с mem::replace? И почему трюк с mem::replace работает? Ведь под капотом у него swap и, если я правильно понимаю, после вызова mem::replace в $A должно находится &mut [] и присвоение туда rest не должно затрагивать исходный массив. Если сбросите чего почитать на тему – буду благодарен, из книги я не понял почему это работает.

я конечно извиняюсь, но зачем такой говнокод? Можно же тупо писать в вектор.

fn main() {
    let foo = 0x01020304u32;
    let bar = 0x05060708u32;
    
    let mut buf: Vec<u8> = Vec::with_capacity(10);
    let mut write_u32 = |n: u32| {
        if buf.len() + 4 <= buf.capacity() {
            buf.extend(&n.to_ne_bytes());
        }
    };
    write_u32(foo);
    write_u32(bar);
    println!("{:?}", buf);
}

если между записями понадобится доступ к этому вектору - заверни его во что-нибудь типа Cell/RefCell.

anonymous
()
Ответ на: комментарий от anonymous

Реальный код немного сложнее. Там указатель на функцию write_u32 должен быть помещён в структуру (так что буфер так легко не захватишь, они будут разными по ходу работы программы) и именно указатель, потому что функции записи будут для big endian и для little endian и выбор будет производиться при конструировании экземпляра, а с замыканиями всё сложнее.

andalevor ★★★
() автор топика
Ответ на: комментарий от anonymous

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

andalevor ★★★
() автор топика
Ответ на: комментарий от Marvel

Очень похоже на то, что надо. Но я никак не могу понять как это можно использовать в том же стиле. Т.е. сохранить в структуре функцию с impl Write

andalevor ★★★
() автор топика

Мыши плакали, кололись, но продолжали грызть кактус.

anonymous
()
Ответ на: комментарий от andalevor

Не обязательно использовать impl Write. Есть и другие варианты:

use std::io::{Cursor, Write};

fn write1(writer: &mut impl Write, value: u32) {
    writer.write(&value.to_ne_bytes()).unwrap();
}

fn write2(writer: &mut dyn Write, value: u32) {
    writer.write(&value.to_ne_bytes()).unwrap();
}

type MyCursor<'a> = Cursor<&'a mut [u8]>;

fn write3(writer: &mut MyCursor, value: u32) {
    writer.write(&value.to_ne_bytes()).unwrap();
}

fn main() {
    let mut arr = [0u8; 12];
    let mut cursor = Cursor::new(&mut arr[..]);
    write1(&mut cursor, 0x01020304);
    write2(&mut cursor, 0x01020304);
    write3(&mut cursor, 0x05060708);
    for i in &arr {
        println!("{}", i);
    }
}
Marvel
()
Ответ на: комментарий от Marvel

Похоже мне ещё немало предстоит разложить по полочкам в голове знаний о Rust. Спасибо за помощь.

andalevor ★★★
() автор топика
Ответ на: комментарий от Marvel

Хочется еще добавить вариант с классическими аннотациями генериков, которые позволяют уточнять тип руками, в отличие от impl Trait в позиции аргумента:

fn write4<T: Write>(writer: &mut T, value: u32) {
    writer.write(&value.to_ne_bytes()).unwrap();
}
mersinvald ★★★★★
()
Последнее исправление: mersinvald (всего исправлений: 1)
Ответ на: комментарий от DarkEld3r

Я говорю об уточнении типа при вызове (когда автоматический вывод типов не справляется), а не о трейт-баундах.

mersinvald ★★★★★
()
Ответ на: комментарий от mersinvald

Теперь дошло. А не в курсе хотят ли это вообще разрешить?

DarkEld3r ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.