问题
Construction of an object allocates data needed for lifetime of that object, but also creates another object that needs to keep references to the data:
pub fn new() -> Obj {
let data = compute();
Obj {
original: data,
processed: AnotherObj {
reference: &data
}
}
}
Is it possible to express this in Rust's terms?
Here I'd like Obj
, AnotherObj
and data
to have the same lifetime, and of course outlive the new()
call.
回答1:
A raw design of the structs based on your requirements might look like this:
struct AnotherObj<'a> {
original: &'a Vec<i8>, // Let's agree on Vec<i8> as your "data" type.
}
struct Obj<'a> {
original: Vec<i8>, // <-------------------+
processed: AnotherObj<'a>, // should point here --+
}
However it's very tricky to get working (personally, I wasn't able to) because you want the 'a
in AnotherObj<'a>
to be the lifetime of original
. However you must supply a lifetime to Obj<'a>
and thus you would have to specify Obj<'tbc>
where 'tbc
is the lifetime of the Obj
to be created.
I suggest the following alternatives:
1. Make AnotherObj actually own the original
Why not? Obj
will own AnotherObj
, so it can still have access to original
as a nested child:
pub struct AnotherObj {
original: Vec<i8>,
}
pub struct Obj {
processed: AnotherObj,
}
pub fn new() -> Obj {
let data = vec![1,2,3];
Obj {
processed: AnotherObj {
original: data,
// ...
}
}
}
// access as obj.processed.original, you can even create a getter `fn original(&self)`
2. Shared pointer design
Straightforward use of refcounted pointers:
use std::rc::Rc;
pub struct AnotherObj {
original: Rc<Vec<i8>>,
}
pub struct Obj {
original: Rc<Vec<i8>>,
processed: AnotherObj,
}
pub fn new() -> Obj {
let data = Rc::new(vec![1,2,3]);
Obj {
original: data.clone(),
processed: AnotherObj {
original: data.clone(),
}
}
}
3. With raw pointers
Options 1. and 2. will bring you the peace of mind of the safe Rust gods, therefore I don't recommend this third option. I still post it here for completeness. Note: it compiles, but I never tested it at runtime, so it may bite. There's only safe code below but you'll have to go in unsafe
land when you want to dereference the raw pointer.
use std::ptr;
pub struct AnotherObj {
original: *mut Vec<i8>,
}
pub struct Obj {
original: Vec<i8>,
processed: AnotherObj,
}
pub fn new() -> Obj {
let data = vec![1,2,3];
let mut obj = Obj {
original: data,
processed: AnotherObj {
original: ptr::null_mut(),
}
};
obj.processed.original = &mut obj.original as *mut Vec<i8>;
obj
}
来源:https://stackoverflow.com/questions/30823880/struct-that-owns-some-data-and-a-reference-to-the-data