Вернуть ссылку вместе с объектом, на который указывает ссылка, в Rust

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

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

extern crate futures;
use futures::prelude::*;

// Parsed data with attribute values that might be not owned, only referenced
trait Data<'a> {
    fn attribute<'s, 'n>(&'s self, name: &'n str) -> &'a str;
}

fn async_load_blob() -> Box<Future<Item = Vec<u8>, Error = ()>> {
    Box::new(futures::future::err(())) // Dummy impl to compile
}

fn parse<'a>(_blob: &'a [u8]) -> Result<Box<Data<'a> + 'a>, ()> {
    Err(()) // Dummy impl just to compile fine
}

fn resolve_attribute<'a, 'n>(
    name: &'n str,
) -> Box<Future<Item = (Vec<u8>, &'a str), Error = ()> + 'a> {
    let owned_name = name.to_owned(); // move attribute name into lambda
    let fut = async_load_blob().and_then(move |blob| {
        // COMPILE ERROR: how to convince borrow checker that the
        // owned data is properly moved out together with the reference?
        let data_res = parse(blob.as_slice());
        match data_res {
            Ok(data) => {
                let attr = data.attribute(owned_name.as_str());
                futures::future::ok((blob, attr))
            }
            Err(e) => futures::future::err(e),
        }
    });
    Box::new(fut)
}

Проблемная часть — это кортеж, возвращенный в успешной ветке. Если я попытаюсь вернуть (таким образом, удалить) собственные данные из области видимости, средство проверки заимствования не сможет понять корреляцию между ними и сообщит об ошибке.

Я также пытался использовать Rc и другие трюки уже и каждый раз терпел неудачу. Можно ли это выразить и исправить в Rust, или вся концепция в корне ошибочна и должна быть реализована по-другому, например. возвращая атрибуты как собственные значения, таким образом копируя вместо ссылки?


person Zólyomi István    schedule 05.01.2018    source источник


Ответы (1)


То, что у вас есть, по сути является внутренней ссылкой (кортеж содержит ссылку на другой свой элемент), что очень сложно в Rust. Средство проверки заимствования не может отличить ссылку на сам объект (который перемещается и, таким образом, сделает ссылку недействительной) и вещи, которыми владеет объект (например, строковые данные в куче, которые были бы стабильными).

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

person Sebastian Redl    schedule 05.01.2018
comment
Спасибо за супер быстрый ответ! Я также пытался вернуть пользовательские структуры, связывающие два значения вместе, но также не удалось. Использует ли ящик для аренды небезопасный код для достижения этой цели? Я еще не очень знаком с этим. - person Zólyomi István; 05.01.2018
comment
@ZólyomiIstván ZólyomiIstván да, он использует небезопасный код. - person Shepmaster; 05.01.2018