This doesn't work because &robot.get_data() creates a temporary value that goes out of scope. I know that one way I can fix this is to have the do_stuff function just taken an Option<Data> but then it seems like the called would need to call it with cloned Data since it can't just send a reference.
It is more idiomatic to use match as an expression here instead of forward declaring our_data.
#[derive(Clone)]
struct Data {
pub x: i32,
pub y: i32,
}
struct Agent {
q: i32,
r: i32,
}
impl Agent {
pub fn get_data(&self) -> Data {
Data {
x: self.q,
y: self.r,
}
}
fn do_stuff(agent: &Agent, data: Option<&Data>) {
let our_data = match data {
// Note: We need to clone the inner `&Data` because
// `Agent::get_data()` returns an owned `Data` and not a borrowed
// one (like the `data` parameter)
Some(d) => d.clone(),
None => agent.get_data(),
};
todo!()
}
}
Your original code won't compile as-is because Agent::get_data() constructs a new (owned) Data, whereas the thing inside the data parameter is borrowed. I needed to make a copy of the data parameter's contents (d.clone()) so both branches have the same type.
A quick question about this solution: under the hood, is the compiler still cloning the data or is it smartly just passing ownership of the memory? If this struct was something like 8 gigs of memory, am I going to have issues with perf?
Assuming that the 8GiB of memory is stored on the heap (since it's probably gonna overflow the stack), and the structs merely hold a pointer to it, no, there is no cloning going on.