I want to know what is the reason for this error.here is my code:
enum Command {
Request(u32)
}
trait Processor {
fn on_command(&'static self,cmd: Command);
}
struct Server {
partition_size: u32,
entities: Vec<Box<dyn Processor>>,
}
impl Server {
fn select_processor(&self, partition_id: u32) -> Option<&Box<dyn Processor>> {
let index = partition_id % self.partition_size;
self.entities.get(index as usize)
}
fn process_command(&self, cmd: Command) {
match cmd {
Command::Request(partition_id) => {
let processor = self.select_processor(partition_id);
if let Some(processor) = processor {
processor.on_command(cmd)
}
}
}
}
}
I got an error:
error[E0521]: borrowed data escapes outside of method
--> src/server/demo.rs:24:33
|
21 | fn process_command(&self, cmd: Command) {
| -----
| |
| `self` is a reference that is only valid in the method body
| let's call the lifetime of this reference `'1`
...
24 | let processor = self.select_processor(partition_id);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| `self` escapes the method body here
| argument requires that `'1` must outlive `'static`
When I try to modify on_command to fn on_command(& self,cmd: Command), there is no problem.what is the reason for this error?
on_command requiring &'static self means it poses the API-contract:
I need a reference that stays valid forever.
process_command has &self, which means:
I need a reference of any lifetime (that stays valid for at least the duration of the function call)
you “connect” the two lifetimes since the &Box<dyn Processor> reference is sort-of derived from the self: &Server one:
the call let processor = self.select_processor(partition_id); produces the &Box<dyn Processor> from the &Server using fn select_processor
the type signature select_processor(&self, partition_id: u32) -> Option<&Box<dyn Processor>> contains elided lifetimes for &self and &Box<dyn Processor>. Such elided lifetimes (one input, one output lifetime) desugar to be connected, i.e. the same lifetime:
If you compare the requirements, it doesn’t work out. “a reference that stays valid forever” as required by on_command allows on_command’s function body to do things such as letting the reference escape outside of the function. For example, you can freely write such a reference to a global (static or thread-local) variable, or send it to another thread that keeps running for a long time. If a function like on_command is allowed to let the reference “escape” in this way, the compiler will, at the caller site, pessimistically assume that it does escape, too. Lifetime analysis / borrow checking always happens locally, one function at a time. (This is a feature! And super useful to avoid great confusion when programming larger Rust code bases.)
On the other hand the reference “of any lifetime” where you only know that it “stays valid for at least the duration of the function call”, which is what process_command receives. It must not let this reference “escape” the current function/method call to process_command because there’s no guarantee the reference it receives is valid for any longer. Calling on_command on it (or a derived reference of the same lifetime) is hence forbidden.
Is my understanding correct?
because on_command is declared as &'static self, it requires the lifecycle of Processor to be 'static as well. when I get the processor in process_command, the compiler does not consider it to be 'static, so this error occurs.
when I change process_command to process_command(&'static self, cmd: Command), the declaration period of Server is also 'static, so all its properties become 'static. at this time, the processor I get in the process_command is considered by the compiler to be 'static, so it meets the declaration period requirement.
Yes, I wouldn’t use the same phrasing[1], but that sounds about right in terms of understanding.
I think the call to processor.on_command(cmd) involves a second transformation by-the-way; before on_command is called, &Box<dyn Processor> will deref-coerce into &dyn Processor. This coercion preserves the lifetime, too, though; so the same principle applies.
Thank you very much and I'm glad to have your help,I already understand its principle, your explanation is very useful.I think you are right, I will try it.