在Rust中返回一个引用和被引用对象

4
当在Rust中使用Future时,通常会通过lambda实现链接处理步骤来传递对象(例如连接、已处理数据等)的所有权。我理解这个概念并且已经做了很多次而没有问题。
我正在尝试做同样的事情,但这次部分结果是一个引用类型。我无法说服Rust borrow checker接受以下过于简化的代码:
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中是否可以表达和修复,或者整个概念基本上是有缺陷的,应该以不同的方式实现,例如将属性作为拥有的值返回,从而复制而不是引用?

1个回答

1
你所拥有的是一个内部引用(元组包含对其其他元素的引用),这在Rust中非常棘手。借用检查器无法区分对对象本身的引用(移动因此会使引用无效)和对象拥有的东西(例如堆上的字符串数据,这将是稳定的)。 rental crate试图解决这个问题。您可以使用它来替换元组,使用自定义结构体引用它所拥有的堆数据。

谢谢您的超快回复!我也尝试过返回自定义结构体将两个值绑定在一起,但也失败了。租赁箱是否使用不安全代码来实现此功能?我对此还不是很熟悉。 - Zólyomi István
@ZólyomiIstván 是的,它使用了不安全的代码。 - Shepmaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接