作为一个 Rust 新手,我可能有点天真地开始了这个:
...
pub trait Decode<T> {
fn decode_from<R: io::Read + ?Sized>(&mut self, stream: &mut R) -> T;
}
pub struct MQTTFrame<'a> {
pub payload: &'a Vec<u8>,
}
pub struct MQTTFrameDecoder<'a> {
pub payload: &'a mut Vec<u8>,
}
impl<'a> Decode<MQTTFrame<'a>> for MQTTFrameDecoder<'a> {
fn decode_from<R: io::Read + ?Sized>(&mut self, stream: &mut R) -> MQTTFrame<'a> {
stream.read(&mut self.payload);
MQTTFrame{ payload: self.payload }
}
}
Run Code Online (Sandbox Code Playgroud)
其中,在尝试编译时,受到了欢迎:
src/testbed/mod.rs:31:24: 31:36 error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements [E0495]
src/testbed/mod.rs:31 MQTTFrame{ payload: self.payload }
^~~~~~~~~~~~
src/testbed/mod.rs:29:5: 32:6 help: consider using an explicit lifetime parameter as shown: fn decode_from<R: io::Read + ?Sized>(&'a mut self, stream: &mut R)
-> MQTTFrame<'a>
src/testbed/mod.rs:29 fn decode_from<R: io::Read + ?Sized>(&mut self, stream: &mut R) -> MQTTFrame<'a> {
src/testbed/mod.rs:30 stream.read(&mut self.payload);
src/testbed/mod.rs:31 MQTTFrame{ payload: self.payload }
src/testbed/mod.rs:32 }
Run Code Online (Sandbox Code Playgroud)
StackOverflow 上的某个地方 - 抱歉,我忘了在哪里 - 类似案例中的某个人建议添加这样的生命周期参数(省略未更改的代码):
pub trait Decode<'a, T> {
fn decode_from<R: io::Read + ?Sized>(&'a mut self, stream: &mut R) -> T;
}
impl<'a> Decode<'a, MQTTFrame<'a>> for MQTTFrameDecoder<'a> {
fn decode_from<R: io::Read + ?Sized>(&'a mut self, stream: &mut R) -> MQTTFrame<'a> {
stream.read(&mut self.payload);
MQTTFrame{ payload: self.payload }
}
}
Run Code Online (Sandbox Code Playgroud)
瞧!它编译。现在,如果我只能理解为什么它会编译。有人可以解释一下
这是一个无法编译的简化测试用例(playpen):
pub trait Decode<T> {
fn decode_from<'b>(&'b mut self) -> T;
}
pub struct MQTTFrame<'a> {
pub payload: &'a Vec<u8>,
}
pub struct MQTTFrameDecoder<'a> {
pub payload: &'a mut Vec<u8>,
}
impl<'a> Decode<MQTTFrame<'a>> for MQTTFrameDecoder<'a> {
fn decode_from<'b>(&'b mut self) -> MQTTFrame<'a> {
MQTTFrame{ payload: self.payload }
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,我已经省略了函数的生命周期decode_from并删除了冗余的流参数。
很明显,该函数正在获取具有任意短生命周期的引用'b,然后将其扩展为具有生命周期'a。这是可变引用的问题,因为这样你就可以同时可变地和不可变地借用一些东西:
fn main() {
let mut v = vec![];
/* lifetime 'a */ {
let mut decoder = MQTTFrameDecoder{ payload: &mut v };
let frame: MQTTFrame;
/* lifetime 'b */ {
frame = decoder.decode_from(); // borrows decoder just for lifetime 'b
}
// v is mutably borrowed (by decoder) and immutably borrowed (by frame) at the same time! oops!
decoder.payload.push(1);
println!("{:?}", frame.payload);
}
}
Run Code Online (Sandbox Code Playgroud)
因此,借用检查器拒绝让该函数编译。
但是,如果您强制引用decoder具有生命周期'a,那么就不再有问题了。编译器不能使用生命周期较短的引用,它必须可变地借用decoder更长的时间,因此当我们尝试再次借用它时,编译器应该给我们一个错误。
为了实现这一点,我们想写
fn decode_from(&'a mut self) -> MQTTFrame<'a> {
MQTTFrame{ payload: self.payload }
}
Run Code Online (Sandbox Code Playgroud)
但现在我们得到一个错误:
<anon>:14:5: 16:6 error: method `decode_from` has an incompatible type for trait:
expected bound lifetime parameter 'b,
found concrete lifetime [E0053]
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,我们需要让我们的特质意识到,你只能有decode_from特定的生命周期,而不是任意的生命周期。所以将解码更改为
pub trait Decode<'a, T> {
fn decode_from(&'a mut self) -> T;
}
Run Code Online (Sandbox Code Playgroud)
并对实施做出适当的改变
impl<'a> Decode<'a, MQTTFrame<'a>> for MQTTFrameDecoder<'a> { ... }
Run Code Online (Sandbox Code Playgroud)
现在,如果我们尝试上面的代码(playpen is.gd/BLStYq),借用检查器会抱怨:
<anon>:28:9: 28:24 error: cannot borrow `*decoder.payload` as mutable more than once at a time [E0499]
<anon>:28 decoder.payload.push(1);
Run Code Online (Sandbox Code Playgroud)
这是因为,现在,为了调用 function ,对 的引用decoder必须具有生命周期。注释掉有问题的行,示例的其余部分就会编译!该代码现在是安全的,因为没有延长可变生命周期。'adecode_from
在旁边:
由于对 的引用decoder必须与解码器本身一样长,因此decoder在调用 后您实际上根本无法使用decode_from. 既然如此,最好用 来表达这一点,self而不是&'a mut self。然后语法就干净一点了,很明显,一旦使用了解码器就不能再使用了。
pub trait Decode<T> {
fn decode_from(self) -> T;
}
pub struct MQTTFrame<'a> {
pub payload: &'a Vec<u8>,
}
pub struct MQTTFrameDecoder<'a> {
pub payload: &'a mut Vec<u8>,
}
impl<'a> Decode<MQTTFrame<'a>> for MQTTFrameDecoder<'a> {
fn decode_from(self) -> MQTTFrame<'a> {
MQTTFrame{ payload: self.payload }
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3247 次 |
| 最近记录: |