How to return struct in Rust without 'use of moved value' error? - struct

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.

Related

How to pass argument to the functions called using clokwerk library

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));

Rust 'use of moved value' error when passing value into Enum variant

I am very new to Rust (just a couple of days). Of course, I am already getting stuck with the concept of ownership.
I have a rather lengthy problem, so here are all the relevant declarations I used:
pub struct ThePrimaryStruct<'a> {
frames: Vec<Frame<'a>>,
stack: Vec<Object<'a>>,
ip: usize
}
pub struct FunctionObject<'a> {
pub min_arity: i32,
pub max_arity: i32,
pub chunk: Chunk<'a>,
pub name: &'a str,
}
pub struct Frame<'a> {
pub function: FunctionObject<'a>,
// ... other struct members
}
pub struct Chunk<'a> {
pub codes: Vec<OpCode>, // OpCode is an enum
pub locations: Vec<(i64, i64)>,
pub constants: Vec<Object<'a>>
}
pub enum Object<'a> {
Function(FunctionObject<'a>),
// Other enum variants
}
The above code is not the problem. The problem arises when I implement the following method for ThePrimaryStruct:
pub(crate) fn the_function(&mut self, source: &'a str) -> SomeResult {
// `Compiler::compile()` returns a FunctionObject struct.
let func: FunctionObject = Compiler::compile(source);
// The enum variant `Object::Function` takes ownership of `func`
// The code works fine up until this point.
self.stack.push(Object::Function(func));
self.frames.push(Frame {
// The struct member `function` should have the
// exact same value as the one we just pushed into
// the `self.stack` vector.
function: func, // <---- Source of conflict
// ... other struct members
});
self.run() // self.run() returns `SomeResult`
}
Running this results in the error:
error[E0382]: use of moved value: `func`
|
37 | let func: FunctionObject = Compiler::compile(source);
| ---- move occurs because `func` has type `FunctionObject<'_>`, which does not implement the `Copy` trait
...
40 | self.stack.push(Object::Function(func));
| ---- value moved here
...
44 | function: func,
| ^^^^ value used here after move
I understand why this error occurs (or at least I think I understand): The Object::Function variant takes ownership of func, which is then dropped from memory when we are done pushing the object into self.stack. This then creates a conflict with the initialization of the Frame struct because I am trying to use a value that no longer exists.
I have tried implementing the Copy trait for the struct FunctionObject, but that creates even more problems because FunctionObject has a member of type Chunk<'a> which itself has vector members.
EDIT:
Cloning definitely solves the problem. However, by cloning the FunctionObject I would be duplicating the data inside the chunk which could be of an arbitrarily long size. Referencing the FunctionObject in both the stack with Object::Function(&func) and in the frame with Frame { function: &func, ... } then results in a 'func' does not live long enough error.
Is there something fundamentally wrong with what I am trying to do?
You seem to have a FunctionObject that you want to store both in stack and frame.
A better solution might be to not store the FunctionObject directly on the stack and frame, but use smart pointers instead.
I will show you a solution using Rc, however, you seem to be making a compiler, so you might want a different data structure to store your function objects in, like an arena.
The following code includes only the changes I made to your original, but you can also have a look on the playground where I got it to compile:
pub struct Frame<'a> {
pub function: std::rc::Rc<FunctionObject<'a>>,
// ... other struct members
}
pub enum Object<'a> {
Function(std::rc::Rc<FunctionObject<'a>>),
// Other enum variants
}
pub(crate) fn the_function(&mut self, source: &'a str) -> SomeResult {
// `Compiler::compile()` returns a FunctionObject struct.
let func: FunctionObject = Compiler::compile(source);
let func = std::rc::Rc::new(func);
// The enum variant `Object::Function` takes ownership of `func`
// The code works fine up until this point.
self.stack.push(Object::Function(func.clone()));
self.frames.push(Frame {
// The struct member `function` should have the
// exact same value as the one we just pushed into
// the `self.stack` vector.
function: func, // <---- No longer source of conflict
// ... other struct members
});
self.run() // self.run() returns `SomeResult`
}
Rc manages an object by reference counting.
When the last Rc is dropped, the value (FunctionObject) will also be dropped.
Using .clone() on func makes a copy of the reference and increments the count, but doesn't copy the underlying object.

How to fix ".. was mutably borrowed here in the previous iteration of the loop" in Rust?

I have to iterate on keys, find the value in HashMap by key, possibly do some heavy computation in the found struct as a value (lazy => mutate the struct) and cached return it in Rust.
I'm getting the following error message:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:25:26
|
23 | fn it(&mut self) -> Option<&Box<Calculation>> {
| - let's call the lifetime of this reference `'1`
24 | for key in vec!["1","2","3"] {
25 | let result = self.find(&key.to_owned());
| ^^^^ `*self` was mutably borrowed here in the previous iteration of the loop
...
28 | return result
| ------ returning this value requires that `*self` is borrowed for `'1`
Here is the code in playground.
use std::collections::HashMap;
struct Calculation {
value: Option<i32>
}
struct Struct {
items: HashMap<String, Box<Calculation>> // cache
}
impl Struct {
fn find(&mut self, key: &String) -> Option<&Box<Calculation>> {
None // find, create, and/or calculate items
}
fn it(&mut self) -> Option<&Box<Calculation>> {
for key in vec!["1","2","3"] {
let result = self.find(&key.to_owned());
if result.is_some() {
return result
}
}
None
}
}
I can't avoid the loop as I have to check multiple keys
I have to make it mutable (self and the structure) as the possible calculation changes it
Any suggestion on how to change the design (as Rust forces to think in a bit different way that makes sense) or work around it?
PS. There are some other issues with the code, but let's split the problems and solve this one first.
You can't do caching with exclusive access. You can't treat Rust references like general-purpose pointers (BTW: &String and &Box<T> are double indirection, and very unidiomatic in Rust. Use &str or &T for temporary borrows).
&mut self means not just mutable, but exclusive and mutable, so your cache supports returning only one item, because the reference it returns has to keep self "locked" for as long as it exists.
You need to convince the borrow checker that the thing that find returns won't suddenly disappear next time you call it. Currently there's no such guarantee, because the interface doesn't stop you from calling e.g. items.clear() (borrow checker checks what function's interface allows, not what function actually does).
You can do that either by using Rc, or using a crate that implements a memory pool/arena.
struct Struct {
items: HashMap<String, Rc<Calculation>>,
}
fn find(&mut self, key: &str) -> Rc<Calculation>
This way if you clone the Rc, it will live for as long as it needs, independently of the cache.
You can also make it nicer with interior mutability.
struct Struct {
items: RefCell<HashMap<…
}
This will allow your memoizing find method to use a shared borrow instead of an exclusive one:
fn find(&self, key: &str) -> …
which is much easier to work with for the callers of the method.
Probably not the cleanest way to do that, but it compiles. The idea is not to store the value found in a temporary result, to avoid aliasing: if you store the result, self is kept borrowed.
impl Struct {
fn find(&mut self, key: &String) -> Option<&Box<Calculation>> {
None
}
fn it(&mut self) -> Option<&Box<Calculation>> {
for key in vec!["1","2","3"] {
if self.find(&key.to_owned()).is_some() {
return self.find(&key.to_owned());
}
}
None
}
}
I had similar issues, and I found a workaround by turning the for loop into a fold, which convinced the compiler that self was not mutably borrowed twice.
It works without using interior mutability or duplicated function call; the only downside is that if the result was found early, it will not short-circuit but continue iterating until the end.
Before:
for key in vec!["1","2","3"] {
let result = self.find(&key.to_owned());
if result.is_some() {
return result
}
}
After:
vec!["1", "2,", "3"]
.iter()
.fold(None, |result, key| match result {
Some(result) => Some(result),
None => self.find(&key.to_string())
})
Working playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=92bc73e4bac556ce163e0790c7d3f154

Return Ref to something inside of Rc<RefCell<>> without Ref::map

Working code first:
use std::cell::{Ref, RefCell};
use std::rc::Rc;
struct ValueHolder {
value: i32
}
fn give_value(wrapped: &Rc<RefCell<ValueHolder>>) -> Ref<i32> {
Ref::map(
(**wrapped).borrow(),
|borrowed| { &(*borrowed).value },
)
}
fn main() {
println!("Our value: {}", *give_value(
&Rc::new(RefCell::new(ValueHolder { value: 1337 }))
));
}
The relevant part is the give_value function.
I want to return a Ref to something inside a Rc<RefCell<>>, in this case a value inside of a struct.
That works just fine, but since I just started to learn Rust, I wonder, how I could achieve the same thing without using Ref::map.
The "naive" approach:
fn give_value(wrapped: &Rc<RefCell<ValueHolder>>) -> &i32 {
&(*(**wrapped).borrow()).value
}
fails for obvious reasons:
error[E0515]: cannot return value referencing temporary value
--> src/bin/rust_example.rs:9:5
|
9 | &(*(**wrapped).borrow()).value
| ^^^--------------------^^^^^^^
| | |
| | temporary value created here
| returns a value referencing data owned by the current function
So my question is: How can I recreate what the Ref::map function does by myself?
You can't. RefCell requires that Ref be used whenever the value is used, so it knows when it should allow a borrow. When the Ref gets dropped, it signals to the RefCell that it can decrease the borrow count, and if the borrow count is 0, then a mutable borrow can happen. Being able to obtain a reference to the internal data that doesn't borrow the Ref (note that a reference you can return from a function cannot borrow the Ref otherwise you'd be referencing a temporary) would be problematic, because then the Ref could get dropped and the RefCell thinks that it can lend out a mutable borrow, but there's still an immutable borrow to the data. The source code for Ref::map is:
pub fn map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Ref<'b, U>
where
F: FnOnce(&T) -> &U,
{
Ref { value: f(orig.value), borrow: orig.borrow }
}
which uses private fields that you can't access. So, no, you cannot recreate Ref::map yourself.

Use regular reference instead of `Box` in recursive data structures

I am new to Rust. When I read chapter 15 of The Rust Programming Language, I failed to know why one should use Boxes in recursive data structures instead of regular references. 15.1 of the book explains that indirection is required to avoid infinite-sized structures, but it does not explain why to use Box.
#[derive(Debug)]
enum FunctionalList<'a> {
Cons(u32, &'a FunctionalList<'a>),
Nil,
}
use FunctionalList::{Cons, Nil};
fn main() {
let list = Cons(1, &Cons(2, &Cons(3, &Nil)));
println!("{:?}", list);
}
The code above compiles and produces the desired output. It seems that using FunctionalList to store a small amount of data on stack works perfectly well. Does this code cause troubles?
It is true that the FunctionalList works in this simple case. However, we will run into some difficulties if we try to use this structure in other ways. For instance, suppose we tried to construct a FunctionalList and then return it from a function:
#[derive(Debug)]
enum FunctionalList<'a> {
Cons(u32, &'a FunctionalList<'a>),
Nil,
}
use FunctionalList::{Cons, Nil};
fn make_list(x: u32) -> FunctionalList {
return Cons(x, &Cons(x + 1, &Cons(x + 2, &Nil)));
}
fn main() {
let list = make_list(1);
println!("{:?}", list);
}
This results in the following compile error:
error[E0106]: missing lifetime specifier
--> src/main.rs:9:25
|
9 | fn make_list(x: u32) -> FunctionalList {
| ^^^^^^^^^^^^^^ help: consider giving it an explicit bounded or 'static lifetime: `FunctionalList + 'static`
If we follow the hint and add a 'static lifetime, then we instead get this error:
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:10:12
|
10 | return Cons(x, &Cons(x + 1, &Cons(x + 2, &Nil)));
| ^^^^^^^^^^^^^^^^^^^^^^-----------------^^
| | |
| | temporary value created here
| returns a value referencing data owned by the current function
The issue is that the inner FunctionalList values here are owned by implicit temporary variables whose scope ends at the end of the make_list function. These values would thus be dropped at the end of the function, leaving dangling references to them, which Rust disallows, hence the borrow checker rejects this code.
In contrast, if FunctionalList had been defined to Box its FunctionalList component, then ownership would have been moved from the temporary value into the containing FunctionalList, and we would have been able to return it without any problem.
With your original FunctionalList, the thing we have to think about is that every value in Rust has to have an owner somewhere; and so if, as in this case, the FunctionaList is not the owner of its inner FunctionalLists, then that ownership has to reside somewhere else. In your example, that owner was an implicit temporary variable, but in more complex situations we could use a different kind of external owner. Here's an example of using a TypedArena (from the typed-arena crate) to own the data, so that we can still implement a variation of the make_list function:
use typed_arena::Arena;
#[derive(Debug)]
enum FunctionalList<'a> {
Cons(u32, &'a FunctionalList<'a>),
Nil,
}
use FunctionalList::{Cons, Nil};
fn make_list<'a>(x: u32, arena: &'a Arena<FunctionalList<'a>>) -> &mut FunctionalList<'a> {
let l0 = arena.alloc(Nil);
let l1 = arena.alloc(Cons(x + 2, l0));
let l2 = arena.alloc(Cons(x + 1, l1));
let l3 = arena.alloc(Cons(x, l2));
return l3;
}
fn main() {
let arena = Arena::new();
let list = make_list(1, &arena);
println!("{:?}", list);
}
In this case, we adapted the return type of make_list to return only a mutable reference to a FunctionalList, instead of returning an owned FunctionalList, since now the ownership resides in the arena.

Resources