Reputation: 420
I want to print out the parameters passed to the FastCGI application:
extern crate fastcgi; // 1.0.0
use std::io::Write;
fn main() {
fastcgi::run(|mut req| {
let mut output = String::from("Content-Type: text/plain\n\n");
{
let mut params = req.params();
loop {
let param = params.next();
match param {
Some(t) => output.push_str(&format!("{:?}", t)),
None => break,
}
}
}
write!(&mut req.stdout(), "{}", &output).unwrap_or(());
});
}
My code works but I don't understand why I need to do it that way. My intuition is that I could write this non-working code:
extern crate fastcgi; // 1.0.0
use std::io::Write;
fn main() {
fastcgi::run(|mut req| {
let mut output = String::from("Content-Type: text/plain\n\n");
let mut params = req.params();
loop {
let param = params.next();
match param {
Some(t) => output.push_str(&format!("{:?}", t)),
None => break,
}
}
write!(&mut req.stdout(), "{}", &output).unwrap_or(());
});
}
Compiler Output:
error[E0502]: cannot borrow `req` as mutable because it is also borrowed as immutable
--> src/main.rs:16:21
|
8 | let mut params = req.params();
| --- immutable borrow occurs here
...
16 | write!(&mut req.stdout(), "{}", &output).unwrap_or(());
| ^^^^^^^^^^^^ mutable borrow occurs here
17 | });
| - immutable borrow might be used here, when `params` is dropped and runs the destructor for type `std::boxed::Box<dyn std::iter::Iterator<Item = (std::string::String, std::string::String)>>`
I found the solution by Googling around and following suggestions of the compiler, but I don't understand why it is necessary.
Upvotes: 0
Views: 83
Reputation: 98396
If you look at the definition of Request::params
it is defined as:
pub fn params(&self) -> Params
that is deceptively simple, because Params
has a hidden lifetime generic. It is actually desugared to:
pub fn params<'s>(&'s self) -> Params<'s>
That means that as long as the return of this function lives, self
, that is the Request
, is considered borrowed.
Similarly the definition of Request::stdout
is desugared to:
pub fn stdout<'s>(&'s mut self) -> Stdout<'s>
This method borrows your object mutable, and as you probably know you cannot borrow the same object mutably and non-mutably at the same time.
Writing the extra scope limits the life of params
and frees the borrow just before calling stdout
so their lifetimes do not overlap and the code compiles.
If you do not like the extra indentation level you can also write:
drop(params);
just after the loop to finish the life of params
manually.
You may think that params()
and stdout()
have nothing in common internally and that you should be able to use them mutably at the same time. You might be right, but the compiler does not care, it only sees how these functions are defined, not what they do internally.
Upvotes: 2