Проблемы с временем жизни Tuple в ржавчине.

Я пытаюсь реализовать простой парсер для байтового потока.

У меня проблемы, когда я хочу повторно использовать объявленную ранее переменную,

fn read_data(asn_data: &mut Cursor<&[u8]>) -> Result<(u8, u8, Vec<u8>), Err> {
    let total_len = asn_data.get_ref().len();

    if total_len < 2 {
        return Err(1);
    }
    let d_type = asn_data.read_u8().unwrap();
    let d_len = asn_data.read_u8().unwrap();

    if (asn_data.position() + d_len as u64) > total_len as u64 {
        return Err(2);
    }

    let mut buf = vec![0; d_len as usize];

    match asn_data.read_exact(&mut buf) {
        Err(e) => Err(e),
        Ok(()) => Ok((d_type, d_len, buf)),
    }

}

fn parse_request(request: &[u8]) -> Option<u8> {

    if request.len() == 0 {
        return None;
    }

    let mut rdr = Cursor::new(request);
    let data_tuple = read_data(&mut rdr).unwrap();
    println!("{:02?}", data_tuple.2);

    rdr = Cursor::new(data_tuple.2.as_slice());
    let data_tuple = read_data(&mut rdr).unwrap();
    println!("{:02x?}", data_tuple.2);

    Some(1)
}

В функции parse_request я хочу повторно использовать переменную rdr, но с кодом, показанным выше, я получаю следующую ошибку при компиляции:

ошибка [E0597]: data_tuple.2 не живет достаточно долго -> src / main.rs: 80: 23 | 80 | rdr = Cursor :: new (data_tuple.2.as_slice ()); | ^^^^^^^^^^^^ заемная стоимость не живет достаточно долго ... 104 | } | - data_tuple.2 упал сюда, пока все еще занимал | = примечание: значения в области удаляются в порядке, обратном их созданию

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

Однако если я напишу "let mut", когда использую 2-ю переменную rdr, код компилируется и работает нормально ...

let mut rdr = Cursor::new(data_tuple.2.as_slice());

Я не понимаю, почему ... я хочу повторно использовать переменную вместо того, чтобы снова объявить ее ...

Я пробовал с некоторыми примерами / проблемами, связанными с переменным временем жизни, но я не нашел решения для моего случая ... и решение, которое я нашел, я не понимаю полностью ...


person d00rt    schedule 21.10.2018    source источник
comment
Самое простое решение - включить нелексическое время жизни (или просто использовать бета-версию издания 2018 года).   -  person Sven Marnach    schedule 22.10.2018
comment
Повторное объявление rdr гарантирует, что он объявлен после data_tuple, поэтому первое не сможет пережить второе. Если вы повторно используете переменную, порядок объявления будет обратным, поэтому rdr удаляется только после data_tuple, отсюда и ошибка.   -  person Sven Marnach    schedule 22.10.2018
comment
У вас действительно есть тип ошибки с именем Err, который находится в области действия одновременно с одноименным вариантом перечисления?   -  person Sven Marnach    schedule 22.10.2018


Ответы (1)


Это не связано со временем жизни кортежа, это просто порядок отбрасывания.

Когда переменные определены в отдельных операторах let в одной области (то есть в одном блоке), они будут отброшены в обратном порядке. Посмотрев на ваш код, мы увидим:

let mut rdr = Cursor::new(request);
let data_tuple = read_data(&mut rdr).unwrap();

Итак, data_tuple будет удален первым, пока rdr еще жив. Это плохо, потому что rdr должен ссылаться на кортеж. Самое простое решение - поменять местами их определения:

let data_tuple: (u8, u8, Vec<u8>);
let mut rdr = Cursor::new(request);
data_tuple = read_data(&mut rdr).unwrap();

Таким образом, rdr будет удален первым, освобождая ссылку на data_tuple и позволяя удалить сам кортеж.

Упомянутое вами «исправление» работает, потому что каждый оператор let определяет новую переменную, даже если то же имя уже используется, а существующая переменная немедленно забывается. Итак, когда вы пишете:

let mut rdr = Cursor::new(request);
let data_tuple = read_data(&mut rdr).unwrap();
let mut rdr = Cursor::new(data_tuple.2.as_slice());

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

person Cerberus    schedule 22.10.2018
comment
Тип данных на самом деле не нужен. Просто let data_tuple; отлично работает. Rust выводит тип из более позднего присвоения. - person Sven Marnach; 22.10.2018