This snippet of code:
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap;
fn main() {
let mut vars = HashMap::<i32, f64>::new();
let key = 10;
let val = match vars.entry(key) {
Vacant(entry) => entry.set(0.0),
Occupied(entry) => entry.into_mut(),
};
*val += 3.4;
println!("{}", val);
}
Gives this error:
error[E0599]: no method named `set` found for type `std::collections::hash_map::VacantEntry<'_, i32, f64>` in the current scope
--> src/main.rs:8:32
|
8 | Vacant(entry) => entry.set(0.0),
| ^^^
VacantEntry doesn't implement any method named set, but there is a method named insert:
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap;
fn main() {
let mut vars = HashMap::<i32, f64>::new();
let key = 10;
// vars.insert(key, 25.0);
let val = match vars.entry(key) {
Vacant(entry) => entry.insert(0.0),
Occupied(entry) => entry.into_mut(),
};
*val += 3.4;
println!("{}", val);
}
(playground)
Related
I have the following code:
use std::collections::HashMap;
type Elem = i64;
enum Op {
Num(Elem),
Add((String, String)),
}
type Statements = HashMap<String, Op>;
fn main() {
let mut statements = Statements::new();
statements.insert("lhs".to_string(), Op::Num(64));
statements.insert("op".to_string(), Op::Add(("lhs".to_string(), "rhs".to_string())));
statements.insert("rhs".to_string(), Op::Num(64));
let mut stack = Vec::new();
let mut op_name = "op";
loop {
let result: Elem;
match statements.get(op_name).unwrap() {
Op::Num(_) => {
panic!("{}: Did not expect Num", op_name);
},
Op::Add((lhs, rhs)) => {
if let Op::Num(lhs_value) = statements.get(lhs).unwrap() {
if let Op::Num(rhs_value) = statements.get(rhs).unwrap() {
result = lhs_value + rhs_value;
} else {
stack.push(op_name);
op_name = rhs;
continue;
}
} else {
stack.push(op_name);
op_name = lhs;
continue;
}
},
};
if let Some(new_op_name) = stack.pop() {
*(statements.get_mut(op_name).unwrap()) = Op::Num(result);
op_name = new_op_name;
} else {
println!("Result: {}", result);
return;
}
}
}
which gives me the following compiler error:
error[E0502]: cannot borrow `statements` as mutable because it is also borrowed as immutable
--> minimal.rs:43:15
|
22 | match statements.get(op_name).unwrap() {
| ----------------------- immutable borrow occurs here
...
43 | *(statements.get_mut(op_name).unwrap()) = Op::Num(result);
| ^^^^^^^^^^^-------^^^^^^^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0502`.
I was expecting the borrowing to end with the match statement, since I do not see how I could still access the result of the borrowing after this statement. Why is the value still being borrowed after the match statement?
Is there something I could do to make my code above work?
In my opinion you'll find it difficult to work with strings and strings references. I would rather switch to some type for your HashMap keys that would be small, and copyable, like an integer number. This way you'll not be required to deal with references and mutability - you can just copy your integers with little to no cost.
I resolved your compilation errors, but the overall code becomes more convoluted. Basically now each insert into the hash map will give you a unique integer ID of the operation. You can only query operations from the hash map using this provided ID. It also requires you to push statements in your hash map in the order of appearance. You can't insert add(lhs, rhs) unless you already know IDs of both lhs and rhs
use std::collections::HashMap;
type Elem = i64;
type StatementId = usize;
enum Op {
Num(Elem),
Add((StatementId, StatementId)),
}
#[derive(Default)]
struct StatementsRecord {
record: HashMap<StatementId, (String, Op)>,
next_statement_id: StatementId,
}
impl StatementsRecord {
fn insert(&mut self, name: String, operation: Op) -> StatementId {
self.record.insert(self.next_statement_id, (name, operation));
self.next_statement_id += 1;
self.next_statement_id - 1 // return id of newly stored operation
}
fn get(&self, id: &StatementId) -> Option<&(String, Op)> {
self.record.get(id)
}
fn get_mut(&mut self, id: &StatementId) -> Option<&mut (String, Op)> {
self.record.get_mut(id)
}
fn update(&mut self, id: &StatementId, value: Op) {
self.get_mut(id).unwrap().1 = value;
}
}
fn main() {
let mut statements = StatementsRecord::default();
let lhs_id = statements.insert("lhs".to_string(), Op::Num(64));
let rhs_id = statements.insert("rhs".to_string(), Op::Num(64));
// 64+64 = 128
let mut op_id = statements.insert("op".to_string(), Op::Add((lhs_id, rhs_id)));
// (64+64) + (64+64) = 256
let mut op_id = statements.insert("op".to_string(), Op::Add((op_id, op_id)));
let mut stack = Vec::new();
loop {
let result: Elem;
match statements.get(&op_id).unwrap() {
(op_name, Op::Num(_)) => {
panic!("{}: Did not expect Num", op_name);
},
(op_name, Op::Add((lhs, rhs))) => {
if let (_, Op::Num(lhs_value)) = statements.get(lhs).unwrap() {
if let (_, Op::Num(rhs_value)) = statements.get(rhs).unwrap() {
result = lhs_value + rhs_value;
} else {
stack.push(op_id);
op_id = *rhs;
continue;
}
} else {
stack.push(op_id);
op_id = *lhs;
continue;
}
},
};
if let Some(new_op_id) = stack.pop() {
statements.update(&op_id, Op::Num(result));
op_id = new_op_id;
} else {
println!("Result: {}", result);
return;
}
}
}
Prints
Result: 256
I'm trying to solve the RPN calculator exercise at exercism but stumbled upon this temporary value dropped while borrowed error that I can't seem to work out.
Here's my code:
#[derive(Debug)]
pub enum CalculatorInput {
Add,
Subtract,
Multiply,
Divide,
Value(i32),
}
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack = Vec::new();
for input in inputs {
match input {
CalculatorInput::Value(value) => {
stack.push(value);
},
operator => {
if stack.len() < 2 {
return None;
}
let second = stack.pop().unwrap();
let first = stack.pop().unwrap();
let result = match operator {
CalculatorInput::Add => first + second,
CalculatorInput::Subtract => first - second,
CalculatorInput::Multiply => first * second,
CalculatorInput::Divide => first / second,
CalculatorInput::Value(_) => return None,
};
stack.push(&result.clone());
}
}
}
if stack.len() != 1 {
None
} else {
Some(*stack.pop().unwrap())
}
}
And the error I get:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:32:29
|
32 | stack.push(&result.clone());
| ^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
...
36 | if stack.len() != 1 {
| ----- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
If I understand correctly, the variable result is no loger live outside of the for loop (outside of the operator match branch indeed), that's why I cloned it, but it still gives me the same error.
How can I make a copy of the result which is owned by the stack Vec (if that's what I should do)?
Just for reference, and in case anybody fins this useful, this is the final solution taking into account all the help received:
use crate::CalculatorInput::{Add,Subtract,Multiply,Divide,Value};
#[derive(Debug)]
pub enum CalculatorInput {
Add,
Subtract,
Multiply,
Divide,
Value(i32),
}
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack: Vec<i32> = Vec::new();
for input in inputs {
match input {
Value(value) => {
stack.push(*value);
},
operator => {
if stack.len() < 2 {
return None;
}
let second: i32 = stack.pop().unwrap();
let first: i32 = stack.pop().unwrap();
let result: i32 = match operator {
Add => first + second,
Subtract => first - second,
Multiply => first * second,
Divide => first / second,
Value(_) => return None,
};
stack.push(result);
}
}
}
if stack.len() != 1 {
None
} else {
stack.pop()
}
}
No need to clone, because i32 implements the Copy trait.
The problem was that my vec was receiving an &i32 instead of i32, and thus rust infered it to be a Vec<&i32>.
The error is because Rust did not infer the type you expected.
In your code, the type of value is inferred to be &i32 because input is a reference of a element in inputs, and you push a value later, therefore the type of stack is inferred to be Vec<&i32>.
A best fix is to explicitly specify the type of stack:
let mut stack: Vec<i32> = Vec::new();
And because i32 has implemented Copy trait, you should never need to clone a i32 value, if it is a reference, just dereference it.
Fixed code:
#[derive(Debug)]
pub enum CalculatorInput {
Add,
Subtract,
Multiply,
Divide,
Value(i32),
}
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack: Vec<i32> = Vec::new();
for input in inputs {
match input {
CalculatorInput::Value(value) => {
stack.push(*value);
}
operator => {
if stack.len() < 2 {
return None;
}
let second = stack.pop().unwrap();
let first = stack.pop().unwrap();
let result = match operator {
CalculatorInput::Add => first + second,
CalculatorInput::Subtract => first - second,
CalculatorInput::Multiply => first * second,
CalculatorInput::Divide => first / second,
CalculatorInput::Value(_) => return None,
};
stack.push(result);
}
}
}
if stack.len() != 1 {
None
} else {
Some(stack.pop().unwrap())
}
}
You have the same behavior with this simple exemple
fn main() {
let mut stack = Vec::new();
let a = String::from("test");
stack.push(&a.clone());
//-------- ^
println!("{:?}", stack);
}
and the good way is to not borrow when clone.
fn main() {
let mut stack = Vec::new();
let a = String::from("test");
stack.push(a.clone());
//-------- ^
println!("{:?}", stack);
}
The variable should be used like this stack.push(result.clone()); and change code like this
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack: Vec<i32> = Vec::new();
//---------------- ^
for input in inputs {
match input {
CalculatorInput::Value(value) => {
stack.push(value.clone());
//----------------- ^
},
operator => {
if stack.len() < 2 {
return None;
}
let second = stack.pop().unwrap();
let first = stack.pop().unwrap();
let result = match operator {
CalculatorInput::Add => first + second,
CalculatorInput::Subtract => first - second,
CalculatorInput::Multiply => first * second,
CalculatorInput::Divide => first / second,
CalculatorInput::Value(_) => return None,
};
stack.push(result.clone());
//-^
}
}
}
if stack.len() != 1 {
None
} else {
Some(stack.pop().unwrap())
//------- ^
}
}
We all know that using global variables can lead to subtle bugs. I need to migrate Python programs to Rust, keeping the algorithm intact as far as possible. Once I have demonstrated Python-Rust equivalence there will be opportunities to debug and change the logic to fit Rust better. Here is a simple Python program using global variables, followed by my unsuccessful Rust version.
# global variable
a = 15
# function to perform addition
def add():
global a
a += 100
# function to perform subtraction
def subtract():
global a
a -= 100
# Using a global through functions
print("Initial value of a = ", a)
add()
print("a after addition = ", a)
subtract()
print("a after subtraction = ", a)
Here is a Rust program that runs, but I cannot get the closures to update the so-called global variable.
fn fmain() {
// global variable
let mut a = 15;
// perform addition
let add = || {
let mut _name = a;
// name += 100; // the program won't compile if this is uncommented
};
call_once(add);
// perform subtraction
let subtract = || {
let mut _name = a;
// name -= 100; // the program won't compile if this is uncommented
};
call_once(subtract);
// Using a global through functions
println!("Initial value of a = {}", a);
add();
println!("a after addition = {}", a);
subtract();
println!("a after subtraction = {}", a);
}
fn main() {
fmain();
}
fn call_once<F>(f: F)
where
F: FnOnce(),
{
f();
}
My request: Re-create the Python logic in Rust.
Your Rust code is not using global variables, the a variable is stack-allocated. While Rust doesn't particularly endorse global variables, you can certainly use them. Translated to Rust that uses actual globals, your program would look like this:
use lazy_static::lazy_static;
use parking_lot::Mutex; // or std::sync::Mutex
// global variable
lazy_static! {
static ref A: Mutex<u32> = Mutex::new(15);
}
// function to perform addition
fn add() {
*A.lock() += 100;
}
// function to perform subtraction
fn subtract() {
*A.lock() -= 100;
}
fn main() {
// Using a global through functions
println!("Initial value of a = {}", A.lock());
add();
println!("a after addition = {}", A.lock());
subtract();
println!("a after subtraction = {}", A.lock());
}
Playground
If you prefer to use closures, you can do that too, but you'll need to use interior mutability to allow multiple closures to capture the same environment. For example, you could use a Cell:
use std::cell::Cell;
fn main() {
let a = Cell::new(15);
let add = || {
a.set(a.get() + 100);
};
let subtract = || {
a.set(a.get() - 100);
};
// Using a global through functions
println!("Initial value of a = {}", a.get());
add();
println!("a after addition = {}", a.get());
subtract();
println!("a after subtraction = {}", a.get());
}
Playground
Dependency-less examples as enum and function. EDIT : Code improved, as suggested in comment and corrected match arm.
use std::sync::{Arc, Mutex, Once};
static START: Once = Once::new();
static mut ARCMUT: Vec<Arc<Mutex<i32>>> = Vec::new();
// as enum
enum Operation {
Add,
Subtract,
}
impl Operation {
// static change
fn result(self) -> i32 {
let mut arc_clone = unsafe { ARCMUT[0].clone() };
let mut unlock = arc_clone.lock().unwrap();
match self {
Operation::Add => *unlock += 100,
Operation::Subtract => *unlock -= 100,
}
*unlock
}
// dynamic change
fn amount(self, amount: i32) -> i32 {
let mut arc_clone = unsafe { ARCMUT[0].clone() };
let mut unlock = arc_clone.lock().unwrap();
match self {
Operation::Add => *unlock += amount,
Operation::Subtract => *unlock -= amount,
}
*unlock
}
}
// as a function
fn add() -> i32 {
let mut arc_clone = unsafe { ARCMUT[0].clone() };
let mut unlcok = arc_clone.lock().unwrap();
*unlcok += 100;
*unlcok
}
// as trait
trait OperationTrait {
fn add(self) -> Self;
fn subtract(self) -> Self;
fn return_value(self) ->i32;
}
impl OperationTrait for i32 {
fn add(mut self) -> Self {
let arc_clone = unsafe{ARCMUT[0].clone()};
let mut unlock = arc_clone.lock().unwrap();
*unlock += self;
self
}
fn subtract(mut self) -> Self {
let arc_clone = unsafe{ARCMUT[0].clone()};
let mut unlock = arc_clone.lock().unwrap();
*unlock -= self;
self
}
fn return_value(self)->Self{
let arc_clone = unsafe{ARCMUT[0].clone()};
let mut unlock = arc_clone.lock().unwrap();
*unlock
}
}
// fn main
fn main() {
START.call_once(|| unsafe {
ARCMUT = vec![Arc::new(Mutex::new(15))];
});
let test = Operation::Add.result();
println!("{:?}", test);
let test = Operation::Subtract.amount(100);
println!("{:?}", test);
let test = add();
println!("{:?}", test);
let test = 4000.add();
println!("{:?}", test);
}
Here is my simplified code. I need to change the pdp_state in a function. but the state remain 'a'. I don't figure out why cloning Rc does not work. I also checked this cloning out side a structure an it worked.
#[derive(Clone,Copy)]
enum PDPStatus{
a,
b
}
struct network{
pdp_state:Rc<RefCell<PDPStatus>>,
}
impl network{
fn set(&mut self){
let mut t = *self.pdp_state.clone().borrow_mut();
match t {
a => {let m1 = self.pdp_state.clone();
let mut a = (*m1).borrow_mut() ;
*a = PDPStatus::b;
println!("a");},
b=> {let m1 = self.pdp_state.clone();m1.replace( PDPStatus::a);
println!("b");},
};
}
}
fn main() {
let mut network1 = network::new();
network1.set();
network1.set();
network1.set();
network1.set();
}
Update:
My set function would look like this. I need two closure that have access to pdp_state. I pass these closures as callbacks. I am sure the these closure wouldn't call together.
fn set(&mut self){
let borrowed_pdp_status = self.pdp_state.borrow().clone();
match borrowed_pdp_status {
PDPStatus::a => {
let mut state = self.pdp_state.clone();
let mut closuree = || state = Rc::new(RefCell::new(PDPStatus::b));
let mut state1 = self.pdp_state.clone();
let mut closuree1 = || state1 = Rc::new(RefCell::new(PDPStatus::b));
closuree();
closuree1();
println!("a");
},
PDPStatus::b => {
let mut closuree = || self.pdp_state = Rc::new(RefCell::new(PDPStatus::a));
closuree();
println!("b");
},
};
}
In the set method, you need to borrow self.pdp_state and then clone() it in a variable, and then match the variable where you cloned it.
Replace the set method with this:
fn set(&mut self) {
let borrowed_pdp_status = self.pdp_state.borrow().clone();
match borrowed_pdp_status {
PDPStatus::a => {
self.pdp_state = Rc::new(RefCell::new(PDPStatus::b));
println!("a");
},
PDPStatus::b => {
self.pdp_state = Rc::new(RefCell::new(PDPStatus::a));
println!("b");
},
};
}
Playground link - https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=426d4cb7db9a92ee4ddcd4f36dbc12f7
This answer was posted after the question was updated:
EDIT
You can use the replace() method from RefCell
fn set(&mut self) {
let borrowed_pdp_status = self.pdp_state.borrow().clone();
match borrowed_pdp_status {
PDPStatus::a => {
let mut closuree = || {
self.pdp_state.replace(PDPStatus::b);
};
let mut closuree1 = || {
self.pdp_state.replace(PDPStatus::b);
};
closuree();
closuree1();
println!("a");
}
PDPStatus::b => {
let mut closuree = || {
self.pdp_state.replace(PDPStatus::a);
};
closuree();
println!("b");
}
};
}
Playground link - https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=4af02228d58b2f2c865a525e3f70d6a0
OLD
You could just make the closures take &mut self.pdp_state as an argument, and then update it.
fn set(&mut self) {
let borrowed_pdp_status = self.pdp_state.borrow().clone();
match borrowed_pdp_status {
PDPStatus::a => {
let mut closuree = |local_pdp_state: &mut Rc<RefCell<PDPStatus>>| {
*local_pdp_state = Rc::new(RefCell::new(PDPStatus::b))
};
let mut closuree1 = |local_pdp_state: &mut Rc<RefCell<PDPStatus>>| {
*local_pdp_state = Rc::new(RefCell::new(PDPStatus::b))
};
closuree(&mut self.pdp_state);
closuree1(&mut self.pdp_state);
println!("a");
}
PDPStatus::b => {
let mut closuree = |local_pdp_state: &mut Rc<RefCell<PDPStatus>>| {
*local_pdp_state = Rc::new(RefCell::new(PDPStatus::a))
};
closuree(&mut self.pdp_state);
println!("b");
}
};
}
Playground link - https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=4af96385b0446082afdb7d615bb8eecb
I'm trying to call a Dyon built-in function (sin) from Rust:
use dyon::{Module, Runtime, Variable};
use std::sync::Arc;
fn main() {
let mut dyon_runtime = Runtime::new();
let module = Module::new();
let dyon_module = Arc::new(module);
let v = dyon_runtime.call_str_ret("sin", &[Variable::f64(0.0)], &dyon_module);
match v {
Err(e) => {
eprintln!("Error: {:?}", e);
}
Ok(v) => {
println!("Called sin - result {:?}", v);
}
};
}
However, I get
Error: "Could not find function `sin`"
What do I need to do to correctly call this function?
I can't explain the design decisions here, but call_str_ret only handles functions that have been loaded, not external functions or intrinsics.
As a workaround, you can load a little shim function that just calls off to the appropriate function:
use dyon::{Module, Runtime, Variable};
use std::sync::Arc;
fn main() {
let mut dyon_runtime = Runtime::new();
let mut module = Module::new();
let shim = Arc::new("do_it(x) = sin(x)".into());
dyon::load_str("main.rs", shim, &mut module).expect("Unable to load shim function");
let dyon_module = Arc::new(module);
let v = dyon_runtime.call_str_ret("do_it", &[Variable::f64(90.0)], &dyon_module);
match v {
Err(e) => {
eprintln!("Error: {:?}", e);
}
Ok(v) => {
println!("Called sin - result {:?}", v);
}
};
}
Called sin - result F64(0.8939966636005579, None)
call_str() only cares about one type of function call. I don't know why they do this, but one solution would be to do it yourself:
use dyon::{ast, Module, Runtime, Variable};
use range::Range;
use std::cell::Cell;
use std::sync::Arc;
fn main() {
let mut dyon_runtime = Runtime::new();
let module = Module::new();
let name: Arc<String> = Arc::new("sin".into());
let f_index = Cell::new(module.find_function(&name, 0));
let args = vec![ast::Expression::Variable(Box::new((
Range::empty(0),
Variable::F64(1.0, None),
)))];
let call = ast::Call {
alias: None,
name,
f_index,
args,
custom_source: None,
source_range: Range::empty(0),
};
let dyon_module = Arc::new(module);
println!("{:?}", dyon_runtime.call(&call, &dyon_module));
}
Both of the other answers led me to a solution that works cleanly for both cases:
I took the Runtime.call_str_ret and modified it to use any non-None result from module.find_function. IMO the code is actually cleaner than the original version in Runtime. I've submitted a PR for this which has been merged, so releases of Dyon after 0.40.0 will have call_str_ret working for built-in functions.
If you can't use a more recent version of Dyon, then you could manually apply the patch from here: https://github.com/PistonDevelopers/dyon/pull/582.
Or alternatively you could use your own version of call_str_ret, like this:
use dyon::{Module, Runtime, Variable};
use std::sync::Arc;
extern crate range;
/// Call function by name, returning a value.
pub fn call_str_ret_ex(
runtime:&mut Runtime,
function: &str,
args: &[Variable],
module: &Arc<Module>
) -> Result<Variable, String> {
use std::cell::Cell;
use range::Range;
use dyon::FnIndex;
use dyon::runtime::Flow;
use dyon::ast;
let name: Arc<String> = Arc::new(function.into());
let fn_index = module.find_function(&name, 0);
if let FnIndex::None = fn_index {
return Err(format!("Could not find function `{}`",function))
}
let call = ast::Call {
alias: None,
name: name.clone(),
f_index: Cell::new(fn_index),
args: args.iter()
.map(|arg| ast::Expression::Variable(Box::new((
Range::empty(0), arg.clone()))))
.collect(),
custom_source: None,
source_range: Range::empty(0),
};
match runtime.call(&call, &module) {
Ok((Some(val), Flow::Continue)) => Ok(val),
Err(err) => Err(err),
_ => Err("Error during call".to_owned())
}
}
This will let you write the original code as
def test_dyon_fn(
dyon_runtime: &mut Runtime
module: &Module,
fn: &str,
)
let v = call_str_ret_ex(&mut dyon_runtime, fn, &[Variable::f64(0.0)], &dyon_module);
match v {
Err(e) => {
eprintln!("Error: {:?}", e);
}
Ok(v) => {
println!("Called {:?} - result {:?}", fn, v);
}
};
fn main() {
let mut dyon_runtime = Runtime::new();
let mut module = Module::new();
let shim = Arc::new("sin_shim(x) = sin(x)".into());
dyon::load_str("main.rs", shim, &mut module).expect("Unable to load shim function");
let dyon_module = Arc::new(module);
test_dyon_fn(&mut dyon_runtime, &dyon_module, "sin");
test_dyon_fn(&mut dyon_runtime, &dyon_module, "sin_shim");
test_dyon_fn(&mut dyon_runtime, &dyon_module, "no_such");
}
This prints:
Called sin - result F64(0.0, None)
Called sin_shim - result F64(0.0, None)
Error: "Could not find function `no_such`"