我有这样的代码不能编译:
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
时不会?
2条答案
按热度按时间ppcbkaq51#
因为您没有指定任何生存期,Rust将根据elision rules推断它们为:
这意味着只要你保留
Result
或它包含的任何东西,它就会推断self
是被借用的。要修复它,你可以指定返回的str
的生存期,因为它总是静态的。fxnxkyjh2#
@cafce25很好地解释了生存期省略是如何导致错误的生存期的,但这仍然不能解释为什么会失败。即使生存期不正确,当我们为
&str
借用self
时,它是错误情况,错误情况立即从函数返回,因此不会进一步借用self
。这是因为
?
操作符大致可以将其解糖为(简化了,但实际的解糖在这里并不重要):和it is well known that the borrow checker is overly conservative w.r.t. branches。它将返回表达式中的borrow扩展到函数的其余部分,使得
&str
即使在不能真正存活的情况下也能存活。如果使用Polonius(
cargo +nightly rustc -- -Zpolonius
)编译它,则编译成功。