为什么我的 trait 需要一个生命周期参数? [英] Why does my trait need a lifetime parameter?

查看:57
本文介绍了为什么我的 trait 需要一个生命周期参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为一个 Rust 新手,我可能有点天真地开始:

Being a Rust newbie, I probably somewhat naively started with this:

...

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 }
    }
}

在尝试编译时遇到了:

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     }

StackOverflow 上的某个地方 - 抱歉,我忘了在哪里 - 类似案例中的某个人建议添加这样的生命周期参数(省略未更改的代码):

Somewhere on StackOverflow - sorry, I forgot where - someone in a similar case suggested to add a lifetime parameter like so (omitting unchanged code):

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 }
    }
}

你瞧!它编译.现在,如果我只能理解为什么它会编译.谁能解释一下

And lo and behold! It compiles. Now if I could only understand why it compiles. Could someone explain

  1. 为什么原始代码无法编译?
  2. 为什么修改后的代码会编译?

推荐答案

这是一个无法编译的简化测试用例 (playpen):

Here's a reduced testcase that fails to compile (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 }
    }
}

请注意,我已经消除了 生命周期code>decode_from 函数并删除冗余流参数.

Note that I have elided the lifetimes for the decode_from function and removed the redundant stream parameter.

很明显,该函数正在获取具有任意短生命周期 'b 的引用,然后将其扩展为具有生命周期 'a.这是可变引用的一个问题,因为你可以同时可变和不可变地借用一些东西:

It is clear then that the function is taking a reference with an arbitrarily short lifetime 'b, and then extending it to have lifetime 'a. This is a problem with mutable references as then you can borrow something mutably and immutably at the same time:

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);
    }
}

出于这个原因,借用检查器拒绝让函数编译.

For this reason the borrow checker refuses to let the function compile.

如果您强制对 decoder 的引用具有生命周期 'a,那么就不再有问题了.编译器不能使用生命周期较短的引用,它必须可变地借用 decoder 更长的时间,所以当我们再次尝试借用它时,编译器应该给我们一个错误.

If you force the reference to decoder to have lifetime 'a, though, then there is no longer a problem. The compiler cannot use the reference with the shorter lifetime, it must mutably borrow decoder for longer, and so the compiler should give us an error when we try to borrow it again.

为了实现这一点,我们想写

In order to achieve this, we would like to write

fn decode_from(&'a mut self) -> MQTTFrame<'a> {
    MQTTFrame{ payload: self.payload }
}

但现在我们得到一个错误:

But now we get an error:

<anon>:14:5: 16:6 error: method `decode_from` has an incompatible type for trait:
 expected bound lifetime parameter 'b,
    found concrete lifetime [E0053]

为了解决这个问题,我们需要让我们的 trait 意识到你只能 decode_from 某些生命周期,而不是任意的生命周期.所以将解码更改为

To fix this, we need to have our trait be aware that you can only decode_from certain lifetimes, not arbitrary ones. So change decode to

pub trait Decode<'a, T> {
    fn decode_from(&'a mut self) -> T;
}

并对实现进行适当的更改

And make the appropriate change to the implementation

impl<'a> Decode<'a, MQTTFrame<'a>> for MQTTFrameDecoder<'a> { ... }

现在,如果我们尝试上面的代码(playpen is.gd/BLStYq),借用检查器会抱怨:

Now if we try the code above (playpen is.gd/BLStYq), the borrow checker complains:

<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);

那是因为,现在,为了调用函数decode_from,对decoder 的引用必须具有生命周期'a.注释掉违规行,示例的其余部分将编译!此代码现在是安全的,因为没有延长可变生命周期.

That's because, now, the reference to decoder must have lifetime 'a when it is taken in order to call the function decode_from. Comment out the offending line and the rest of the example compiles! This code is now safe because no mutable lifetimes are being extended.

旁白:

由于对 decoder 的引用必须与解码器本身一样长,因此在调用 decode_fromdecoder代码>.在这种情况下,最好用 self 而不是 &'a mut self 来表达这一点.然后语法更简洁一些,很明显,解码器一旦使用过就不能再使用了.

As the reference to decoder must live as long as the decoder itself, you can't actually use decoder at all after you have called decode_from. As this is the case, it may be better to express this by taking self instead of &'a mut self. Then the syntax is a little cleaner, and it is obvious that once a decoder has been used then it can't be used again.

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 }
    }
}

这篇关于为什么我的 trait 需要一个生命周期参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆