Rust 'borrowed value does not live long enough' while assigning to a static variable - rust

My goal is to keep a static variable and have the value be overridden by CLI arguments but I'm having a hard time finding a way to keep a static copy of the value I get from the args iterator.
static mut ROOT_DIRECTORY: &str = "C:\\test\\source";
fn main() {
let args: Vec<String> = env::args().collect();
let mut index = 0;
for arg in args {
match arg.as_str() {
"/r" => unsafe {
if args_length <= index + 1 {
panic!("Missing root directory value.");
}
ROOT_DIRECTORY = args.get(index + 1).unwrap();
if ROOT_DIRECTORY.is_empty() {
panic!("Root directory value cannot be empty.")
}
}
}
}
}
Gives the following compilation error
error[E0597]: `args` does not live long enough
--> src\main.rs:90:34
|
90 | ROOT_DIRECTORY = args.get(index + 1).unwrap();
| ^^^^---------------
| |
| borrowed value does not live long enough
| argument requires that `args` is borrowed for `'static`
...
168 | }
| - `args` dropped here while still borrowed
error[E0382]: borrow of moved value: `args`
--> src\main.rs:90:34
|
54 | let args: Vec<String> = env::args().collect();
| ---- move occurs because `args` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
...
76 | for arg in args {
| ----
| |
| value moved here
| help: consider borrowing to avoid moving into the for loop: `&args`
...
90 | ROOT_DIRECTORY = args.get(index + 1).unwrap();
|
Is there any way for me to create a static copy of the value from the iterator?

You cannot do that. Static variables must be 'static, that is, must not contain non-'static lifetimes. This is why you can elide lifetimes in the declaration of static references. Yours is actually equivalent to:
static mut ROOT_DIRECTORY: &'static str = "C:\\test\\source";
And your args is a local variable, so a reference to it is not 'static.
Is there any way for me to create a static copy of the value from the iterator?
The easiest option is to make the static variable own its data, instead of being a reference, that is, let it be a String. Unfortunately, the static constructor must be const, and the only const constructor of String that I know of is String::new(). You could add a helper function fn get_root_directory() -> &'static str that reads the global variable and returns the default if unset, but if you are into that, you could make the static a Option<String>:
static mut ROOT_DIRECTORY: Option<String> = None;
pub fn get_root_directory() -> &'static str {
unsafe {
ROOT_DIRECTORY.as_deref().unwrap_or("C:\\test\\source")
}
}
Another option would be to leak a heap-allocated string to make it static. As long as you only assign to it once, the leak should not be a problem. Something like:
static mut ROOT_DIRECTORY: &'static str = "default value";
fn main() {
let x = "...".to_string();
unsafe {
ROOT_DIRECTORY = Box::leak(x.into_boxed_str());
}
}

Related

How can I iterate on a Bevy Query and keep a reference to the iterated value so that I can use it later?

I have a borrow in the empty variable and I want to extend its life. In the commented code-block, I attempt to address it, but the reference is no longer available. I have to loop through the loop again to find the match in order to act on it.
How can I loop through a query looking for a best-match and then act on it once I know it's the best match, without having to loop through to find it again?
use bevy::prelude::*;
struct Person;
struct Name(String);
fn main() {
App::build()
.add_default_plugins()
.add_startup_system(startup.system())
.add_system(boot.system())
.run();
}
fn boot(mut query: Query<(&Person, &mut Name)>) {
let mut temp_str = String::new();
let mut empty: Option<&mut Name> = None;
for (_p, mut n_val) in &mut query.iter() {
if n_val.0.to_lowercase() > temp_str.to_lowercase() {
temp_str = n_val.0.clone();
empty = Some(&mut n_val);
}
}
println!("{}", temp_str);
if let Some(n) = empty {
// ...
}
// for (_p, mut n_val) in &mut query.iter() {
// if n_val.0 == temp_str {
// n_val.0 = "a".to_string();
// }
// }
}
fn startup(mut commands: Commands) {
commands
.spawn((Person, Name("Gene".to_string())))
.spawn((Person, Name("Candace".to_string())))
.spawn((Person, Name("Zany".to_string())))
.spawn((Person, Name("Sarah".to_string())))
.spawn((Person, Name("Carl".to_string())))
.spawn((Person, Name("Robert".to_string())));
}
Cargo.toml:
[package]
name = "sample"
version = "0.1.0"
authors = [""]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bevy = "0.1.3"
Specific error:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:17:33
|
17 | for (_p, mut n_val) in &mut query.iter() {
| ^^^^^^^^^^^-
| | |
| | temporary value is freed at the end of this statement
| creates a temporary which is freed while still in use
...
24 | if let Some(n) = empty {
| ----- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
error[E0597]: `n_val` does not live long enough
--> src/main.rs:20:26
|
20 | empty = Some(&mut n_val);
| ^^^^^^^^^^ borrowed value does not live long enough
21 | }
22 | }
| - `n_val` dropped here while still borrowed
23 | println!("{}", temp_str);
24 | if let Some(n) = empty {
| ----- borrow later used here
You cannot extend the lifetime of a reference, but that is not your issue here, the error says temporary value dropped while borrowed, so you must extend the lifetime of your temporary.
If you wonder what temporary, the compiler also points to that (literally) in the error message: query.iter(). This is a function call, and the returned value is not bound to anything, so the compiler creates a temporary value for that. Then you iterate using a reference to that temporary. When the for loop ends, the temporary is dropped and any reference lifetime to it expires.
The solution is to bind the temporary to a local variable. This way you extend the lifetime of the object to the scope of the variable:
let mut iter = query.iter();
for (_p, n_val) in &mut iter {
if n_val.0.to_lowercase() > temp_str.to_lowercase() {
temp_str = n_val.0.clone();
empty = Some(n_val);
}
}
PS: I find quite bizarre the pattern of iterating over &mut iter. I would expect the return of iter() to implement Iterator or IntoIterator directly, but it looks like this is not the case.

rust E0597: borrowed value does not live lnog enough

I am trying to rewrite an algorithm from javascript to rust. In the following code, I get borrowed value does not live long enough error at line number 17.
[dependencies]
scraper = "0.11.0"
use std::fs;
fn get_html(fname: &str) -> String {
fs::read_to_string(fname).expect("Something went wrong reading the file")
}
pub mod diff_html {
use scraper::{element_ref::ElementRef, Html};
pub struct DiffNode<'a> {
node_ref: ElementRef<'a>,
}
impl<'a> DiffNode<'a> {
fn from_html(html: &str) -> Self {
let doc = Self::get_doc(&html);
let root_element = doc.root_element().to_owned();
let diffn = Self {
node_ref: root_element,
};
diffn
}
fn get_doc(html: &str) -> Html {
Html::parse_document(html).to_owned()
}
}
pub fn diff<'a>(html1: &str, _html2: &str) -> DiffNode<'a> {
let diff1 = DiffNode::from_html(&html1);
diff1
}
}
fn main() {
//read strins
let filename1: &str = "test/test1.html";
let filename2: &str = "test/test2.html";
let html1: &str = &get_html(filename1);
let html2: &str = &get_html(filename2);
let diff1 = diff_html::diff(html1, html2);
//write html
//fs::write("test_outs/testx.html", html1).expect("unable to write file");
//written output file.
}
warning: unused variable: `diff1`
--> src\main.rs:43:9
|
43 | let diff1 = diff_html::diff(html1, html2);
| ^^^^^ help: if this is intentional, prefix it with an underscore: `_diff1`
|
= note: `#[warn(unused_variables)]` on by default
error[E0597]: `doc` does not live long enough
--> src\main.rs:17:32
|
14 | impl<'a> DiffNode<'a> {
| -- lifetime `'a` defined here
...
17 | let root_element = doc.root_element().to_owned();
| ^^^--------------------------
| |
| borrowed value does not live long enough
| assignment requires that `doc` is borrowed for `'a`
...
22 | }
| - `doc` dropped here while still borrowed
I want a detailed explanation/solution if possible.
root_element which is actually an ElementRef has reference to objects inside doc, not the actual owned object. The object doc here is created in from_html function and therefore owned by the function. Because doc is not returned, it is dropped / deleted from memory at the end of from_html function block.
ElementRef needs doc, the thing it is referencing to, to be alive when it is returned from the memory.
pub mod diff_html {
use scraper::{element_ref::ElementRef, Html};
pub struct DiffNode<'a> {
node_ref: ElementRef<'a>,
}
impl<'a> DiffNode<'a> {
fn from_html(html: &'a scraper::html::Html) -> Self {
Self {
node_ref: html.root_element(),
}
}
}
pub fn diff<'a>(html1_string: &str, _html2_string: &str) {
let html1 = Html::parse_document(&html1_string);
let diff1 = DiffNode::from_html(&html1);
// do things here
// at the end of the function, diff1 and html1 is dropped together
// this way the compiler doesn't yell at you
}
}
More or less you need to do something like this with diff function to let the HTML and ElementRef's lifetime to be the same.
This behavior is actually Rust's feature to guard values in memory so that it doesn't leak or reference not referencing the wrong memory address.
Also if you want to feel like operating detachable objects and play with reference (like java, javascript, golang) I suggest reading this https://doc.rust-lang.org/book/ch15-05-interior-mutability.html

Iterate through a whole file one character at a time

I'm new to Rust and I'm struggle with the concept of lifetimes. I want to make a struct that iterates through a file a character at a time, but I'm running into issues where I need lifetimes. I've tried to add them where I thought they should be but the compiler isn't happy. Here's my code:
struct Advancer<'a> {
line_iter: Lines<BufReader<File>>,
char_iter: Chars<'a>,
current: Option<char>,
peek: Option<char>,
}
impl<'a> Advancer<'a> {
pub fn new(file: BufReader<File>) -> Result<Self, Error> {
let mut line_iter = file.lines();
if let Some(Ok(line)) = line_iter.next() {
let char_iter = line.chars();
let mut advancer = Advancer {
line_iter,
char_iter,
current: None,
peek: None,
};
// Prime the pump. Populate peek so the next call to advance returns the first char
let _ = advancer.next();
Ok(advancer)
} else {
Err(anyhow!("Failed reading an empty file."))
}
}
pub fn next(&mut self) -> Option<char> {
self.current = self.peek;
if let Some(char) = self.char_iter.next() {
self.peek = Some(char);
} else {
if let Some(Ok(line)) = self.line_iter.next() {
self.char_iter = line.chars();
self.peek = Some('\n');
} else {
self.peek = None;
}
}
self.current
}
pub fn current(&self) -> Option<char> {
self.current
}
pub fn peek(&self) -> Option<char> {
self.peek
}
}
fn main() -> Result<(), Error> {
let file = File::open("input_file.txt")?;
let file_buf = BufReader::new(file);
let mut advancer = Advancer::new(file_buf)?;
while let Some(char) = advancer.next() {
print!("{}", char);
}
Ok(())
}
And here's what the compiler is telling me:
error[E0515]: cannot return value referencing local variable `line`
--> src/main.rs:37:13
|
25 | let char_iter = line.chars();
| ---- `line` is borrowed here
...
37 | Ok(advancer)
| ^^^^^^^^^^^^ returns a value referencing data owned by the current function
error[E0597]: `line` does not live long enough
--> src/main.rs:49:34
|
21 | impl<'a> Advancer<'a> {
| -- lifetime `'a` defined here
...
49 | self.char_iter = line.chars();
| -----------------^^^^--------
| | |
| | borrowed value does not live long enough
| assignment requires that `line` is borrowed for `'a`
50 | self.peek = Some('\n');
51 | } else {
| - `line` dropped here while still borrowed
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0515, E0597.
For more information about an error, try `rustc --explain E0515`.
error: could not compile `advancer`.
Some notes:
The Chars iterator borrows from the String it was created from. So you can't drop the String while the iterator is alive. But that's what happens in your new() method, the line variable owning the String disappears while the iterator referencing it is stored in the struct.
You could also try storing the current line in the struct, then it would live long enough, but that's not an option – a struct cannot hold a reference to itself.
Can you make a char iterator on a String that doesn't store a reference into the String? Yes, probably, for instance by storing the current position in the string as an integer – it shouldn't be the index of the char, because chars can be more than one byte long, so you'd need to deal with the underlying bytes yourself (using e.g. is_char_boundary() to take the next bunch of bytes starting from your current index that form a char).
Is there an easier way? Yes, if performance is not of highest importance, one solution is to make use of Vec's IntoIterator instance (which uses unsafe magic to create an object that hands out parts of itself) :
let char_iter = file_buf.lines().flat_map(|line_res| {
let line = line_res.unwrap_or(String::new());
line.chars().collect::<Vec<_>>()
});
Note that just returning line.chars() would have the same problem as the first point.
You might think that String should have a similar IntoIterator instance, and I wouldn't disagree.

Two closures that use references to parent scope

Im trying to create a struct that stores 2 closures, each with read references to an parent scope variable where they were created.
After I have closed over the references in the parent scope, how do I make sure they live for the same amount of time as the closures?
For example:
struct S {
x: bool,
}
type Closure = Box<dyn Fn()>;
struct Env {
fn_a: Closure,
fn_b: Closure,
}
fn get_env() -> Env {
let s = S { x: true };
let fn_a = || {
&s.x;
};
let fn_b = || {
&s.x;
};
Env {
fn_a: Box::new(fn_a),
fn_b: Box::new(fn_b),
}
}
fn main() {
let env = get_env();
}
playground
Results in:
error[E0597]: `s` does not live long enough
--> src/main.rs:16:10
|
15 | let fn_a = || {
| -- value captured here
16 | &s.x;
| ^ borrowed value does not live long enough
...
23 | fn_a: Box::new(fn_a),
| -------------- cast requires that `s` is borrowed for `'static`
...
26 | }
| - `s` dropped here while still borrowed```
It depends on your scenario. How long would the returned closures live?
If it lives as long as the Env value, what about moving s into the Env value and accessing s from the Env value?
If you don't know (or don't want to spend the trouble to figure out) the lifetime for the closures, a convenient (although slightly less efficient) way is to use Rc, then move a clone of the Rc from the results:
Playground
use std::rc::Rc;
pub struct S {
x: bool,
}
pub type Closure = Box<dyn Fn()>;
#[allow(unused)]
pub struct Env {
fn_a: Closure,
fn_b: Closure,
}
fn get_env() -> Env {
let s = Rc::new(S { x: true });
let cloned = Rc::clone(&s);
let fn_a = move || {
s.x;
};
let fn_b = move || {
cloned.x;
};
Env {
fn_a: Box::new(fn_a),
fn_b: Box::new(fn_b),
}
}
fn main() {
let _env = get_env();
}

Why can borrowed string literal outlive its owner by faking a lifetime?

I understand that a borrow cannot outlive the existence of the thing it points to, to eradicate the dangling pointers.
A borrow or an alias can outlive the owner by faking the lifetimes:
fn main() {
let e;
let first = "abcd";
{
let second = "defgh";
e = longest(first, second);
}
println!("{}", e);
}
fn longest<'a>(first: &'a str, second: &'a str) -> &'a str {
if first.len() > second.len() {
first
} else {
second
}
}
Result:
defgh
In the above example, the variable e has a longer lifetime than the second variable and clearly the first & second variables lifetimes are different.
When e is initialized with longest(first, second) it gets the second variable whose lifetime to function call is faked as it is equal to first but it is confined to the block and it is assigned to e which will outlive the second. Why is this OK?
This is due to the fact that both of these have the 'static lifetime.
Here's an example that doesn't work because the str here does not live for the life of the program like a &'static str does.
The only change is the following line: let second = String::from("defgh"); and the next line where it is passed to the longest function.
fn main() {
let e;
let first = "abcd";
{
let second = String::from("defgh");
e = longest(first, &second);
}
println!("{}", e);
}
fn longest<'a>(first: &'a str, second: &'a str) -> &'a str {
if first.len() > second.len() {
first
} else {
second
}
}
Here's the error:
error[E0597]: `second` does not live long enough
--> src/main.rs:6:28
|
6 | e = longest(first, &second);
| ^^^^^^^ borrowed value does not live long enough
7 | }
| - `second` dropped here while still borrowed
8 | println!("{}", e);
| - borrow later used here
More information can be found in Static - Rust By Example

Resources