Borrowing battles in Rust
About
The knowledge gained from winning my fights against the borrow checker is ever fleeting. Hopefully documenting it here will preserve some understanding.
Battles
A
async fn get_html(url: &str) -> Result<String, Error> {
ClientBuilder::native().connect("http://localhost:4444")
.map_err(Error::ClientInitializationError)
.and_then(|c| {
c.source().map_err(Error::WebDriverError)
}).await
}
// error[E0515]: cannot return value referencing function parameter `c`
// --> src/main.rs:15:13
// |
// 15 | c.source().map_err(Error::WebDriverError)
// | ----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// | |
// | returns a value referencing data owned by the current function
// | `c` is borrowed here
//
// For more information about this error, try `rustc --explain E0515`.
// error: could not compile `web-scraping-1` due to previous error
My understanding here is that the closure is assuming ownership of the client
(c). As a result, the data is being discarded at the end of the invocation and
there is nothing left to return.
Theoretically, this is resolved by borrowing the data instead but we're dealing
with futures here and .as_ref() is not an available method for futures.
B
The Rust book demonstrates a simple example where a variable outlives.
fn main() {
let r; // ---------+-- 'a
// |
{ // |
let x = 5; // -+-- 'b |
r = &x; // | |
} // -+ |
// |
println!("r: {}", r); // |
} // ---------+
The C equivalent code compiles fine and may execute as "expected", but r is
actually a wild pointer once the nested scope exits.
#include <stdio.h>
void main() {
int *r;
{
int x = 5;
r = &x;
}
printf("The value of 'x' is %d", *r);
}