如何解决如何将生命周期与 AsRef 包装器分离? 1.不要延长引用生命周期,而是允许一种方法来提取内部对象2.将类型明确限制为 &[u8] 和 &mut [u8]
我正在尝试为 &[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]>
,而不是使用 AsMut<[u8]>
。我尝试了以下方法,但不起作用。 Playground:
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> {
| ^^
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]
生命周期分离?
解决方法
经过一番挖掘,我现在更了解情况了。问题是 S: AsRef<[u8]>
不仅允许 S
是 &[u8]
或 &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]
这意味着我们不再使用 AsRef
,Vec
不在图片中,我们知道我们实际上有一个引用。在这种情况下,生命周期扩展适用于 &[u8]
情况,即我们可以从包装器中获取 &[u8]
引用,并且该引用将在包装器中存活。对于 &mut [u8]
,不幸的是,我们仍然需要选项 1 中的 extract
函数。
这个解决方案仍然实现了作为引入 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_mut(&mut data));
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。