I wrote a function to test the deference of Box in Rust:
struct S;
fn f1() {
// test1
let s1 : Box<S> = Box::new(S);
let s2 : S = *s1; // The S in s1 is moved to s2;
// test2
let mut s3 : Box<S> = Box::new(S);
// let s4 : S = *DerefMut::deref_mut(&mut s3); //compile error: cannot move out of a mutable reference.
// test3
let mut s5 : &mut S = &mut S;
// let s6 :S = *s5; //compile error: cannot move out of a mutable reference.
}
I know a value cannot be moved out of a reference (like test2 and test3), but why the value in Box can be moved out (like test1). I thought test1 and test2 are equal.
Because Box is known to the compiler as a very special type. It has a special exception to the usual dereference rules to make this possible.
You can find a more detailed explanation in this blog post: https://manishearth.github.io/blog/2017/01/10/rust-tidbits-box-is-special/
Related
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).
The compiler issues an error on the following code, and I don't know how to fix it. Note, it works for the non-closure (direct call) case, it's just when I try to capture the value s in a closure that it fails. What's the right way to fix this?
fn count_letter(data : String, c : char) -> i32 {
data.chars().filter(|x| *x == c).count() as i32
}
fn main()
{
// Pretend this has to be a String, even though in this toy example it could be a str
let s = "there once was a man from nantucket".to_string();
// Works
println!("{:?}", count_letter(s, 'n'));
// error[E0507]: cannot move out of `s`, a captured variable in an `FnMut` closure
let result : Vec<(char, i32)> = ('a'..='z').map(|x| (x, count_letter(s.clone, x))).collect();
println!("{:?}", result);
}
The error is: error[E0507]: cannot move out of s, a captured variable in an FnMut closure
I gues you want this behavior:
fn count_letter(data : &str, c : char) -> i32 {
data.chars().filter(|x| *x == c).count() as i32
}
fn main()
{
// Pretend this has to be a String, even though in this toy example it could be a str
let s = "there once was a man from nantucket".to_string();
// Works
println!("{:?}", count_letter(&s, 'n'));
// Also works
let result : Vec<(char, i32)> = ('a'..='z').map(|x| (x, count_letter(&s, x))).collect();
println!("{:?}", result);
}
I'm trying to understand the closures in Rust. I wrote a code like this;
use std::ops::Add;
fn main() {
let mut a = "a string".to_string();
let mut cl = || {
a.add(" another string");
};
cl();
println!("{:?}", a);
}
I expect a result like "a string another string". In the documentation it says that try to avoid using clone() where possible, but I can't manage to compile this code without using a = a.clone().add(" another string").
To answer your original question: You can't. This is because your string a is moved into the closure. You can't have it back though. See Denys answer for a solution.
A solution to this specific problem would be to use push_str instead of Add, because push_str requires a mutable referece instead of a moved value.
fn main() {
let mut a = "a string".to_string();
let mut cl = || {
a.push_str(" another string");
};
cl();
println!("{:?}", a);
}
A solution would be to move the value to the closure, then make it return it:
use std::ops::Add;
fn main() {
let mut a = "a string".to_string();
let cl = || {
a.add(" another string")
};
a = cl();
println!("{:?}", a);
}
But capturing the outer scope is rather limited. You can't for example have two closures defined this way. You might want a more flexible solution:
let a = "a string".to_string();
let c1 = |s: String| {
s.add(" another string")
};
let c2 = |s: String| {
s + " and another one"
};
let a = c1(a);
let a = c2(a);
Given this:
fn main() {
let variable = [0; 15];
}
The Rust compiler produces this warning:
= note: #[warn(unused_variables)] on by default
= note: to avoid this warning, consider using `_variable` instead
What's the difference between variable and _variable?
The difference is an underscore at the front, which causes the Rust compiler to allow it to be unused. It is kind of a named version of the bare underscore _ which can be used to ignore a value.
However, _name acts differently than _. The plain underscore drops the value immediately while _name acts like any other variable and drops the value at the end of the scope.
An example of how it does not act exactly the same as a plain underscore:
struct Count(i32);
impl Drop for Count {
fn drop(&mut self) {
println!("dropping count {}", self.0);
}
}
fn main() {
{
let _a = Count(3);
let _ = Count(2);
let _c = Count(1);
}
{
let _a = Count(3);
let _b = Count(2);
let _c = Count(1);
}
}
prints the following (playground):
dropping count 2
dropping count 1
dropping count 3
dropping count 1
dropping count 2
dropping count 3
The key difference between _variable and variable is that first one tells compiler not to give any warnings if we do not use it in our code. Example:
// src/main.rs
fn main() {
let _x = 1;
let y = 2;
}
Compiling main.rs gives:
warning: unused variable: `y`
--> src/main.rs:3:9
|
3 | let y = 2;
| ^ help: if this is intentional, prefix it with an underscore: `_y`
|
= note: `#[warn(unused_variables)]` on by default
The more interesting case is when we are comparing _ with _variable.
Ignoring an Unused Variable by Starting Its Name with _:
The syntax _x still binds the value to the variable, whereas _ doesn’t bind at all.
Consider example:
// src/main.rs
fn main() {
let s = Some(String::from("Hello!"));
if let Some(_s) = s {
println!("found a string");
}
println!("{:?}", s);
}
When we try to compile main.rs we get error:
error[E0382]: borrow of moved value: `s`
--> src/main.rs:8:22
|
4 | if let Some(_s) = s {
| -- value moved here
...
8 | println!("{:?}", s);
| ^ value borrowed here after partial move
|
= note: move occurs because value has type `std::string::String`, which does not implement the `Copy` trait
help: borrow this field in the pattern to avoid moving `s.0`
|
4 | if let Some(ref _s) = s {
| ^^^
Aha! The syntax _x still binds the value to the variable, which means that we are moving the ownership of s to _s, thus, we can no longer access variable s anymore; which happens when we try to print value of s.
The correct way of doing the above is:
// src/main.rs
fn main() {
let s = Some(String::from("Hello!"));
if let Some(_) = s {
println!("found a string");
}
println!("{:?}", s);
}
Above code works just fine. s does not get moved into _, so we can still access it later.
Sometimes I use _ with iterators:
fn main() {
let v = vec![1, 2, 3];
let _ = v
.iter()
.map(|x| {
println!("{}", x);
})
.collect::<Vec<_>>();
}
Compiling gives result:
1
2
3
When doing more complex operations on iterable types above example acts as utility for me.
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);
}