【问题标题】:Tying a trait lifetime variable to &self lifetime将特征生命周期变量绑定到 &self 生命周期
【发布时间】:2015-04-22 19:11:06
【问题描述】:

我想按照以下思路做一些事情:

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

GetRef trait 中显式生命周期变量的要点是允许 Foo 对象上的 get_ref() 的返回值比 Foo 本身的寿命更长,将返回值的生命周期与生命周期的生命周期联系起来Foo 的缓冲区。

但是,我还没有找到以编译器接受的方式为Bar 实现GetRef 的方法。我已经尝试了上述几种变体,但似乎找不到一种有效的变体。有什么理由根本无法做到这一点?如果没有,我该怎么做?

【问题讨论】:

    标签: rust lifetime


    【解决方案1】:

    将特征生命周期变量绑定到 &self 生命周期

    不可能。

    有什么理由根本无法做到这一点?

    是的。拥有向量与借用切片不同。你的 trait GetRef 只对已经代表“贷款”并且不拥有切片的事物有意义。对于像Bar 这样的拥有类型,您不能安全地返回一个比Self 寿命更长的借用切片。这就是借用检查器为避免悬空指针而阻止的。

    您尝试做的是将生命周期参数链接到Self 的生命周期。但是Self 的生命周期不是其类型 的属性。这仅取决于定义此值的范围。这就是您的方法行不通的原因。

    另一种看待它的方式是:在特征中,您必须明确说明 Self 是否被方法及其结果借用。您定义了 GetRef 特征以返回与Self w.r.t 链接的内容。一生。所以,不借。因此,它对于拥有数据的类型是不可实现的。如果不借用 Vec,则无法创建引用 Vec 元素的借用切片。

    如果没有,我该怎么做?

    取决于你所说的“这个”到底是什么意思。如果你想编写一个“共同分母”特征,可以为借来的 拥有的切片实现,你必须这样做:

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

    这个 trait 的含义是 get_ref 借用 Self 并返回一种“贷款”,因为当前的生命周期省略规则。相当于更明确的形式

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

    现在两种类型都可以实现:

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

    【讨论】:

    • 答案末尾的代码几乎就是我目前拥有的以及我想要摆脱的。我想这样做的原因有点令人费解,但归结为我需要能够获得比它们来自的Foo 更长的切片(但不是底层缓冲区)。
    • @fjh 我认为这里的关键点是,在 trait 中,生命周期必须始终具有相同的“形状”——它可以是实现者参数化的生命周期,也可以是是对象本身,但不能两者兼而有之。在您的示例中,当Bar 死亡时缓冲区也是如此 - 缓冲区的寿命不可能更长。
    • @Shepmaster 是的,我意识到对Bar 的引用不能超过Bar 本身,但我希望有一种方法可以让它与Foo 一起工作而无需Bar 的 impl 不可能。我有足够的信心,现在不能这样做。不过,真可惜。
    【解决方案2】:

    你可以为 &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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-16
      • 1970-01-01
      相关资源
      最近更新 更多