简体   繁体   English

将特质寿命变量与&self life绑定

[英]Tying a trait lifetime variable to &self lifetime

I'd like to do something along the following lines: 我想按照以下方式做一些事情:

trait GetRef<'a> {
    fn get_ref(&self) -> &'a [u8];
}

struct Foo<'a> {
    buf: &'a [u8]
}

impl <'a> GetRef<'a> for Foo<'a> {
    fn get_ref(&self) -> &'a [u8] {
        &self.buf[1..]
    }
}

struct Bar {
    buf: Vec<u8>
}

// this is the part I'm struggling with:
impl <'a> GetRef<'a> for Bar {
    fn get_ref(&'a self) -> &'a [u8] {
        &self.buf[1..]
}

The point of the explicit lifetime variable in the GetRef trait is to allow the return value of get_ref() on a Foo object to outlive the Foo itself, tying the return value's lifetime to that of the lifetime of Foo 's buffer. GetRef特性中显式生命周期变量的GetRef是允许Foo对象上的get_ref()返回值超过Foo本身,将返回值的生存期与Foo缓冲区的生存期联系起来。

However, I haven't found a way to implement GetRef for Bar in a way that the compiler accepts. 但是,我还没有找到一种以编译器接受的方式实现Bar GetRef的方法。 I've tried several variations of the above, but can't seem to find one that works. 我已经尝试了上述几种变体,但似乎找不到可行的变体。 Is there any there any reason that this fundamentally cannot be done? 是否有任何理由根本无法做到这一点? If not, how can I do this? 如果没有,我该怎么办?

Tying a trait lifetime variable to &self lifetime 将特质寿命变量与&self life绑定

Not possible. 不可能。

Is there any there any reason that this fundamentally cannot be done? 是否有任何理由根本无法做到这一点?

Yes. 是。 An owning vector is something different than a borrowed slice. 拥有向量与借来的切片有所不同。 Your trait GetRef only makes sense for things that already represent a “loan” and don't own the slice. 您的特征GetRef仅对已经表示“贷款”且不拥有切片的事物有意义。 For an owning type like Bar you can't safely return a borrowed slice that outlives Self . 对于Bar这样的拥有类型,您不能安全地返回借来的切片,而该切片的寿命超过Self That's what the borrow checker prevents to avoid dangling pointers. 这就是借位检查器为避免指针悬而未决的原因。

What you tried to do is to link the lifetime parameter to the lifetime of Self . 您尝试做的是将寿命参数链接到Self的寿命。 But the lifetime of Self is not a property of its type . 但是, Self的寿命不是其类型的属性。 It just depends on the scope this value was defined in. And that's why your approach cannot work. 它仅取决于定义此值的范围。这就是您的方法无法起作用的原因。

Another way of looking at it is: In a trait you have to be explicit about whether Self is borrowed by a method and its result or not. 看它的另一种方式是:在一个特质,你必须明确是否Self由的方法和它的结果还是不借来的。 You defined the GetRef trait to return something that is not linked to Self wrt lifetimes. 您定义了GetRef特征以返回链接到Self wrt生命周期的内容。 So, no borrowing. 因此,无需借款。 So, it's not implementable for types that own the data. 因此,它对于拥有数据的类型是不可行的。 You can't create a borrowed slice referring to a Vec 's elements without borrowing the Vec . 您不能创建一个借来片指的是Vec的元素,而无需借用Vec

If not, how can I do this? 如果没有,我该怎么办?

Depends on what exactly you mean by “this”. 取决于您“此”的确切含义。 If you want to write a “common denominator” trait that can be implemented for both borrowed and owning slices, you have to do it like this: 如果你要编写可以同时为借拥有片实现的“共同点”特质,你必须做这样的:

trait GetRef {
    fn get_ref(&self) -> &[u8];
}

The meaning of this trait is that get_ref borrows Self and returns a kind of “loan” because of the current lifetime elision rules. 此特征的含义是,由于当前的生命周期淘汰规则, get_ref 借用了 Self并返回一种“贷款”。 It's equivalent to the more explicit form 相当于更明确的形式

trait GetRef {
    fn get_ref<'s>(&self) -> &'s [u8];
}

It can be implemented for both types now: 现在可以为两种类型实现它:

impl<'a> GetRef for Foo<'a> {
    fn get_ref(&self) -> &[u8] { &self.buf[1..] }
}

impl GetRef for Bar {
    fn get_ref(&self) -> &[u8] { &self.buf[1..] }
}

You could make different lifetimes for &self and result in your trait like that: 您可以为&self设置不同的生命,并导致如下特征:

trait GetRef<'a, 'b> {
    fn get_ref(&'b self) -> &'a [u8];
}

struct Foo<'a> {
    buf: &'a [u8]
}

impl <'a, 'b> GetRef<'a, 'b> for Foo<'a> {
    fn get_ref(&'b self) -> &'a [u8] {
        &self.buf[1..]
    }
}

struct Bar {
    buf: Vec<u8>
}

// Bar, however, cannot contain anything that outlives itself
impl<'a> GetRef<'a, 'a> for Bar {
    fn get_ref(&'a self) -> &'a [u8] {
        &self.buf[1..]
    }
}


fn main() {
    let a = vec!(1 as u8, 2, 3);
    let b = a.clone();
    let tmp;
    {
        let x = Foo{buf: &a};
        tmp = x.get_ref();
    }
    {
        let y = Bar{buf: b};
        // Bar's buf cannot outlive Bar
        // tmp = y.get_ref();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM