I'm trying to implement a smart pointer that should be able to reference data of type T
either borrowed with the lifetime 'a
or borrowed with the lifetime '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),
}
The SmartPtr
will also contain other enum fields like Rc
and Box
(the example above has been simplified). SmartPtr
will be mostly used in structs that should be cloneable ... when the input data T
(for example a static string) is 'static
I don't want to clone the data.
I would like to implement Clone
for this:
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)
}
}
}
}
The compiler fails:
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),
| ^^^^^^^^^^^
How do I fix this?
Edited
As I wrote in the comment, my SmartPtr makes no sense. But this seems to make sense:
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
}
I don't see why the 'static
is required in SmartPtr<T : 'static
. The SmartPtr<T : 'static
defines the lifetime of T for the entire enum, right? But I only need a static lifetime in case Static(&'static T)
, not for the two cases Rc(Rc<T>)
and Boxed(Box<T>)
(T is owned in Box<T>
- a lifetime makes no sense IMHO).
I don't get it... but it works (but don't see why this works):
#[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);
}