rust 为什么在Result〈_,&str>上使用?会导致生存期错误?

iyr7buue  于 2023-01-13  发布在  其他
关注(0)|答案(2)|浏览(125)

我有这样的代码不能编译:

impl BytePacketBuffer {
    fn read(&mut self) -> Result<u8, &str> {
        if self.pos >= 512 {
            return Err("End of buffer".into());
        }
        let res = self.buf[self.pos];
        self.pos += 1;

        Ok(res)
    }

    fn read_u16(&mut self) -> Result<u16, &str> {
        let res = ((self.read()? as u16) << 8) | (self.read()? as u16);
        Ok(res)
    }
}
error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/byte_packet_buffer.rs:53:51
   |
52 |     fn read_u16(&mut self) -> Result<u16, &str> {
   |                 - let's call the lifetime of this reference `'1`
53 |         let res = ((self.read()? as u16) << 8) | (self.read()? as u16);
   |                     ------------                  ^^^^^^^^^^^ second mutable borrow occurs here
   |                     |
   |                     first mutable borrow occurs here
   |                     returning this value requires that `*self` is borrowed for `'1`

但是如果我把返回类型从&str修改为String,它编译时不会出错,谁能解释一下为什么我在返回&str时会出错,而在返回String时不会?

ppcbkaq5

ppcbkaq51#

因为您没有指定任何生存期,Rust将根据elision rules推断它们为:

fn read<'a>(&'a mut self) -> Result<u8, &'a str>

这意味着只要你保留Result或它包含的任何东西,它就会推断self是被借用的。要修复它,你可以指定返回的str的生存期,因为它总是静态的。

fn read(&mut self) -> Result<u8, &'static str>
fxnxkyjh

fxnxkyjh2#

@cafce25很好地解释了生存期省略是如何导致错误的生存期的,但这仍然不能解释为什么会失败。即使生存期不正确,当我们为&str借用self时,它是错误情况,错误情况立即从函数返回,因此不会进一步借用self
这是因为?操作符大致可以将其解糖为(简化了,但实际的解糖在这里并不重要):

match expr {
    Ok(v) => v,
    Err(e) => return Err(From::from(e)),
}

it is well known that the borrow checker is overly conservative w.r.t. branches。它将返回表达式中的borrow扩展到函数的其余部分,使得&str即使在不能真正存活的情况下也能存活。
如果使用Poloniuscargo +nightly rustc -- -Zpolonius)编译它,则编译成功。

相关问题