The following is MVP of what I am doing
use std::sync::Arc;
use clokwerk::Interval::*;
use clokwerk::TimeUnits;
use std::time::Duration;
use std::thread;
#[derive(Clone, Debug)]
pub struct Person {
pub name: String,
pub age: u16,
}
pub fn print_debug_person(person_arc: Arc<Person>) {
println!("Person is :{:?}", person_arc)
}
fn main() {
let p = Person { name: "Asnim".to_string(), age: 10 };
let p = Arc::new(p);
let mut scheduler = clokwerk::Scheduler::new();
for loop_period in 1..5 {
let person_arc = p.clone();
scheduler.every(loop_period.seconds()).run(move || print_debug_person(person_arc));
}
loop {
scheduler.run_pending();
thread::sleep(Duration::from_millis(10));
}
}
Here the code fails with error
error[E0507]: cannot move out of `person_arc`, a captured variable in an `FnMut` closure
--> src/main.rs:27:79
|
26 | let person_arc = p.clone();
| ---------- captured outer variable
27 | scheduler.every(loop_period.seconds()).run(move || print_debug_person(person_arc));
| ^^^^^^^^^^ move occurs because `person_arc` has type `Arc<Person>`, which does not implement the `Copy` trait
What am I doing wrong here. What change should I make so that arc can be passed to this function?
Isn't Arc the right structure to use?
I wont able able add Copy trait to the struct as String doesn't implement Copy trait. Right?
Dependencies
clokwerk = "0.3.5"
The function print_debug_person takes ownership of the value given to it, so calling it with person_arc will attempt to move it. However, since the closure is intended to be called multiple times, this would leave the value invalid for future calls.
To fix this, you can either make a new Arc<Person> each time by cloning it:
scheduler.every(loop_period.seconds()).run(move || print_debug_person(person_arc.clone()));
Or, since your function doesn't seem to need ownership, it should just borrow the Person:
pub fn print_debug_person(person: &Person) {
println!("Person is :{:?}", person)
}
Which you can call with a &Arc<Person> due to deref coercion:
scheduler.every(loop_period.seconds()).run(move || print_debug_person(&person_arc));
Related
I think the problem I'm running into with this code is that the struct I'm trying to return has variables that are strings.
Currently I am querying an InfluxDB database and storing the result in the result variable. The print line towards the bottom of my function confirms that the index it correctly and is printing
IotData { time: 2021-12-27T14:01:34.404593Z, device_id: "1000", transaction_date: "27-12-2021", transaction_time: "14:01:34", usage: 8 }
How do I return this struct? I added the Clone attribute to the struct and return the clone since I encountered the has not attribute 'Copy' error, but now I am receiving the error, use of moved value: 'result'. I am new to Rust and don't quite understand ownership. My next guess is that I need to add lifetimes to my function and return the reference instead, but am not sure where to go from here.
Code Dump:
use influxdb::{ Client, ReadQuery};
use chrono::{ Utc };
extern crate serde;
extern crate serde_json;
use serde_derive::{ Serialize, Deserialize };
#[derive(Serialize, Deserialize, Debug, Clone)]
struct IotData {
time: chrono::DateTime<Utc>,
device_id: String,
transaction_date: String,
transaction_time: String,
usage: i64,
}
pub async fn pull(last_time: u64) -> IotData {
let client = Client::new("http://localhost:8086", "PuPPY");
let query_text = format!("
SELECT *
FROM device_data
WHERE time > {}
ORDER BY time
LIMIT 1", last_time);
let read_query = ReadQuery::new(query_text);
let result = client
.json_query(read_query)
.await
.and_then(|mut db_result| db_result.deserialize_next::<IotData>());
println!("{:?}", result.unwrap().series[0].values[0]);
return result.unwrap().series[0].values[0].clone();
}
Minimized example yielding the essentially same error:
pub fn pull<T: std::fmt::Debug>(opt: Option<T>) -> T {
println!("{:?}", opt.unwrap());
opt.unwrap()
}
Playground
The error is this:
error[E0382]: use of moved value: `opt`
--> src/lib.rs:3:5
|
1 | pub fn pull<T: std::fmt::Debug>(opt: Option<T>) -> T {
| --- move occurs because `opt` has type `Option<T>`, which does not implement the `Copy` trait
2 | println!("{:?}", opt.unwrap());
| -------- `opt` moved due to this method call
3 | opt.unwrap()
| ^^^ value used here after move
|
note: this function takes ownership of the receiver `self`, which moves `opt`
help: consider calling `.as_ref()` to borrow the type's contents
|
2 | println!("{:?}", opt.as_ref().unwrap());
| +++++++++
(By the way, if you're reading your errors from IDE, you might not see most of this. That's the general advice: confusing compiler errors in IDE are usually more clear in console, where they are not trimmed)
Here, it's easy to see the issue: Option::unwrap consumes self, since that's the only way for it to yield the owned value. So, then we unwrap the incoming Option to print its contents, we destroy it for good - there's nothing more to return.
To fix it, we can do one of the following:
Just follow the compiler suggestion and add as_ref before first unwrap. In this case, we will consume not the Option<T>, but only the shared reference to it, which can be freely used without touching the value.
Remove the println!, since it seems to be purely debugging information anyway.
Unwrap the Option once, and then use the unwrapped value twice:
pub async fn pull(last_time: u64) -> IotData {
// --snip--
let value = result.unwrap().series[0].values[0];
println!("{:?}", value);
return value;
}
Note also that you don't really need clone in any case - again, Option::unwrap returns an owned value, so you don't have to clone it explicitly.
Running into an ownership issue when attempting to reference multiple values from a HashMap in a struct as parameters in a function call. Here is a PoC of the issue.
use std::collections::HashMap;
struct Resource {
map: HashMap<String, String>,
}
impl Resource {
pub fn new() -> Self {
Resource {
map: HashMap::new(),
}
}
pub fn load(&mut self, key: String) -> &mut String {
self.map.get_mut(&key).unwrap()
}
}
fn main() {
// Initialize struct containing a HashMap.
let mut res = Resource {
map: HashMap::new(),
};
res.map.insert("Item1".to_string(), "Value1".to_string());
res.map.insert("Item2".to_string(), "Value2".to_string());
// This compiles and runs.
let mut value1 = res.load("Item1".to_string());
single_parameter(value1);
let mut value2 = res.load("Item2".to_string());
single_parameter(value2);
// This has ownership issues.
// multi_parameter(value1, value2);
}
fn single_parameter(value: &String) {
println!("{}", *value);
}
fn multi_parameter(value1: &mut String, value2: &mut String) {
println!("{}", *value1);
println!("{}", *value2);
}
Uncommenting multi_parameter results in the following error:
28 | let mut value1 = res.load("Item1".to_string());
| --- first mutable borrow occurs here
29 | single_parameter(value1);
30 | let mut value2 = res.load("Item2".to_string());
| ^^^ second mutable borrow occurs here
...
34 | multi_parameter(value1, value2);
| ------ first borrow later used here
It would technically be possible for me to break up the function calls (using the single_parameter function approach), but it would be more convenient to pass the
variables to a single function call.
For additional context, the actual program where I'm encountering this issue is an SDL2 game where I'm attempting to pass multiple textures into a single function call to be drawn, where the texture data may be modified within the function.
This is currently not possible, without resorting to unsafe code or interior mutability at least. There is no way for the compiler to know if two calls to load will yield mutable references to different data as it cannot always infer the value of the key. In theory, mutably borrowing both res.map["Item1"] and res.map["Item2"] would be fine as they would refer to different values in the map, but there is no way for the compiler to know this at compile time.
The easiest way to do this, as already mentioned, is to use a structure that allows interior mutability, like RefCell, which typically enforces the memory safety rules at run-time before returning a borrow of the wrapped value. You can also work around the borrow checker in this case by dealing with mut pointers in unsafe code:
pub fn load_many<'a, const N: usize>(&'a mut self, keys: [&str; N]) -> [&'a mut String; N] {
// TODO: Assert that keys are distinct, so that we don't return
// multiple references to the same value
keys.map(|key| self.load(key) as *mut _)
.map(|ptr| unsafe { &mut *ptr })
}
Rust Playground
The TODO is important, as this assertion is the only way to ensure that the safety invariant of only having one mutable reference to any value at any time is upheld.
It is, however, almost always better (and easier) to use a known safe interior mutation abstraction like RefCell rather than writing your own unsafe code.
i have the following code snippet which implements some kind of Emitter Struct:
type Callback<'a> = Option<&'a mut dyn FnMut()>;
struct Emitter<'a> {
cb: Callback<'a>
}
impl<'a> Emitter<'a> {
fn emit(&mut self) {
if self.cb.is_some() {
let f = self.cb.unwrap();
f()
}
}
}
fn main() {
let mut cb = || println!("test");
let mut e = Emitter {
cb : Some(&mut cb)
};
e.emit();
}
The emit() function tries to run the saved callback clojure. But i cannot wrap my head around how to run the callback, since the code produces the following error:
--> src/main.rs:11:15
|
11 | let f = self.cb.unwrap();
| ^^^^^^^
| |
| move occurs because `self.cb` has type `Option<&mut dyn FnMut()>`, which does not implement the `Copy` trait
| help: consider borrowing the `Option`'s content: `self.cb.as_ref()`
Appreciate some help :)
Here is the snippet on replit: https://replit.com/#lutzer/RustEmitterTest
What's going on here is that your line
let f = self.cb.unwrap();
would want to move the closure out of the Option enum. This operation consumes that enum, which isn't allowed for things that belong to a struct.
Here is a simpler example to show what I mean:
fn main() {
let an_option = Some(String::from("Woot!");
let the_value = an_option.unwrap();
println!("The value is {}", the_value);
println!("The option is {:?}", an_option); // error here! Can't use an_option any more!!!
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4a4a3660b68ebada99113db5165b6e76
So if you take ownership of something stored inside the Some part of an Option, via unwrap, then the whole Option gets moved out. You can see that in the signature of unwrap:
pub const fn unwrap(self) -> T
Note how it says self, and not &self or &mut self. That means, after calling unwrap, that the enum gets consumed and cannot be used any more, unless the value inside the Some part can simply be copied (If you replace the String in my example with, say, an integer, it will compile without issue).
The comment by Omer Erden then explains a way around that: Ask the Option to give you a mutable reference instead via as_mut.
Or skip all that directly and use the map method of option, which you can use to do something if the option is Some and just not do anything if it's None.
I want to collect changes to a struct and apply them all at once.
The basic outline looks like this:
enum SomeEnum {
Foo,
Bar,
}
struct SomeStruct {
attrib: SomeEnum,
next_attrib: Option<SomeEnum>,
}
impl SomeStruct {
pub fn apply_changes(&mut self) {
if let Some(se) = self.next_attrib {
self.attrib = se;
}
self.next_attrib = None;
}
}
which yields the following compiler error:
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:13:27
|
13 | if let Some(se) = self.next_attrib {
| -- ^^^^ cannot move out of borrowed content
| |
| hint: to prevent move, use `ref se` or `ref mut se`
I found Get an enum field from a struct: cannot move out of borrowed content and added #[derive(Clone, Copy)] to my enum's definition.
This may work but I feel uncomfortable about (implicitly) using copying since this could generally happen to larger datatypes as well.
The actual owner is never moved out of the struct.
Is there another way to accomplish this, without exposing the Copy/Clone traits to all users of the enum?
Essentially, you can't assign the value to self.attrib if it's still owned by self.next_atrrib. That means you need to remove the value from self.next_attrib and then give ownership to self.attrib.
One way to do this would be to manually replace the value. For instance, you could use std::mem::replace to replace the value with None and take ownership of the current value as next_attrib. Then you can take the value and, if it is Some(_), you can place its content in self.attrib.:
impl SomeStruct {
pub fn apply_changes(&mut self) {
let next_attrib = std::mem::replace(&mut self.next_attrib, None);
if let Some(se) = next_attrib {
self.attrib = se;
}
}
}
Since this is a relatively common pattern, however, there is a utility function on Option to handle situations where you'd like to take ownership of the contents of an Option and set the Option to None. The Option::take method is what you want.
impl SomeStruct {
pub fn apply_changes(&mut self) {
if let Some(se) = self.next_attrib.take() {
self.attrib = se;
}
}
}
See also:
How can I swap in a new value for a field in a mutable reference to a structure?
I want my method of struct to perform in a synchronized way. I wanted to do this by using Mutex (Playground):
use std::sync::Mutex;
use std::collections::BTreeMap;
pub struct A {
map: BTreeMap<String, String>,
mutex: Mutex<()>,
}
impl A {
pub fn new() -> A {
A {
map: BTreeMap::new(),
mutex: Mutex::new(()),
}
}
}
impl A {
fn synchronized_call(&mut self) {
let mutex_guard_res = self.mutex.try_lock();
if mutex_guard_res.is_err() {
return
}
let mut _mutex_guard = mutex_guard_res.unwrap(); // safe because of check above
let mut lambda = |text: String| {
let _ = self.map.insert("hello".to_owned(),
"d".to_owned());
};
lambda("dd".to_owned());
}
}
Error message:
error[E0500]: closure requires unique access to `self` but `self.mutex` is already borrowed
--> <anon>:23:26
|
18 | let mutex_guard_res = self.mutex.try_lock();
| ---------- borrow occurs here
...
23 | let mut lambda = |text: String| {
| ^^^^^^^^^^^^^^ closure construction occurs here
24 | if let Some(m) = self.map.get(&text) {
| ---- borrow occurs due to use of `self` in closure
...
31 | }
| - borrow ends here
As I understand when we borrow anything from the struct we are unable to use other struct's fields till our borrow is finished. But how can I do method synchronization then?
The closure needs a mutable reference to the self.map in order to insert something into it. But closure capturing works with whole bindings only. This means, that if you say self.map, the closure attempts to capture self, not self.map. And self can't be mutably borrowed/captured, because parts of self are already immutably borrowed.
We can solve this closure-capturing problem by introducing a new binding for the map alone such that the closure is able to capture it (Playground):
let mm = &mut self.map;
let mut lambda = |text: String| {
let _ = mm.insert("hello".to_owned(), text);
};
lambda("dd".to_owned());
However, there is something you overlooked: since synchronized_call() accepts &mut self, you don't need the mutex! Why? Mutable references are also called exclusive references, because the compiler can assure at compile time that there is only one such mutable reference at any given time.
Therefore you statically know, that there is at most one instance of synchronized_call() running on one specific object at any given time, if the function is not recursive (calls itself).
If you have mutable access to a mutex, you know that the mutex is unlocked. See the Mutex::get_mut() method for more explanation. Isn't that amazing?
Rust mutexes do not work the way you are trying to use them. In Rust, a mutex protects specific data relying on the borrow-checking mechanism used elsewhere in the language. As a consequence, declaring a field Mutex<()> doesn't make sense, because it is protecting read-write access to the () unit object that has no values to mutate.
As Lukas explained, your call_synchronized as declared doesn't need to do synchronization because its signature already requests an exclusive (mutable) reference to self, which prevents it from being invoked from multiple threads on the same object. In other words, you need to change the signature of call_synchronized because the current one does not match the functionality it is intended to provide.
call_synchronized needs to accept a shared reference to self, which will signal to Rust that it can be called from multiple threads in the first place. Inside call_synchronized a call to Mutex::lock will simultaneously lock the mutex and provide a mutable reference to the underlying data, carefully scoped so that the lock is held for the duration of the reference:
use std::sync::Mutex;
use std::collections::BTreeMap;
pub struct A {
synced_map: Mutex<BTreeMap<String, String>>,
}
impl A {
pub fn new() -> A {
A {
synced_map: Mutex::new(BTreeMap::new()),
}
}
}
impl A {
fn synchronized_call(&self) {
let mut map = self.synced_map.lock().unwrap();
// omitting the lambda for brevity, but it would also work
// (as long as it refers to map rather than self.map)
map.insert("hello".to_owned(), "d".to_owned());
}
}