Lifetimes of references in mutable Vector - rust

I have an algorithm like:
let seed: Foo = ...
let mut stack: Vec<&Foo> = Vec::new();
stack.push(&seed);
while let Some(next) = stack.pop {
let more_foos: Vec<Foo> = some_function_of(next) // 0 to many Foos returned
for foo in more_foos {
stack.push(&foo);
}
}
I receive the error that foo does not live long enough. I assume this is because stack has a greater lifetime. How can I fix this?

more_foos and its contents are dropped at the end of each iteration of the while let loop. However, you're trying to store a reference to items from more_foos in stack, and that's not valid, as that would lead to dangling pointers.
Instead, you should make stack own Foo objects instead.
fn main() {
let seed: Foo = unimplemented!();
let mut stack: Vec<Foo> = Vec::new();
stack.push(seed);
while let Some(next) = stack.pop() {
let more_foos: Vec<Foo> = unimplemented!();
for foo in more_foos {
stack.push(foo);
}
}
}
Note: the for loop can be replaced with:
stack.extend(more_foos);
which might be slightly more efficient.

Related

How to use common BTreeMap variable in rust(single thread)

Here is my original simplified code, I want to use a global variable instead of the variables in separate functions. What's the suggestion method in rust?
BTW, I've tried to use global or change to function parameter, both are nightmare for a beginner. Too difficult to solve the lifetime & variable type cast issue.
This simple program is only a single thread tool, so, in C language, it is not necessary the extra mutex.
// version 1
use std::collections::BTreeMap;
// Trying but failed
// let mut guess_number = BTreeMap::new();
// | ^^^ expected item
fn read_csv() {
let mut guess_number = BTreeMap::new();
let lines = ["Tom,4", "John,6"];
for line in lines.iter() {
let split = line.split(",");
let vec: Vec<_> = split.collect();
println!("{} {:?}", line, vec);
let number: u16 = vec[1].trim().parse().unwrap();
guess_number.insert(vec[0], number);
}
for (k, v) in guess_number {
println!("{} {:?}", k, v);
}
}
fn main() {
let mut guess_number = BTreeMap::new();
guess_number.insert("Tom", 3);
guess_number.insert("John", 7);
if guess_number.contains_key("John") {
println!("John's number={:?}", guess_number.get("John").unwrap());
}
read_csv();
}
To explain how hard it is for a beginner, by pass parameter
// version 2
use std::collections::BTreeMap;
fn read_csv(guess_number: BTreeMap) {
// ^^^^^^^^ expected 2 generic arguments
let lines = ["Tom,4", "John,6"];
for line in lines.iter() {
let split = line.split(",");
let vec: Vec<_> = split.collect();
println!("{} {:?}", line, vec);
let number: u16 = vec[1].trim().parse().unwrap();
guess_number.insert(vec[0], number);
}
}
fn main() {
let mut guess_number = BTreeMap::new();
guess_number.insert("Tom", 3);
guess_number.insert("John", 7);
if guess_number.contains_key("John") {
println!("John's number={:?}", guess_number.get("John").unwrap());
}
read_csv(guess_number);
for (k, v) in guess_number {
println!("{} {:?}", k, v);
}
}
After some effort, try & error to get the possible work type BTreeMap<&str, i32>
// version 3
use std::collections::BTreeMap;
fn read_csv(guess_number: &BTreeMap<&str, i32>) {
// let mut guess_number = BTreeMap::new();
let lines = ["Tom,4", "John,6"];
for line in lines.iter() {
let split = line.split(",");
let vec: Vec<_> = split.collect();
println!("{} {:?}", line, vec);
let number: i32 = vec[1].trim().parse().unwrap();
guess_number.insert(vec[0], number);
}
for (k, v) in guess_number {
println!("{} {:?}", k, v);
}
}
fn main() {
let mut guess_number: BTreeMap<&str, i32> = BTreeMap::new();
guess_number.insert("Tom", 3);
guess_number.insert("John", 7);
if guess_number.contains_key("John") {
println!("John's number={:?}", guess_number.get("John").unwrap());
}
read_csv(&guess_number);
for (k, v) in guess_number {
println!("{} {:?}", k, v);
}
}
will cause following error
7 | fn read_csv(guess_number: &BTreeMap<&str, i32>) {
| -------------------- help: consider changing this to be a mutable reference: `&mut BTreeMap<&str, i32>`
...
16 | guess_number.insert(vec[0], number);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `guess_number` is a `&` reference, so the data it refers to cannot be borrowed as mutable
The final answer (seems not suggest use global in Rust, so use 'mutable reference').
// version 4
use std::collections::BTreeMap;
fn read_csv(guess_number: &mut BTreeMap<&str, i32>) {
let lines = ["Tom,4", "John,6"];
for line in lines.iter() {
let split = line.split(",");
let vec: Vec<_> = split.collect();
println!("{} {:?}", line, vec);
let number: i32 = vec[1].trim().parse().unwrap();
guess_number.insert(vec[0], number);
}
}
fn main() {
let mut guess_number: BTreeMap<&str, i32> = BTreeMap::new();
guess_number.insert("Tom", 3);
guess_number.insert("John", 7);
if guess_number.contains_key("John") {
println!("John's number={:?}", guess_number.get("John").unwrap());
}
read_csv(&mut guess_number);
for (k, v) in guess_number {
println!("{} {:?}", k, v);
}
}
This question is not specific to BTreeMaps but for pretty much all data types, such as numbers, strings, vectors, enums, etc.
If you want to pass a variable (value) from one function to another, you can do that in various ways in Rust. Typically you either move the value or you pass a reference to it. Moving is something quite specific to Rust and its ownership model. This is really essential, so if you have serious intentions to learn Rust, I strongly suggest you read the chapter Understanding Ownership from "the book". Don't get discouraged if you don't understand it from one reading. Spend as much time as needed, as you really can't move forward w/o this knowledge.
As for global variables, there are very few situations where they should be used. In Rust using global variables is slightly more difficult, compared to most other languages. This thread is quite useful, although you might find it a bit difficult to comprehend. My advice to a beginner would be to first fully understand the basic concept of moving and passing references.

Rust peekable double reference

Why does a peekable iterator return a double reference in an Option?
struct Foo {}
let mut foovec = vec![];
foovec.push(Foo {});
let mut iter = foovec.iter().peekable();
let next = iter.peek();
next is an Option<&&Foo>, not an Option<&Foo>.
How do I get it to be the latter?
I do not want to use .into_iter() because I do not want to consume the vec. I just want a borrowed reference to the Foo struct wrapped in an Option.
peek yields references to whatever you're iterating over. If that's also references, it'll yield double references. You can use the copied Option adapter to remove that level of indirection:
struct Foo {}
let mut foovec = vec![];
foovec.push(Foo {});
let mut iter = foovec.iter().peekable();
// use `copied` here to go from Option<&&_> to Option<&_>
let next = iter.peek().copied();
Alternatively, you can just call next after you checked that you want the peeked value:
struct Foo {}
let mut foovec = vec![];
foovec.push(Foo {});
let mut iter = foovec.iter().peekable();
if is_okay(iter.peek()) {
let next = iter.next(); // `next` has type `&Foo`
}
You could even use pattern matching to remove one level of indirection:
if let Some(&next) = iter.peek() {
// `next` has type `&Foo` in this block
}

How to fix use of moved value in Rust?

I am trying to convert a yaml file to xml using Rust and I am not able to figure out how to fix this error regarding the use of moved value. I think I understand why this error is coming, but haven't got a clue about what to do next.
Here's the code:
struct Element {
element_name: String,
indentation_count: i16,
}
struct Attribute<'a> {
attribute_name: &'a str,
attribute_value: &'a str,
}
fn convert_yaml_to_xml(content: String, indentation_count: i16) -> String {
let mut xml_elements: Vec<Element> = vec![];
let mut attributes: Vec<Attribute> = vec![];
xml_elements.push(Element {element_name: "xmlRoot".to_string(), indentation_count: -1});
let mut target: Vec<u8> = Vec::new();
let mut xml_data_writer = EmitterConfig::new().perform_indent(true).create_writer(&mut target);
let mut attribute_written_flag = false;
let mut xml_event;
xml_event = XmlEvent::start_element("xmlRoot");
for line in content.lines() {
let current_line = line.trim();
let caps = indentation_count_regex.captures(current_line).unwrap();
let current_indentation_count = caps.get(1).unwrap().as_str().to_string().len() as i16;
if ELEMENT_REGEX.is_match(current_line) {
loop {
let current_attribute_option = attributes.pop();
match current_attribute_option {
Some(current_attribute_option) => {
xml_event.attr(current_attribute_option.attribute_name, current_attribute_option.attribute_value)
},
None => {
break;
},
};
}
xml_data_writer.write(xml_event);
// Checking if the line is an element
let caps = ELEMENT_REGEX.captures(current_line).unwrap();
let element_name = caps.get(2);
let xml_element_struct = Element {
indentation_count: current_indentation_count,
element_name: element_name.unwrap().as_str().to_string(),
};
xml_elements.push(xml_element_struct);
xml_event = XmlEvent::start_element(element_name.unwrap().as_str());
attribute_written_flag = false;
} else if ATTR_REGEX.is_match(current_line) {
// Checking if the line is an attribute
let caps = ATTR_REGEX.captures(current_line).unwrap();
let attr_name = caps.get(2);
let attr_value = caps.get(3);
// Saving attributes to a stack
attributes.push(Attribute{ attribute_name: attr_name.unwrap().as_str(), attribute_value: attr_value.unwrap().as_str() });
// xml_event.attr(attr_name.unwrap().as_str(), attr_value.unwrap().as_str());
}/* else if NEW_ATTR_SET_REGEX.is_match(current_line) {
let caps = NEW_ATTR_SET_REGEX.captures(current_line).unwrap();
let new_attr_set_name = caps.get(2);
let new_attr_set_value = caps.get(3);
current_xml_hash.insert("name".to_string(), new_attr_set_name.unwrap().as_str().to_string());
current_xml_hash.insert("value".to_string(), new_attr_set_value.unwrap().as_str().to_string());
} */
}
if attribute_written_flag {
xml_data_writer.write(xml_event);
}
for item in xml_elements.iter() {
let event = XmlEvent::end_element();
let event_name = item.element_name.to_string();
xml_data_writer.write(event.name(event_name.as_str()));
}
println!("OUTPUT");
println!("{:?}", target);
return "".to_string();
}
And here's the error:
error[E0382]: use of moved value: `xml_event`
--> src/main.rs:77:25
|
65 | let mut xml_event;
| ------------- move occurs because `xml_event` has type `StartElementBuilder<'_>`, which does not implement the `Copy` trait
...
77 | xml_event.attr(current_attribute_option.attribute_name, current_attribute_option.attribute_value)
| ^^^^^^^^^ --------------------------------------------------------------------------------------- `xml_event` moved due to this method call, in previous iteration of loop
|
note: this function takes ownership of the receiver `self`, which moves `xml_event`
--> /Users/defiant/.cargo/registry/src/github.com-1ecc6299db9ec823/xml-rs-0.8.4/src/writer/events.rs:193:24
|
193 | pub fn attr<N>(mut self, name: N, value: &'a str) -> StartElementBuilder<'a>
| ^^^^
From XmlEvent::start_element() documentation we see that it produces a StartElementBuilder<'a>.
From StartElementBuilder<'a>::attr() documentation we see that it consumes the StartElementBuilder<'a> (the first parameter is self, not &mut self) and produces a new StartElementBuilder<'a> (which is probably similar to self but considers the expected effect of .attr()).
This approach is known as the consuming builder pattern, which is used in Rust (for example std::thread::Builder).
The typical usage of such an approach consists in chaining the function calls: something.a().b().c().d() such as something is consumed by a(), its result is consumed by b(), the same about c() and finally d() does something useful with the last result.
The alternative would be to use mutable borrows in order to modify in place something but dealing with mutable borrows is known as difficult in some situations.
In your case, you can just reassign the result of .attr() to xml_event because otherwise the .attr() function would have no effect (its result is discarded) and xml_event would become unusable because it is consumed; reassigning it makes it usable again afterwards (at least i guess, i didn't try).

Why do String::from(&str) and &str.to_string() behave differently in Rust?

fn main() {
let string = "Rust Programming".to_string();
let mut slice = &string[5..12].to_string(); // Doesn't work...why?
let mut slice = string[5..12].to_string(); // works
let mut slice2 = String::from(&string[5..12]); // Works
slice.push('p');
println!("slice: {}, slice2: {}, string: {}", slice,slice2,string);
}
What is happening here? Please explain.
The main issue here that & have lower priority than method call.
So, actual code is
let mut slice = &(string[5..12].to_string());
So you a taking a reference to temporary String object that dropped and cannot be used later.
You should wrap your reference in parenthesis and call the method on the result.
fn main() {
let string = "Rust Programming".to_string();
let mut slice = (&string[5..12]).to_string(); // ! -- this should work -- !
let mut slice = string[5..12].to_string(); // works
let mut slice2 = String::from(&string[5..12]); // Works
slice.push('p');
println!("slice: {}, slice2: {}, string: {}", slice,slice2,string);
}

Why can't I make a reference to memory inside "if"?

I could make a copy of this vector, but that will take time and memory.
I could write another println, but this is just an example — instead of println there may be several loops — and it will take space and complicate the code. I could perform the conversion in main and write two versions of the function call, but changing the reference is much easier.
fn foo(mut a: &Vec<i32>) {
let mut c: Vec<i32>;
if a[0] == 0 {
c = vec![1; 3];
a = &c;
}
println!("{:?}", a);
}
fn main() {
let a: Vec<i32> = vec![0; 3];
foo(&a);
}
Error:
main.rs:9:14: 9:15 error: `c` does not live long enough
main.rs:9 a = &c;
^
The rules of lifetime in rust are quite (very) strict: if you have a reference to an object, this object must live longer than the reference, in both direction.
This means the reference must be created after the object.
In your case, a exists before c, so the assignment a = &c is invalid. A simple fix can be to create a copy of the reference after c is created and work on this copy:
fn foo(vec_ref: &Vec<i32>){
let mut c: Vec<i32>;
let mut a = vec_ref
if a[0] == 0 {
c = vec![1; 3];
a = &c;
}
println!("{:?}",a);
}
or in a more rusty way:
fn foo(vec_ref: &Vec<i32>){
let mut c: Vec<i32>;
let a = if vec_ref[0] == 0 {
c = vec![1; 3];
&c
} else {
vec_ref
};
println!("{:?}",a);
}

Resources