我正在尝试实现一个智能指针,该智能指针应该能够引用类型为T
的数据,该数据可以是在生命周期'a
借来的,或者是在生命周期'static
借来的:
pub enum SmartPtr<'a, T: 'a> {
/// Should live as long as this struct or longer - don't know exactly how long, so we need to clone this when we clone the struct
Borrowed(&'a T),
/// Lives forever: So we never need to clone this
/// Fails here with: 'the parameter type `T` may not live long enough'
Static(&'static T),
}
SmartPtr
还将包含其他枚举字段,例如Rc
和Box
(上面的示例已简化)。 SmartPtr
将主要用于应该可克隆的结构中……当输入数据T
(例如静态字符串)为'static
时,我不想克隆数据。
我想为此实现Clone
:
impl<'a, T> Clone for SmartPtr<'a, T>
where
T: Clone,
{
fn clone(&self) -> Self {
match self {
SmartPtr::Borrowed(value) => {
// here we have to clone the value
SmartPtr::Borrowed(value.clone())
}
SmartPtr::Static(value) => {
// Important: No need to clone, since value is static and lives forever
SmartPtr::Static(value)
}
}
}
}
编译器失败:
error[E0310]: the parameter type `T` may not live long enough
--> src/main.rs:7:12
|
2 | pub enum SmartPtr<'a, T: 'a> {
| -- help: consider adding an explicit lifetime bound `T: 'static`...
...
7 | Static(&'static T),
| ^^^^^^^^^^^
|
note: ...so that the reference type `&'static T` does not outlive the data it points at
--> src/main.rs:7:12
|
7 | Static(&'static T),
| ^^^^^^^^^^^
我该如何解决?
已编辑
正如我在评论中所写,我的SmartPtr没有任何意义。但这似乎是有道理的:
pub enum SmartPtr<T : 'static /* WHY IS 'static REQUIRED HERE? */> where T : ?Sized {
Rc(Rc<T>), // Here 'static makes no sense, it's Rc'd
Boxed(Box<T>), // Here 'static makes no sense, it's owned
Static(&'static T) // Here we need 'static
}
我不明白为什么'static
中需要SmartPtr<T : 'static
。 SmartPtr<T : 'static
定义了整个枚举的T的生存期,对吧?但是我只需要在Static(&'static T)
情况下的静态生存期,而在Rc(Rc<T>)
和Boxed(Box<T>)
的两种情况下都不需要(这是T在Box<T>
中拥有的生存期,恕我直言)。
我不明白...但是它有效(但是不知道为什么这样):
#[test]
fn smart_ptr_test() {
// Static string -> Ok, this of course works "hello" is static
let static_string = SmartPtr::Static("hello");
// Boxed vector -> But it's not 'static, why does this work?
let vector = vec!["hello"];
let box_vector = SmartPtr::Boxed(Box::new(vector));
// Rc'd vector -> why does this work?, vector_rc is not static
let vector_rc = Rc::new(vec!["hello"]);
let box_vector = SmartPtr::Rc(vector_rc);
}
答案 0 :(得分:0)
感谢trentcl和Shepmaster。这篇 http://stackoverflow.com/questions/40053550/the-compiler-suggests-i-add-a-static-lifetime-because-the-parameter-type-may-no的帖子提供了帮助,现在情况更加清晰了(也许不是100%,但现在足够清晰)。
我举了一个新的例子来说明为什么'static
的生存期对于枚举情况Boxed(Box<T>)
也是有意义的:
pub enum SmartPtr<T : 'static> where T : ?Sized {
Rc(Rc<T>),
Boxed(Box<T>),
Static(&'static T),
}
struct Bar {
data: Vec<String>,
}
struct Foo<'a> {
data: &'a Vec<String>,
}
#[test]
fn smart_ptr_test_2() {
// Example 1: Does compile: Bar is 'static (since vector is moved)
{
let vec2 = vec!["hello".to_string()];
let bar = Box::new(Bar {
data: vec2
});
let box3 = SmartPtr::Boxed(bar);
}
// Example 2: Does not compile ('a in Foo is inferred to be 'static but in my code it's not)
{
let vec1 = vec!["hello".to_string()];
let foo = Box::new(Foo {
// compiler error: 'note: borrowed value must be valid for the static lifetime'
data: &vec1
});
// when this line is here: the compiler infers lifetime 'a of Foo to be 'static
let box2 = SmartPtr::Boxed(foo);
// <--- life of 'vec1' ends here; it's not 'static since 'vec1' goes out of scope here
}
}