我正在try 实现一个简单的文件链.不幸的是,我对BufRead::fill_buf的实现产生了一个borrow 判断器错误.

impl BufRead for FileChain {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        loop {
            let buf = self.stream.fill_buf()?;
            if !buf.is_empty() {
                return Ok(buf);
            } if let Some(filename) = self.future_files.pop() {
                self.stream = BufReader::new(File::open(&filename)?);
            } else {
                return Ok(&[])
            }
        }
    }
}
error[E0506]: cannot assign to `self.stream` because it is borrowed
40 |     fn fill_buf(&mut self) -> io::Result<&[u8]> {
   |                 - let's call the lifetime of this reference `'1`
41 |         loop {
42 |             let buf = self.stream.fill_buf()?;
   |                       ---------------------- `self.stream` is borrowed here
43 |             if !buf.is_empty() {
44 |                 return Ok(buf);
   |                        ------- returning this value requires that `self.stream` is borrowed for `'1`
45 |             } if let Some(filename) = self.future_files.pop() {
46 |                 self.stream = BufReader::new(File::open(&filename)?);
   |                 ^^^^^^^^^^^ `self.stream` is assigned to here but it was already borrowed

您可以找到完整的类定义here(56行).

我认为这类似于已知的borrow 判断器问题,描述了hereherehere. 基本上,检验者认为buf个引用阻止stream改变.但是,return bufstream更新不能同时进行.

现有的解决方案(例如从here开始)不能在这里应用,因为我没有HashMap/Vector,而且我受BufRead个API的限制.我也不能使用Polonius,因为我只能使用稳定的功能.

我的问题是:是否有可能在不牺牲速度的情况下使用安全代码修改此代码?如果这是不可能的,有没有办法覆盖borrow 判断器使用不安全的代码?

推荐答案

有没有办法用不安全的代码覆盖借入判断器?

虽然使用unSafe不会关闭借入判断器,但它确实允许您绕过它的一些安全措施.例如,这是汇编的,我认为是合理的:

fn fill_buf(&mut self) -> io::Result<&[u8]> {
    loop {
        // unsafe: we either return a reference into self (which prevents
        // the caller from mutating self until dropping that reference),
        // or we proceed to mutate self. This is safe under borrowing
        // rules, but fails to compile due to limitations of the current
        // borrow checker. Here we use `transmute()` to temporarily
        // decouple the reference from self (it is reassigned the lifetime
        // of self on returning). Note that the safe code without
        // `transmute()` compiles under Polonius.
        unsafe {
            let buf = std::mem::transmute::<_, &'static [u8]>(self.stream.fill_buf()?);
            if !buf.is_empty() {
                return Ok(buf);
            }
        }
        if let Some(filename) = self.future_files.pop() {
            self.stream = BufReader::new(File::open(&filename)?);
        } else {
            return Ok(&[]);
        }
    }
}

当使用unsafe时,您需要自己证明代码实际上是合理的-上面的代码在unsafe旁边的注释中记录了推理,这被认为是最佳实践. 请记住,不安全使您能够比安全更进一步地作弊.例如,修改签名以返回不正确的Result<&'static [u8]>仍然可以编译,尽管它使函数明显不可靠.这就是为什么在性能不是最重要的情况下最好避免使用unsafe.

Rust相关问答推荐

Rust为什么应用于引用的操作符可以强制,而具有显式类型的let则不能?

如何定义使用拥有的字符串并返回拥有的Split的Rust函数?

使用元组执行条件分支的正确方法

如何找到一个数字在二维数组中的位置(S)?

带扫描的铁 rust 使用滤镜

如何用Axum/Tower压缩Html内容?

铁 rust 中的泛型:不能将`<;T作为添加>;::Output`除以`{Float}`

为什么我们需要std::thread::scope,如果我们可以使用thread.join()在函数的生命周期内删除引用?

Trait bound i8:来自u8的不满意

如何从ruust中的fig.toml中读取?

在Rust中声明和定义一个 struct 体有什么区别

如何初始化选项<;T>;数组Rust 了?

如何在 `connect_activate()` 之外创建一个 `glib::MainContext::channel()` 并将其传入?

Rust 如何返回大类型(优化前)?

有什么办法可以追踪泛型的单态化过程吗?

Rust 异步和 AsRef 未被发送

仅当满足外部条件时如何添加到 actix web 的路由

当用作函数参数时,不强制执行与绑定的关联类型

如何重写这个通用参数?

如何阅读 HttpRequest 主体