首页 > 解决方案 > 如何将生命周期与 AsRef 包装器分离?

问题描述

我正在尝试为&[u8]数据构建一个临时包装类,允许调用者提取具有原始生命周期的数据,而不是临时包装生命周期。

如果&[u8]直接使用,这有效: Playground

struct Wrapper1<'a> {
    data: &'a [u8],
}

impl<'a> Wrapper1<'a> {
    // In the return value, we return lifetime 'a, not the lifetime of the wrapper
    pub fn get(&self) -> &'a [u8] {
        &self.data[2..]
    }
}

fn func(data: &[u8]) -> &[u8] {
    let wrapper = Wrapper1 { data };
    // Note that we can return wrapper.get() even though Wrapper1 goes out of scope
    wrapper.get()
}

fn main() {
    let data = vec![5; 10];
    println!("{:?}", func(&data));
}

现在我想在对可变性进行抽象时做同样的事情,即&[u8]我需要使用AsRef<[u8]>and而不是使用AsMut<[u8]>。我尝试了以下方法,但它不起作用。游乐场

use std::marker::PhantomData;

struct Wrapper2<'a, S: 'a + AsRef<[u8]>> {
    data: S,
    _p: PhantomData<&'a S>,
}

impl<'a, S: 'a + AsRef<[u8]>> Wrapper2<'a, S> {
    pub fn get<'b>(&'b self) -> &'a [u8] {
        &self.data.as_ref()[2..]
    }
}

fn func(data: &[u8]) -> &[u8] {
    let wrapper = Wrapper2 {
        data,
        _p: PhantomData,
    };
    wrapper.get()
}

fn main() {
    let data = vec![5; 10];
    println!("{:?}", func(&data));
}

错误信息:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:10:20
   |
10 |         &self.data.as_ref()[2..]
   |                    ^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'b` as defined on the method body at 9:16...
  --> src/main.rs:9:16
   |
9  |     pub fn get<'b>(&'b self) -> &'a [u8] {
   |                ^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:10:10
   |
10 |         &self.data.as_ref()[2..]
   |          ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 8:6...
  --> src/main.rs:8:6
   |
8  | impl<'a, S: 'a + AsRef<[u8]>> Wrapper2<'a, S> {
   |      ^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:10:9
   |
10 |         &self.data.as_ref()[2..]
   |         ^^^^^^^^^^^^^^^^^^^^^^^^

它无法为返回找到一个好的生命周期,Wrapper2::get()因为它要求它比&self.

有没有办法wrapper像我在&[u8]上面的例子中那样将它与生命周期解耦?

标签: rustlifetime

解决方案


经过一番挖掘,我现在对情况有了更好的了解。问题是它S: AsRef<[u8]>不仅允许S&[u8]or这样的引用类型&mut [u8],而且还可以是像Vec<u8>. 虽然对于引用,您可能会争辩说应该有一种方法可以将它们的寿命延长到寿命之外Wrapper,因为Vec<u8>,这显然没有意义,Vec<u8>因为wrapper.

我提出了两种可能的解决方案:

1.不要延长引用的生命周期,而是允许一种提取内部对象的方法。

这允许func问题中提出的 return 语句。

操场

struct Wrapper2<S: AsRef<[u8]>> {
    data: S,
}

impl<S: AsRef<[u8]>> Wrapper2<S> {
    pub fn get(&self) -> &[u8] {
        &self.data.as_ref()[2..]
    }
    
    pub fn extract(self) -> S {
        // but note that we can only return the full data,
        // not a subset like get() or get_mut() would be doing
        self.data
    }
}

impl<S: AsRef<[u8]> + AsMut<[u8]>> Wrapper2<S> {
    pub fn get_mut(&mut self) -> &mut [u8] {
        &mut self.data.as_mut()[2..]
    }
}

fn func(data: &[u8]) -> &[u8] {
    let wrapper = Wrapper2 { data };
    let _g = wrapper.get();
    wrapper.extract()
}

fn func_mut(data: &mut [u8]) -> &mut [u8] {
    let mut wrapper = Wrapper2 { data };
    let _g = wrapper.get_mut();
    wrapper.extract()
}

fn main() {
    let mut data = vec![5; 10];
    println!("{:?}", func(&data));
    println!("{:?}", func_mut(&mut data));
}

2. 明确限制类型&[u8]&mut [u8]

这意味着我们不再使用AsRefVec不在图片中,我们知道我们实际上有一个参考。在这种情况下,生命周期延长适用于这种&[u8]情况,即我们可以从包装器中获取&[u8]引用,并且该引用将在包装器中继续存在。对于&mut [u8],不幸的是,我们仍然需要extract选项 1 中的函数。

AsRef该解决方案仍然实现了作为引入/的原因提到的问题的“抽象可变性”目标AsMut,它只是在没有这些特征的情况下做到了。

操场

struct Wrapper2<S> {
    data: S,
}

impl <'a> Wrapper2<&'a [u8]> {
    fn get(&self) -> &'a [u8] {
        &self.data[2..]
    }
}

impl <'a> Wrapper2<&'a mut [u8]> {
    fn get_mut(&mut self) -> &mut [u8] {
        &mut self.data[2..]
    }
    
    fn extract(self) -> &'a mut [u8] {
        &mut self.data[2..]
    }
}

fn func(data: &[u8]) -> &[u8] {
    let wrapper = Wrapper2 { data };
    wrapper.get()
}

fn func_mut(data: &mut [u8]) -> &mut [u8] {
    let mut wrapper = Wrapper2 { data };
    let _a = wrapper.get_mut();
    let _b = wrapper.get_mut();
    wrapper.extract()
}

fn main() {
    let mut data = vec![5; 10];
    println!("{:?}", func(&data));
    println!("{:?}", func_mut(&mut data));
}

推荐阅读