I've got a simple struct and two instances of it as below:
#[derive(Debug)]
struct User {
first: String,
last: String,
age: u32,
}
let u1 = User {
first: String::from("John"),
last: String::from("Doe"),
age: 22,
};
let u2 = User {
first: String::from("Mary"),
..u1
};
println!("user: {:#?}", u1);
Error message:
error[E0382]: borrow of moved value: `u1`
--> src/main.rs:20:29
|
15 | let u2 = User {
| ______________-
16 | | first: String::from("Mary"),
17 | | ..u1
18 | | };
| |_____- value moved here
19 |
20 | println!("user: {:#?}", u1);
| ^^ value borrowed here after partial move
|
= note: move occurs because `u1.last` has type `std::string::String`, which does not implement the `Copy` trait
I tried to revise it to ..&u1 hoping it will pass the borrow check so that I could spread in the base struct (u1) to u2, but to no avail, wondering is it even possible for what I wanted to do here?
I understand it's because u1.last is a String, hence needing to pass a reference, but I'm not sure how to make it work in this scenario.
Your User type contains the type String, which owns the string data that it has (and doesn't impl Copy), which is why two users can't point to the same name in memory.
The solution you probably want:
#[derive(Debug, Clone)]
struct User {
first: String,
last: String,
age: u32,
}
fn main() {
let u1 = User {
first: String::from("John"),
last: String::from("Doe"),
age: 22,
};
let u2 = User {
first: String::from("Mary"),
..u1.clone() // Copy the strings into the new user
// (it also copies first, which is then thrown away? Maybe the compiler optimizes this away)
};
println!("user: {:#?}", u1);
}
but if you really want to have two users point to the same name in memory (pretty sure you don't), there are a couple of options:
You can change String to &'static str. This however means that you have to specify it when you compile. (You can't have a user type in their name at runtime, and store it in user)
#[derive(Debug)]
struct User {
first: &'static str,
last: &'static str,
age: u32,
}
fn main() {
let u1 = User {
first: "John",
last: "Doe",
age: 22,
};
let u2 = User {
first: "Mary",
..u1
};
println!("user: {:#?}", u1);
}
You can use a Rc to keep track of the references to a piece of memory. This way you don't have to worry about lifetimes and who's owning what. (Comes at a tiny runtime cost though)
use std::rc::Rc;
#[derive(Debug, Clone)]
struct User {
first: Rc<String>,
last: Rc<String>,
age: u32,
}
fn main() {
let u1 = User {
first: Rc::new(String::from("John")),
last: Rc::new(String::from("Doe")),
age: 22,
};
let u2 = User {
first: Rc::new(String::from("Mary")),
..u1.clone() // Clone the references, not the actual string. For strings with just a couple characters, the time difference is completely negligible)
};
println!("user: {:#?}", u1);
}
Use a Rc<Mutex<String>> instead if you want to modify the name later, and have it change in both u1 and u2.
Related
We have a static list of objects. We would like to create a static constant HashMap with the key being the names of the objects.
How do we do that?
As an example, here is the definition of a Book object:
struct Book<'a> {
name: &'a str,
author: &'a str,
id: i32,
}
Here is a static list of 3 books:
const ALL_BOOKS: &'static [Book] = &[
Book {
name: "Zero to One",
author: "James",
id: 2,
},
Book {
name: "Zero to One",
author: "Tom",
id: 1,
},
Book {
name: "Turtle all the way",
author: "Jerry",
id: 1,
},
];
We want to defined a dictionary of books with the key being the name of the book, and the value being a list of book with that name.
I notice that we have lazy_static from:
Rust best practices when specifying a constant hash map
Global mutable HashMap in a library
Here is what I tried:
lazy_static! {
static ref ALL_BOOKS_BY_SHORT_NAME: HashMap<String, Vec<Book<'static>>> = {
let mut map = HashMap::new();
for book in ALL_BOOKS {
if !map.contains_key(book.name) {
map.insert(book.name.to_owned(), vec![book]);
} else {
let mut list = map.get(book.name).unwrap();
list.push(book)
}
}
map
};
}
Here is the error:
error[E0308]: mismatched types
--> src/main.rs:42:9
|
30 | static ref ALL_BOOKS_BY_SHORT_NAME: HashMap<String, Vec<Book<'static>>> = {
| ----------------------------------- expected `HashMap<String, Vec<Book<'static>>>` because of return type
...
42 | map
| ^^^ expected struct `Book`, found `&Book<'_>`
|
= note: expected struct `HashMap<_, Vec<Book<'static>>>`
found struct `HashMap<_, Vec<&Book<'_>>>`
What does the '_ mean here? How do we solve that?
The '_ is "some lifetime". The actual lifetime is 'static, but the compiler doesn't know that at this stage of the compilation.
The problem is that you're iterating over a slice of Book<'static>s. And inserting items to the map. But iteration over a slice produces references, while your maps is expecting owned Books.
The fix is simple: clone or copy the books.
#[derive(Clone, Copy)]
struct Book<'a> { ... }
lazy_static! {
static ref ALL_BOOKS_BY_SHORT_NAME: HashMap<String, Vec<Book<'static>>> = {
let mut map = HashMap::new();
for book in ALL_BOOKS {
if !map.contains_key(book.name) {
map.insert(book.name.to_owned(), vec![*book]);
} else {
let mut list = map.get(book.name).unwrap();
list.push(*book)
}
}
map
};
}
Some more notes:
Prefer once_cell to lazy_static (its API is going to be part of std).
Use the entry API:
use once_cell::sync::Lazy;
static ALL_BOOKS_BY_SHORT_NAME: Lazy<HashMap<String, Vec<Book<'static>>>> = Lazy::new(|| {
let mut map = HashMap::<_, Vec<_>>::new();
for book in ALL_BOOKS {
map.entry(book.name.to_owned()).or_default().push(*book);
}
map
});
This allocates a string even for duplicate keys but given that this is only an initialization routine this likely doesn't matter.
I want to return a Vec from a method that contains the two variables created in the method.
I know the problem is that the variable created in the method will be destroyed when the method ends。What should I do if I want to return this Vec?
fn thing2vec(thing: &Thing) -> Vec<&str> {
let offset = chrono::FixedOffset::east(8 * 3600);
let bt = chrono::NaiveDateTime::from_timestamp(thing.begin_ts as i64, 0).add(offset);
let et = match thing.end_ts {
0 => {
"-"
}
_ => {
chrono::NaiveDateTime::from_timestamp(thing.end_ts as i64, 0).add(offset).to_string().as_str()
}
};
vec!(&thing.id, &thing.name, &format!("{}", thing.status), &bt.to_string(), et, &thing.comment)
}
error message:
|
21 | chrono::NaiveDateTime::from_timestamp(thing.end_ts as i64, 0).add(offset).to_string().as_str()
| ------------------------------------------------------------------------------------- temporary value created here
...
25 | vec!(&thing.id, &thing.name, &format!("{}", thing.status), &bt.to_string(), et, &thing.comment)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
|
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
If you really need to keep it a Vec, the simplest answer to pick an owned type, ie. Vec<String>, and clone if you need to. Like other comments said Cow could work as well, but does add its own complications.
If it were me, this looks like a structured format so I would just turn it into a struct and return it that way:
struct NewThing<'a> {
id: &'a str,
name: &'a str,
status: String,
// ..etc.
}
If not converting the &strs to Strings is important for performance, you can use Cow:
fn thing2vec<'a>(thing: &'a Thing) -> Vec<Cow<'a, str>> {
let offset = chrono::FixedOffset::east(8 * 3600);
let bt = chrono::NaiveDateTime::from_timestamp(thing.begin_ts as i64, 0).add(offset);
let et = match thing.end_ts {
0 => Cow::Borrowed("-"),
_ => Cow::Owned(
chrono::NaiveDateTime::from_timestamp(thing.end_ts as i64, 0)
.add(offset)
.to_string(),
),
};
vec![
Cow::Borrowed(&thing.id),
Cow::Borrowed(&thing.name),
Cow::Owned(format!("{}", thing.status)),
Cow::Owned(bt.to_string()),
et,
Cow::Borrowed(&thing.comment),
]
}
This question already has answers here:
How to borrow two disjoint fields when the borrow is behind a method call?
(1 answer)
cannot borrow `*self` as mutable more than once at a time
(1 answer)
Closed 1 year ago.
I am new to Rust. Here is a piece of code for computer stock transaction. The Strategy will buy some stocks when the SignalTrigger triggers, and sell those stocks if after 30s/90s in different way. The code can't be compiled. Here is the code:
use std::cmp;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::collections::BinaryHeap;
use std::convert::TryFrom;
use std::error::Error;
use std::fs::File;
use std::io;
use std::process;
#[derive(Debug)]
struct Depth {
ts: u32,
ap_vec: Vec<f64>,
bp_vec: Vec<f64>,
av_vec: Vec<u32>,
bv_vec: Vec<u32>,
}
struct Order {
ts: u32,
id: u32,
is_buy: bool,
is_mkt: bool,
vol: u32,
price: f64,
}
struct LongPosition {
vol_left: u32,
ts: u32,
}
struct Strategy {
order_id: u32,
prev_buy_ts: u32,
map_orderid_position: BTreeMap<u32, LongPosition>, // map<order_id, volume_left>
}
impl Strategy {
fn on_depth(&mut self, depth: &Depth) -> Vec<Order> {
let mut orders_vec: Vec<Order> = Vec::new();
for (order_id, long_position) in &mut self.map_orderid_position {
if depth.ts - long_position.ts > 90 * 1000 {
let order = self.make_order(depth.ts, false, true, long_position.vol_left, 0.0);
orders_vec.push(order);
} else if depth.ts - long_position.ts > 60 * 1000 {
let order = self.make_order(depth.ts,false,true,long_position.vol_left,depth.bp_vec[0]);
orders_vec.push(order);
}
}
return orders_vec;
}
fn make_order(&mut self, ts: u32, is_buy: bool, is_mkt: bool, vol: u32, price: f64) -> Order {
let order = Order {
id: self.order_id,
ts,
is_buy,
is_mkt,
vol,
price,
};
self.order_id = self.order_id + 1;
return order;
}
}
fn main() {
let empty_price_vec: Vec<f64> = Vec::new();
let map_orderid_position: BTreeMap<u32, LongPosition> = BTreeMap::new();
let mut strategy = Strategy {
prev_buy_ts: 0,
order_id: 0,
map_orderid_position: map_orderid_position,
};
}
The compile says:(I have comment line 88 and line 90 in the snippet)
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src\main.rs:46:29
|
44 | for (order_id, long_position) in &mut self.map_orderid_position {
| ------------------------------
| |
| first mutable borrow occurs here
| first borrow later used here
45 | if depth.ts - long_position.ts > 90 * 1000 {
46 | let order = self.make_order(depth.ts, false, true, long_position.vol_left, 0.0);
| ^^^^ second mutable borrow occurs here
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src\main.rs:49:29
|
44 | for (order_id, long_position) in &mut self.map_orderid_position {
| ------------------------------
| |
| first mutable borrow occurs here
| first borrow later used here
...
49 | let order = self.make_order(depth.ts,false,true,long_position.vol_left,depth.bp_vec[0]);
| ^^^^ second mutable borrow occurs here
error: aborting due to 2 previous errors; 12 warnings emitted
For more information about this error, try `rustc --explain E0499`.
error: could not compile `greeting`
I am a little confused about Rust, snippets like these are really common in other languages. Can you make an explanation and tell me how to fix(avoid) this situation?
You are borrowing the whole instance when you are calling self.make_order. The compiler cant be sure that you are not going the change map_orderid_position. Instead, you can create a standalone function and pass the mutable reference to order_id field to it.
impl Strategy {
fn on_depth(&mut self, depth: &Depth) -> Vec<Order> {
let mut orders_vec: Vec<Order> = Vec::new();
for (order_id, long_position) in &mut self.map_orderid_position {
if depth.ts - long_position.ts > 90 * 1000 {
let order = make_order(depth.ts, false, true, long_position.vol_left, 0.0, &mut self.order_id);
orders_vec.push(order);
} else if depth.ts - long_position.ts > 60 * 1000 {
let order = make_order(depth.ts,false,true,long_position.vol_left,depth.bp_vec[0], &mut self.order_id);
orders_vec.push(order);
}
}
return orders_vec;
}
}
fn make_order(ts: u32, is_buy: bool, is_mkt: bool, vol: u32, price: f64, order_id: &mut u32) -> Order {
let order = Order {
id: *order_id,
ts,
is_buy,
is_mkt,
vol,
price,
};
*order_id += 1;
return order;
}
Instead of updating self.order_id in the function make_order() you can update it in the function on_depth(). Then you don't have to use &mut self for make_order() and the problem is solved.
Example:
impl Strategy {
fn on_depth(&mut self, depth: &Depth) -> Vec<Order> {
let mut orders_vec: Vec<Order> = Vec::new();
for (order_id, long_position) in &self.map_orderid_position {
let order = if depth.ts - long_position.ts > 90 * 1000 {
self.make_order(depth.ts, false, true, long_position.vol_left, 0.0)
} else if depth.ts - long_position.ts > 60 * 1000 {
self.make_order(depth.ts, false, true, long_position.vol_left, depth.bp_vec[0])
} else {
continue;
};
orders_vec.push(order);
self.order_id += 1; // Update `self.order_id` here
}
return orders_vec;
}
// Changed `&mut self` to `&self`
fn make_order(&self, ts: u32, is_buy: bool, is_mkt: bool, vol: u32, price: f64) -> Order {
let order = Order {
id: self.order_id,
ts,
is_buy,
is_mkt,
vol,
price,
};
// Removed `self.order_id = self.order_id + 1`
return order;
}
}
From the book:
The benefit of having this restriction is that Rust can prevent data
races at compile time. A data race is similar to a race condition and
happens when these three behaviors occur:
Two or more pointers access the same data at the same time.
At least one of the pointers is being used to write to the data.
There’s no mechanism being used to synchronize access to the data.
Data races cause undefined behavior and can be difficult to diagnose
and fix when you’re trying to track them down at runtime; Rust
prevents this problem from happening because it won’t even compile
code with data races!
I don't know what the best practice is but I would generally make a clone of the variable for reading, for, example:
fn main() {
let mut s = String::from("hello");
let r1 = s.clone(); // if this was &mut s, I'll get the same error
let r2 = &mut s;
println!("{}, {}", r1, r2);
}
So, you could probably try making clone of self.map_orderid_position since you are just reading values from it.
I'm beginning in Rust and I like very much the syntax with .. to create an instance of another instance but I don't know how to use it with a reference of an instance instead.
Try it here.
#[derive(Debug)]
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
fn main() {
let user1 = User {
email: String::from("someone#example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
let user2 = foo(&user1);
println!("{:?}", user2);
}
fn foo(user: &User) -> User {
User {
active: false,
..*user
}
}
Which gives me the error:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:24:11
|
24 | ..*user
| ^^^^^ cannot move out of borrowed content
The funny thing is that it worked for me at some point:
fn reduce<'a>(state: &State<'a>, action: Action) -> Option<State<'a>> {
match action {
Action::LoadRoms { roms } => {
let mut new_state = State { roms, ..*state };
Some(new_state)
}
_ => None,
}
}
From here.
The ..expr syntax moves all the missing member from expr. It moves. That means you generally can't use it with a reference, since you can't move out of a reference (you can "move" Copy types out of a reference though).
To solve you problem, you need to clone, in order to get a new full object you can move from:
fn foo(user: &User) -> User {
User {
active: false,
..user.clone()
}
}
(link to playground)
The downside is that this also clone all members you don't need because you've already specified them. In this case it's fine since cloning active is a trivial operation (as it's just a boolean), however this would make an extra useless clone for username:
fn foo(user: &User) -> User {
User {
username: "foo".into(),
..user.clone()
}
}
This question already has answers here:
Is there any way to return a reference to a variable created in a function?
(5 answers)
Closed 5 years ago.
I am trying to figure out how to declare a variable locally and use it in a value that is being returned. The following is the code that is causing the problem
use std::io;
use std::string::String;
use std::io::Write; // Used for flush implicitly
use topping::Topping;
pub fn read_line(stdin: io::Stdin, prompt: &str) -> String {
print!("{}", prompt);
let _ = io::stdout().flush();
let mut result = String::new();
let _ = stdin.read_line(&mut result);
return result;
}
pub fn handle_topping<'a>(stdin: io::Stdin) -> Topping<'a>{
let name = read_line(stdin, "Topping name: ");
//let price = read_line(stdin, "Price: ");
return Topping {name: &name, price: 0.7, vegetarian: false};
}
I have the following struct as a helper
pub struct Topping<'a> {
pub name: &'a str,
pub vegetarian: bool,
pub price: f32,
}
The compiler throws the following error
error: `name` does not live long enough
--> src/helpers.rs:17:28
|
17 | return Topping {name: &name, price: 0.7, vegetarian: false};
| ^^^^ does not live long enough
18 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the body at 14:58...
--> src/helpers.rs:14:59
|
14 | pub fn handle_topping<'a>(stdin: io::Stdin) -> Topping<'a>{
| ___________________________________________________________^ starting here...
15 | | let name = read_line(stdin, "Topping name: ");
16 | | //let price = read_line(stdin, "Price: ");
17 | | return Topping {name: &name, price: 0.7, vegetarian: false};
18 | | }
| |_^ ...ending here
I don't particularly want to change the struct, would much rather get some advice on what it is that I am not understanding.
Just switch Topping.name from being a &str to being a String.
You can't return a reference to the result of read_line (a String) because that String will get dropped at the end of handle_topping. You can, however, move ownership of the String into the struct and return a Topping {name: String, veg: bool, ...}.