move occurs because `data` has type `Vec<u8>`, which does not implement the `Copy` trait - rust

I am trying to print some data for debugging purposes when I encountered an error. You can have a look at the full code here.
The error occurred when I tried to print data returned from the prepare_hash_data() function, which returns a Vec<u8>.
let data = self.prepare_hash_data()?; // returns Vec<u8>
println!("{}", String::from_utf8(data)?); // error here
let mut hasher = Sha256::new();
hasher.input(&data[..]);
println!("{}", hasher.result_str().as_str());
self.hash = hasher.result_str();
The prepare_hash_data() function is given below. Other details are omitted. Simply, it is just a function that returns Vec<u8>
fn prepare_hash_data(&self) -> Result<Vec<u8>, failure::Error> {
let content = (
self.hash_prev_block.clone(),
self.transactions.clone(),
self.timestamp,
DIFFICULTY,
self.nonce
);
let bytes = bincode::serialize(&content)?;
Ok(bytes)
}
The error given is
error[E0382]: borrow of moved value: `data`
--> src/block.rs:63:23
|
60 | let data = self.prepare_hash_data()?;
| ---- move occurs because `data` has type `Vec<u8>`, which does not implement the `Copy` trait
61 | println!("{}", String::from_utf8(data)?);
| ---- value moved here
62 | let mut hasher = Sha256::new();
63 | hasher.input(&data[..]);
| ^^^^ value borrowed here after move
I tried the following ways
Implementing Copy trait. But, Vec<u8> can't have the Copy trait as described here.
Looking at E0382 given in the error message, there are two ways suggested.
Using a reference, we can let another function borrow the value without changing its ownership.
But how should I use reference in this example?
Should I change the function signature to something like this fn prepare_hash_data(&self) -> Result<&Vec<u8>, failure::Error>?
With Rc, a value cannot be owned by more than one variable.
Don't know how to implement.
I tried cloning the data by println!("{}", String::from_utf8(data.clone())?);
But, it gives another error backtrace::backtrace::trace_unsynchronized
For the full error log, click here
What should be the correct approach to printing some data that can't be copied or cloned without moving it for later usage in subsequent lines?
I did look at the following solutions but can't relate the answer.
move occurs because value has type Vec, which does not implement the Copy trait
'move occurs because value has type' Rust error

I am trying to print some data for debugging purposes
The code you provided:
println!("{}", String::from_utf8(data)?);
Is not the correct way to debug-print data.
For one, String::from_utf8 consumes the data, destroying it in the process. Further, your data most likely isn't valid UTF8 data, so String::from_utf8 will only throw an error.
Use debug printing instead, it works out of the box:
println!("{:?}, data);
 
I retract my previous answer because it partially missed your problem.
It still contained valuable information, so I have kept it below. If someone disagrees, feel free to delete it together with this sentence.
 
--Previous Answer--
Your problem is that String::from_utf8 consumes its argument, meaning, data cannot be accessed any more afterwards.
Here is your problem in a more compact example:
fn main() {
let data: Vec<u8> = "Hello!".as_bytes().to_vec();
// Consumes `data`
println!("{}", String::from_utf8(data).unwrap());
// `data` cannot be accessed any more, as it got moved
// into `String::from_utf8`
println!("Length of vector: {}", data.len());
}
error[E0382]: borrow of moved value: `data`
--> src/main.rs:9:38
|
2 | let data: Vec<u8> = "Hello!".as_bytes().to_vec();
| ---- move occurs because `data` has type `Vec<u8>`, which does not implement the `Copy` trait
...
5 | println!("{}", String::from_utf8(data).unwrap());
| ---- value moved here
...
9 | println!("Length of vector: {}", data.len());
| ^^^^^^^^^^ value borrowed here after move
|
help: consider cloning the value if the performance cost is acceptable
|
5 | println!("{}", String::from_utf8(data.clone()).unwrap());
| ++++++++
In your case this can be easily fixed, though. The reason it consumes the data is because String is an owning variable. It owns its data, meaning, if you create it from a Vec, it stores the Vec data internally.
There is another type: &str, a string slice. It's very similar to String, just that it doesn't own its data, but merely references it. That means you can create it without destroying data:
fn main() {
let data: Vec<u8> = "Hello!".as_bytes().to_vec();
// Borrows `data`
println!("{}", std::str::from_utf8(&data).unwrap());
// `data` is still accessible because it was only borrowed
println!("Length of vector: {}", data.len());
}
Hello!
Length of vector: 6
That said, the given solution is only a workaround. The proper way to fix this is to implement Display.
As your data object clearly has more meaning than just a bunch of bytes, create a proper struct that represents its meaning.
There are two ways I would consider:
A newtype struct, like struct MyData(Vec<u8>), for which you can implement Display.
A String. As you convert it to a string anyway, why not just make it a string right away, as the return value of prepare_hash_data? Note that if your reason to have it a Vec is that it is binary data, then you shouldn't convert it to a string via from_utf8, as it's not UTF-8 data. If it is valid UTF-8 data, however, use a String right away, not a Vec<u8>. And String already implements Display and can be printed without further conversion.

Related

Programming in Rust , how to fix error[E0515] "cannot return value referencing local variable"?

Please help me to compile my code attached bellow. The compiler says that following 2 patterns depending on which lines I comment out.
The program reads a &str which is a simple "svg path command" like code then parses it. The pasted code has been simplified for simplicity. It uses Regex to split the input string into lines then study each line in the main for loop. Each loop pushes the parse result onto a vector. Finally the function returns the vector.
Basically the compiler says returning the vector is not allowed because it refers local variable. Though I don't have any workaround.
error[E0597]: `cmd` does not live long enough
--> src/main.rs:24:25
|
24 | codeV = re.captures(cmd.as_str());
| ----- ^^^ borrowed value does not live long enough
| |
| borrow might be used here, when `codeV` is dropped and runs the destructor for type `Option<regex::Captures<'_>>`
...
30 | }
| - `cmd` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are defined
error[E0515]: cannot return value referencing local variable `cmd`
--> src/main.rs:31:1
|
24 | codeV = re.captures(cmd.as_str());
| --- `cmd` is borrowed here
...
31 | V //Error
| ^ returns a value referencing data owned by the current function
Playground
use regex::Regex;
pub fn parse(path:&str) {//->Vec<Option<regex::Captures<>>> //Error
let reg_n=Regex::new(r"\n").unwrap();
let path=reg_n.replace_all("\n"," ");
let reg_cmd=Regex::new(r"(?P<cmd>[mlhv])").unwrap();
let path=reg_cmd.replace_all(&path,"\n${cmd}");
let cmdV=reg_n.split(&path);
//let cmdV:Vec<&str> = reg.split(path).map(|x|x).collect();
let mut V:Vec<Option<regex::Captures<>>>=vec![];
let mut codeV:Option<regex::Captures<>>=None;
let mut count=0;
for cmd_f in cmdV{//This loop block has been simplified.
count+=1;
if count==1{continue;}
let mut cmd="".to_string();
cmd=cmd_f.to_string();
cmd=cmd.replace(" ","");
let re = Regex::new(r"\{(?P<code>[^\{^\}]{0,})\}").unwrap();
codeV = re.captures(cmd.as_str());
//cmd= re.replace_all(cmd.as_str(),"").to_string();
let cmd_0=cmd.chars().nth(0).unwrap();
//cmd.remove(0);
//V.push(codeV); //Compile error
V.push(None); //OK
}
//V
}
fn main() {
parse("m {abcd} l {efgh}");
}
Though I don't have any workaround.
regex's captures refer to the string they matched for efficiency. This means they can't outlive that string, as the match groups are essentially just offsets into that string.
Since the strings you match are created in the loop body, this means captures can't escape the loop body.
Aside from not creating strings in the loop body (or even the function), the solution / workaround is to convert your capture groups to owned data and store that: instead of trying to return a vector of captures, extract from the capture the data you actually want, convert it to an owned String (or tuple thereof, or whatever), and push that onto your vector.
e.g. https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0107333e30f831a418d75b280e9e2f31
you can use cmd.clone().as_str() if you not sure the value has borrowed or no

error[E0597]: borrowed value does not live long enough in While loop

I am really new to Rust, I am having trouble solving this error, but it only happens if I comment out the while statement , basicly I am asking values from the console and storing it in a HashMap:
use std::collections::HashMap;
use std::io;
fn main() {
let mut customers = HashMap::new();
let mut next_customer = true;
while next_customer {
let mut input_string = String::new();
let mut temp_vec = Vec::with_capacity(3);
let mut vec = Vec::with_capacity(2);
println!("Insert new customer f.e = customer id,name,address:");
io::stdin().read_line(&mut input_string);
input_string = input_string.trim().to_string();
for s in input_string.split(",") {
temp_vec.push(s);
}
vec.push(temp_vec[1]);
vec.push(temp_vec[2]);
let mut key_value = temp_vec[0].parse::<i32>().unwrap();
customers.insert(key_value, vec);
next_customer = false;
}
println!("DONE");
}
The code results in the error
error[E0597]: `input_string` does not live long enough
--> src/main.rs:14:18
|
14 | for s in input_string.split(",") {
| ^^^^^^^^^^^^ borrowed value does not live long enough
...
20 | customers.insert(key_value, vec);
| --------- borrow later used here
21 | next_customer = false;
22 | }
| - `input_string` dropped here while still borrowed
As others have said the problem lies with the lifetime and/or type of the values getting put into the customers map.
customers.insert(key_value, vec);
| --------- borrow later used here
Often this happens when the compiler has decided to give an object a type that you didn't expect. To find out what it's doing you can force the type, and see how it complains. Changing the code to:
let mut customers: HashMap<(),()> = HashMap::new();
Gives us two relevant errors:
20 | customers.insert(key_value, vec);
| ^^^^^^^^^ expected `()`, found `i32`
...
20 | customers.insert(key_value, vec);
| ^^^ expected `()`, found struct `std::vec::Vec`
|
= note: expected unit type `()`
found struct `std::vec::Vec<&str>`
So the type that the compiler wants to give our customers object is HashMap<i32, Vec<&str>>
The problem is that the &str lifetime has got to be inside the block as we don't store the Strings anywhere, and they can't have 'static lifetime since they're user input.
This means we probably want a HashMap<i32,Vec<String>>.
Changing the code to use one of those gives us an error about vec not having the right type: It's getting deduced as a Vec<&str>, but we want a Vec<String>.
We have two options.
Convert the vec to the right type just before we insert it into the map using customers.insert(key_value, vec.iter().map(|s| s.to_string()).collect()). (Though you may want to extract it to a variable for clarity).
Explicitly change the type of vec to Vec<String>
Option 1 "just works". While option 2 leads us down a path of making similar changes closer and closer to the read_line call.
Once you've decided on the fix in option 1, you can remove the manual type annotations that were added to work out the fix, if you find them overly noisy.
The issue is that you are passing around reference to underlying &str values that will get dropped. One way is to take the input string, trim and split it, then clone it going into the other vector.
let temp_vec: Vec<String> = input_string.trim().split(",").map(|t| t.to_string()).collect();
vec.push(temp_vec[1].clone());
vec.push(temp_vec[2].clone());

How can I construct a container from within a closure with a 'static bound? [duplicate]

This question already has an answer here:
Mutating the same data in multiple 'static closures
(1 answer)
Closed 4 years ago.
I'm using the libpulse_binding library, and I'm trying to obtain a sequence of SinkInputInfos from the get_sink_input_info_list function:
pub fn get_sink_input_info_list<F>(
&self,
callback: F,
) -> Operation<dyn FnMut(ListResult<&SinkInputInfo>)>
where
F: FnMut(ListResult<&SinkInputInfo>) + 'static,
The function takes a callback and calls it once for each SinkInputInfo it produces. I'm trying to collect all those SinkInputInfos into a single list so I can get a clearer view of the state of the world. Irritatingly, SinkInputInfo doesn't implement Copy or Clone, so I made a custom struct and implemented From to get the useful information out of the SinkInputInfo:
struct StreamInfo {
readable_name: String,
binary_name: String,
pid: String,
}
impl From<&pulse::context::introspect::SinkInputInfo<'_>> for StreamInfo {
fn from(info: &pulse::context::introspect::SinkInputInfo) -> Self {
let name = info.proplist.gets("application.name").unwrap();
let binary = info.proplist.gets("application.process.binary").unwrap();
let pid = info.proplist.gets("application.process.id").unwrap();
StreamInfo {
readable_name: name,
binary_name: binary,
pid: pid,
}
}
}
However, this doesn't seem to work. I have the following code:
let mut sink_infos: Vec<StreamInfo> = Vec::new();
let op = introspector.get_sink_input_info_list(|result| match result {
pulse::callbacks::ListResult::Item(info) => sink_infos.push(info.into()),
pulse::callbacks::ListResult::End => {},
pulse::callbacks::ListResult::Error => panic!("Error getting sink input info"),
});
but it doesn't compile:
error[E0373]: closure may outlive the current function, but it borrows `sink_infos`, which is owned by the current function
--> src/bin/play-pause.rs:49:52
|
49 | let op = introspector.get_sink_input_info_list(|result| match result {
| ^^^^^^^^ may outlive borrowed value `sink_infos`
50 | pulse::callbacks::ListResult::Item(info) => sink_infos.push(info.into()),
| ---------- `sink_infos` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src/bin/play-pause.rs:49:14
|
49 | let op = introspector.get_sink_input_info_list(|result| match result {
| ______________^
50 | | pulse::callbacks::ListResult::Item(info) => sink_infos.push(info.into()),
51 | | pulse::callbacks::ListResult::End => {},
52 | | pulse::callbacks::ListResult::Error => panic!("Error getting sink input info"),
53 | | });
| |______^
help: to force the closure to take ownership of `sink_infos` (and any other referenced variables), use the `move` keyword
|
49 | let op = introspector.get_sink_input_info_list(move |result| match result {
| ^^^^^^^^^^^^^
tldr: the closure has to have the 'static lifetime because libpulse_binding says so (presumably because it gets handed to the PulseAudio C API, which can then do whatever it likes with it), but sink_infos is not 'static, and the closure has to borrow sink_infos in order to append to it, which makes the closure not 'static, IIUC.
How can I make a Vec (or any container, I'm not fussy) of SinkInputInfos given a 'static closure that gets called repeatedly with a &SinkInputInfo?
The basic problem here is that you're running into Rust's borrowing rules:
Given an object T, it is only possible to have one of the following:
Having several immutable references (&T) to the object (also known as aliasing).
Having one mutable reference (&mut T) to the object (also known as mutability).
You are trying to keep a reference &Vec to your Vec (so you can use it later) whilst simultaneously trying to add things to it in a closure (i.e. an &mut Vec). Rust doesn't know that you won't try to use the &Vec while the closure is using the &mut Vec, so it doesn't let you create a &mut Vec in the closure while there's still a &Vec hanging around outside the closure.
The next best thing you can do is to use an Rc. This will allow you to sidestep the compiler's borrow-checking and instead defer it to runtime. However: this means that if you try to violate the borrowing rules while your program is running, it will panic instead of being a compile-time error!
For the most part, you can treat the Rc<Vec<_>> the same as a normal Vec, since Rc implements Deref.
Since you also want to be able to mutate the Vec in order to add things to it, you also need to put it in a RefCell. This will put a lock around the Vec, making sure that you only have one &mut Vec available at once, and that if you have an &Vec, you can't have a &mut Vec (again, if you try to violate the rules, your program will panic). You can use the .borrow() and .borrow_mut() methods on RefCell to get shared and mutable references to the Vec (there are also try_* variants of these methods, if you can do something sensible if a borrow is not possible).
If you didn't use a RefCell, you would only be able to obtain immutable/shared references (&Vec) from the Rc (unless you only had one Rc, but then you wouldn't need an Rc!)
Try something like the following:
use std::cell::RefCell;
use std::rc::Rc;
let sink_infos: Rc<RefCell<Vec<StreamInfo>>> = Rc::new(RefCell::new(Vec::new()));
let sink_infos2 = sink_infos.clone(); // Create a new Rc which points to the same data.
let op = introspector.get_sink_input_info_list(move |result| match result {
pulse::callbacks::ListResult::Item(info) => sink_infos2.borrow_mut().push(info.into()),
pulse::callbacks::ListResult::End => {},
pulse::callbacks::ListResult::Error => panic!("Error getting sink input info"),
});

How to append to string values in a hash table in Rust?

I have source files that contain text CSV lines for many products for a given day. I want to use Rust to collate these files so that I end up with many new destination CSV files, one per product, each containing portions of the lines only specific to that product.
My current solution is to loop over the lines of the source files and use a HashMap<String, String> to gather the lines for each product. I split each source line and use the element containing the product ID as a key, to obtain an Entry (occupied or vacant) in my HashMap. If it is vacant, I initialize the value with a new String that is allocated up-front with a given capacity, so that I can efficiently append to it thereafter.
// so far, so good (the first CSV item is the product ID)
let mystringval = productmap.entry(splitsource[0].to_owned()).or_insert(String::with_capacity(SOME_CAPACITY));
I then want to append formatted elements of the same source line to this Entry. There are many examples online, such as
https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.entry
of how to make this work if the HashMap value is an integer:
// this works if you obtain an Entry from a HashMap containing int vals
*myval += 1;
I haven't figured out how to append more text to the Entry I obtain from my HashMap<String, String> using this kind of syntax, and I've done my best to research examples online. There are surprisingly few examples anywhere of manipulating non-numeric entries in Rust data structures.
// using the Entry obtained from my first code snippet above
*mystringval.push_str(sourcePortion.as_str());
Attempting to compile this produces the following error:
error: type `()` cannot be dereferenced
--> coll.rs:102:17
|
102 | *mystringval.push_str(sourcePortion.as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
How can I append to a String inside the Entry value?
*mystringval.push_str(sourcePortion.as_str()); is parsed as *(mystringval.push_str(sourcePortion.as_str())); and since String::push_str returns (), you get the () cannot be dereferenced error.
Using parentheses around the dereference solves the precedence issue:
(*mystringval).push_str(sourcePortion.as_str());
The reason *myval += 1 works is because unary * has a higher precedence than +=, which means it's parsed as
(*myval) += 1
Since or_insert returns &mut V, you don't need to dereference it before calling its methods. The following also works:
mystringval.push_str(sourcePortion.as_str());
If you inspect the type returned by or_insert:
fn update_count(map: &mut HashMap<&str, u32>) {
let () = map.entry("hello").or_insert(0);
}
You will see it is a mutable reference:
error[E0308]: mismatched types
--> src/main.rs:4:9
|
4 | let () = map.entry("hello").or_insert(0);
| ^^ expected &mut u32, found ()
|
= note: expected type `&mut u32`
found type `()`
That means that you can call any method that needs a &mut self receiver with no extra syntax:
fn update_mapping(map: &mut HashMap<&str, String>) {
map.entry("hello").or_insert_with(String::new).push_str("wow")
}
Turning back to the integer form, what happens if we don't put the dereference?
fn update_count(map: &mut HashMap<&str, i32>) {
map.entry("hello").or_insert(0) += 1;
}
error[E0368]: binary assignment operation `+=` cannot be applied to type `&mut i32`
--> src/main.rs:4:5
|
4 | map.entry("hello").or_insert(0) += 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use `+=` on type `&mut i32`
error[E0067]: invalid left-hand side expression
--> src/main.rs:4:5
|
4 | map.entry("hello").or_insert(0) += 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid expression for left-hand side
The difference is that the += operator automatically takes a mutable reference to the left-hand side of the expression. Expanded, it might look something like this:
use std::ops::AddAssign;
fn update_count(map: &mut HashMap<&str, i32>) {
AddAssign::add_assign(&mut map.entry("hello").or_insert(0), 1);
}
Adding the explicit dereference brings the types back to one that has the trait implemented:
use std::ops::AddAssign;
fn update_count(map: &mut HashMap<&str, i32>) {
AddAssign::add_assign(&mut (*map.entry("hello").or_insert(0)), 1);
}

How to retrieve a user-defined type from a for loop?

I defined an Attribute type and I have a Vec<Attribute> that I am looping over to retrieve the "best" one. This was similar to my first attempt:
#[derive(Debug)]
struct Attribute;
impl Attribute {
fn new() -> Self {
Self
}
}
fn example(attrs: Vec<Attribute>, root: &mut Attribute) {
let mut best_attr = &Attribute::new();
for a in attrs.iter() {
if is_best(a) {
best_attr = a;
}
}
*root = *best_attr;
}
// simplified for example
fn is_best(_: &Attribute) -> bool {
true
}
I had the following compile error:
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:17:13
|
17 | *root = *best_attr;
| ^^^^^^^^^^ cannot move out of borrowed content
After some searching for a solution, I resolved the error by doing the following:
Adding a #[derive(Clone)] attribute to my Attribute struct
Replacing the final statement with *root = best_attr.clone();
I don't fully understand why this works, and I feel like this is a rough solution to the problem I was having. How does this resolve the error, and is this the correct way to solve this problem?
You are experiencing the basis of the Rust memory model:
every object can (and must!) be owned by only exactly one other object
most types are never implicitly copied and always moved (there are some exceptions: types that implement Copy)
Take this code for example:
let x = String::new();
let y = x;
println!("{}", x);
it generates the error:
error[E0382]: borrow of moved value: `x`
--> src/main.rs:4:20
|
3 | let y = x;
| - value moved here
4 | println!("{}", x);
| ^ value borrowed here after move
|
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
x, of type String, is not implicitly copyable, and thus has been moved into y. x cannot be used any longer.
In your code, when you write *root = *best_attr, you are first dereferencing the reference best_attr, then assigning the dereferenced value to *root. Your Attribute type is not Copy, thus this assignment should be a move.
Then, the compiler complains:
cannot move out of borrowed content
Indeed, best_attr is an immutable reference, which does not allow you to take ownership of the value behind it (it doesn't even allow modifying it). Allowing such a move would put the object owning the value behind the reference in an undefined state, which is exactly what Rust aims to prevent.
In this case, your best option is indeed to create a new object with the same value as the first one, which is exactly what the trait Clone is made for.
#[derive(Clone)] allows you to mark your structs as Clone-able, as long as all of their fields are Clone. In more complex cases, you'll have to implement the trait by hand.

Resources