I have an enum:
enum DaEnum{
One(u8),
Strang(String),
}
I would like to variable y to be assigned value from enum:
let x = DaEnum::One(1);
let y;
match x{
DaEnum::One(one) => {y = one},
DaEnum::Strang(strang) => {y = strang},
}
println!("Value of y =>{:?}",y);
Here is the error from cargo run:
error[E0308]: mismatched types
--> src\main.rs:33:40
|
30 | let y;
| - expected due to the type of this binding
...
33 | DaEnum::Strang(strang) => {y = strang},
| ^^^^^^ expected `u8`, found struct `String`
Desired case would be when x is 1, y is 1and when x is a String, y would also be a String.
A generic function may help with your case if it's simple enough. You can pick up all the common behavior into one function and invoke it in every match arm. Please be aware of the trait because it must be shared by all your usages.
#[derive(Clone)]
enum DaEnum {
One(u8),
Strang(String),
}
fn main() {
let x = DaEnum::One(1);
fn common_stuff<T: std::fmt::Debug>(v: T) {
// common stuff
println!("Value of y =>{:?}", v);
}
// (1)
match x.clone() {
DaEnum::One(one) => {
let y = one;
// not common stuff
common_stuff(y);
}
DaEnum::Strang(strang) => {
let y = strang;
// not common stuff
common_stuff(y);
}
}
// (2)
match x {
DaEnum::One(one) => common_stuff(one),
DaEnum::Strang(strang) => common_stuff(strang),
}
}
Related
In the code below, version 1 does not compile, whereas version 2 does.
fn foo(text: String) -> Result<u32, String> {
let mut acc: u32 = 0;
for string in text.split("_") {
let result: Option<u32> = string.parse::<u32>().ok();
// version 1
let x: u32 = result.ok_or(text)?;
acc += x;
// version 2
// if let Some(x) = result {
// acc += x;
// } else {
// return Err(text)
// }
}
Ok(acc)
}
error[E0382]: use of moved value: `text`
--> src/main.rs:102:35
|
96 | fn foo(text: String) -> Result<u32, String> {
| ---- move occurs because `text` has type `String`, which does not implement the `Copy` trait
...
102 | let x: u32 = result.ok_or(text)?;
| ^^^^ value moved here, in previous iteration of loop
The issue is that I'm moving text into another function (ok_or) on each loop iteration.
So I understand the error message, but is there still a way out to use the shorthand ? notation in this case? The version 2 is the shortest I could get but it still seems too verbose.
(this is just a MWE / toy example, my question is not about summing numbers in a string)
If you cannot afford a copy on the Err case, and you have a lot of places like that, you can use a macro:
macro_rules! try_opt {
( $v:expr, $e:expr $(,)? ) => {
match $v {
Some(v) => v,
None => return Err($e),
}
}
}
let x: u32 = try_opt!(result, text);
If you can afford a string clone in the Err case (not the happy path), you can just take a reference, as String implements From<&String>:
let x: u32 = result.ok_or(&text)?;
While closures are powerful, they can lead to bugs if used carelessly. An example is a closure that modifies its captured variables when this is not wanted. Sometimes we only need an anonymous function that has no free variables. That is, it captures nothing. Can I specify a closure as capturing nothing and get this checked by the compiler? Something like none |...| {...} looks ideal. I know I can define a function in current scope but it's not as elegant as a variable containing an anonymous function.
Only non capturing closures can coerce to function pointers. You can use this fact to check that the closure is non-capturing by attempting to coerce it to a function pointer:
let closure = || {};
let _: fn() = closure;
You can wrap it in a macro to make this convenient:
macro_rules! enforce_non_capturing {
// This macro does not allow specifying the return type (`|| -> Ret {}`),
// but it can be adjusted to allow that.
// It also does not allow patterns as parameter names, but allowing that
// is harder.
(
| $( $param:ident $( : $param_ty:ty )? ),* $(,)? | $body:expr
) => {{
let closure = | $( $param $( : $param_ty )?, )* | $body;
// We want to generate `fn(_, _, ...) -> _` with underscores as the number of parameters.
// We use a dummy repetition to achieve that.
let _: fn( $( enforce_non_capturing!(#replace_with_underscore $param ), )* ) -> _ = closure;
closure
}};
// `||` is recognized as one token instead of two, so we need another arm.
( || $body:expr ) => { enforce_non_capturing!(| | $body) };
(#replace_with_underscore $param:ident) => { _ };
}
fn main() {
// Compiles.
let closure = enforce_non_capturing!(|| {});
closure();
let a = 0;
// Doesn't compile.
// let closure = enforce_non_capturing!(|| a);
// closure();
}
Playground.
Maybe the constraint could not be expressed where the closure/function is provided, but where it is expected.
In this example, fnct2() cannot receive a closure.
fn fnct1(mut f: impl FnMut(i32) -> i32) {
println!("{}", f(10));
}
fn fnct2(f: fn(i32) -> i32) {
println!("{}", f(20));
}
fn main() {
let mut x = 0;
fnct1(|n| {
x += 1;
n + x
});
fnct2(|n| {
// x += 2; // ERROR: expected fn pointer, found closure
// n + x
n + 2
});
println!("x={}", x);
}
/*
11
22
x=1
*/
While this is most certainly not a 'best practice', you can store the closure in a function pointer. Function pointers can only hold non-capturing closures.
This works:
fn main() {
let c: fn() = || {
println!("Hello world!");
};
c();
}
Hello world!
While this doesn't:
fn main() {
let mut a = 10;
let c: fn() = || {
a += 1;
};
}
error[E0308]: mismatched types
--> src/main.rs:3:19
|
3 | let c: fn() = || {
| ____________----___^
| | |
| | expected due to this
4 | | a += 1;
5 | | };
| |_____^ expected fn pointer, found closure
|
= note: expected fn pointer `fn()`
found closure `[closure#src/main.rs:3:19: 3:21]`
note: closures can only be coerced to `fn` types if they do not capture any variables
--> src/main.rs:4:9
|
4 | a += 1;
| ^ `a` captured here
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())
//------- ^
}
}
When using a match to modify a mutable variable, I haven't found a way to use match in a way that is guaranteed to be non-exhaustive and not requiring clone.
struct Stuff {
num: u32,
thing: bool,
}
enum Bar {
Nothing,
SomeStuff(Stuff),
AlsoNothing,
}
fn main() {
let mut things = vec![Bar::SomeStuff(Stuff {
num: 2,
thing: false,
})];
for x in things.iter_mut() {
*x = match *x {
Bar::Nothing => Bar::AlsoNothing,
Bar::AlsoNothing => Bar::SomeStuff(Stuff {
num: 3,
thing: true,
}),
Bar::SomeStuff(thing) => panic!("not sure"),
}
}
}
error[E0507]: cannot move out of borrowed content
--> src/main.rs:19:20
|
19 | *x = match *x {
| ^^ cannot move out of borrowed content
...
25 | Bar::SomeStuff(thing) => panic!("not sure"),
| ----- hint: to prevent move, use `ref thing` or `ref mut thing`
My intent is to write Bar::SomeStuff(thing) => Bar::SomeStuff(thing) and effectively leave it unchanged, but I cannot move through with a borrow or a reference.
Bar::SomeStuff(thing.clone()) could work, but copying a big struct could be very expensive.
Removing the *x = and changing to () could also work, but I am only returning a Bar enum so having the compiler check the return type is something I hope to keep.
If you want to pass a value unchanged, just capture the match with a variable and pass that back, e.g.
fn foo(a: u32) -> u32 {
match a {
0 => 1,
1 => 2,
e => e,
}
}
In your case, I would move the variable assignment into the match arms
for x in things.iter_mut() {
match x {
Bar::Nothing => *x = Bar::AlsoNothing,
Bar::AlsoNothing => *x = Bar::SomeStuff(Stuff { num: 3, thing: true }),
_ => {},
}
}
To understand Rust, I am trying to implement a little formula interpreter.
An expression can only be an integer, a sum, a variable (Term) or an assignment (Set). We can then evaluate an expression. Since symbols with no associated values can appear in an expression, its evaluation yields another expression (and not necessarily an integer).
The values of the variables (if there are any) can be found in a hash table.
use std::rc::Rc;
use std::collections::HashMap;
enum Expr {
Integer(i32),
Term(String),
Plus(Rc<Expr>, Rc<Expr>),
Set(Rc<Expr>, Rc<Expr>),
}
impl Expr {
fn evaluate(&self, env: &mut HashMap<String, Expr>) -> Expr {
match *self {
Expr::Plus(ref a, ref b) => {
let a_ev = Rc::new(a.evaluate(env));
let b_ev = Rc::new(b.evaluate(env));
match (*a_ev, *b_ev) {
(Expr::Integer(x), Expr::Integer(y)) => Expr::Integer(x + y),
_ => Expr::Plus(a_ev, b_ev),
}
}
Expr::Term(ref a) => *env.get(&a).unwrap(),
Expr::Set(ref a, ref b) => {
let b_ev = Rc::new(b.evaluate(env));
match **a {
Expr::Term(x) => {
let x_value = env.get_mut(&x).unwrap();
*x_value = *b_ev;
*b_ev
}
otherwise => {
let a_ev = Rc::new(a.evaluate(env));
Expr::Set(a_ev, b_ev)
}
}
}
otherwise => otherwise,
}
}
}
The above code does not compile. Each match seems to borrow a variable. Moreover, I think we should not use the String type, but I can't understand why.
The compilation error:
error[E0277]: the trait bound `std::string::String: std::borrow::Borrow<&std::string::String>` is not satisfied
--> src/main.rs:22:39
|
22 | Expr::Term(ref a) => *env.get(&a).unwrap(),
| ^^^ the trait `std::borrow::Borrow<&std::string::String>` is not implemented for `std::string::String`
|
= help: the following implementations were found:
<std::string::String as std::borrow::Borrow<str>>
This question is somewhat subjective, but here are some problems I see:
let a_ev = Rc::new(a.evaluate(env));
let b_ev = Rc::new(b.evaluate(env));
match (*a_ev, *b_ev) {
(Expr::Integer(x), Expr::Integer(y)) => Expr::Integer(x+y),
_ => Expr::Plus(a_ev,b_ev)
}
Here, you can't dereference a_ev and b_ev because *a_ev is owned by the Rc container holding it. You can fix this error by waiting until you actually need the values to be put in Rc containers to create them:
match (a.evaluate(env), b.evaluate(env)) {
(Expr::Integer(x), Expr::Integer(y)) => Expr::Integer(x + y),
(a_ev, b_ev) => Expr::Plus(Rc::new(a_ev), Rc::new(b_ev))
}
Expr::Term(ref a) => *env.get(&a).unwrap()
Here, the variable a has type &String, and so writing &a makes no sense -- it would be like a reference to a reference. That can be fixed by changing &a to a. Also, env.get(a).unwrap() is a reference to a Expr that is owned by the HashMap, so you can't dereference/move it. One solution to this problem would be to use a HashMap<String, Rc<Expr>> instead of a HashMap<String, Expr>. Another would be to simply clone the value:
Expr::Term(ref a) => env.get(a).unwrap().clone(),
In order to be able to clone the value, you must use a "derive" compiler directive to say that Expr implements that trait:
#[derive(Clone)]
enum Expr { // ...
let b_ev = Rc::new(b.evaluate(env));
match **a {
Expr::Term(x) => {
let x_value = env.get_mut(&x).unwrap();
*x_value = *b_ev;
*b_ev
},
// ...
Here, you move *b_ev into the HashMap and then try to dereference/move it again by returning it. Also, like above, you have an extra &. Both of these issues can be solved in the same way as above:
let b_ev = b.evaluate(env);
match **a {
Expr::Term(ref x) => {
let x_value = env.get_mut(x).unwrap();
*x_value = b_ev.clone();
b_ev
},
// ...
otherwise => { let a_ev = Rc::new(a.evaluate(env)); // ...
Here, you are moving **a into otherwise while it is still owned by an Rc container. Since you don't use otherwise, the problem is easily fixed by replacing it with _:
_ => { // ...
otherwise => otherwise
You can't take a value that is owned by something else (*self is owned by something else) and return it by value. You can, however, clone it:
_ => self.clone()
Overall, the problem with your code is that it tries to duplicate data in a few places. As I said above, there are two ways of fixing it that I can think of: using Rc<Expr> everywhere instead of Expr, or using clone. Here is a fixed version of your code that compiles and uses clone:
use std::rc::Rc;
use std::collections::HashMap;
#[derive(Clone, Debug)]
enum Expr {
Integer(i32),
Term(String),
Plus(Rc<Expr>, Rc<Expr>),
Set(Rc<Expr>, Rc<Expr>),
}
impl Expr {
fn evaluate(&self, env: &mut HashMap<String, Expr>) -> Expr {
match *self {
Expr::Plus(ref a, ref b) => {
match (a.evaluate(env), b.evaluate(env)) {
(Expr::Integer(x), Expr::Integer(y)) => Expr::Integer(x + y),
(a_ev, b_ev) => Expr::Plus(Rc::new(a_ev), Rc::new(b_ev))
}
},
Expr::Term(ref a) => env.get(a).unwrap().clone(),
Expr::Set(ref a, ref b) => {
let b_ev = b.evaluate(env);
match **a {
Expr::Term(ref x) => {
let x_value = env.get_mut(x).unwrap();
*x_value = b_ev.clone();
b_ev
},
_ => {
let a_ev = a.evaluate(env);
Expr::Set(Rc::new(a_ev), Rc::new(b_ev))
}
}
}
_ => self.clone()
}
}
}
fn main() {
let e = Expr::Plus(Rc::new(Expr::Integer(9)), Rc::new(Expr::Integer(34)));
let mut env = HashMap::new();
println!("{:?}", e.evaluate(&mut env));
}
[playpen]
This is a second version where I follow Adrian's suggestion to replace all ExprNode with Rc<ExprNode>. The only cloned variables are Rc pointers, so I guess this just increments a reference count. My only regret is that we lost the method syntax, but I think this can be repaired by defining Expr with a struct instead of a type alias.
use std::rc::Rc;
use std::collections::HashMap;
#[derive(Debug)]
enum ExprNode {
Integer(i32),
Term(String),
Plus(Expr, Expr),
Set(Expr, Expr),
}
type Expr = Rc<ExprNode>;
type Env = HashMap<String, Expr>;
fn evaluate(e: &Expr, env: &mut Env) -> Expr {
match **e {
ExprNode::Plus(ref a, ref b) => {
let a_ev = evaluate(a, env);
let b_ev = evaluate(b, env);
match (&*a_ev, &*b_ev) {
(&ExprNode::Integer(x), &ExprNode::Integer(y)) => Rc::new(ExprNode::Integer(x + y)),
_ => Rc::new(ExprNode::Plus(a_ev, b_ev)),
}
}
ExprNode::Term(ref a) => env.get(a).unwrap().clone(),
ExprNode::Set(ref a, ref b) => {
let b_ev = evaluate(b, env);
match **a {
ExprNode::Term(ref x) => {
let x_value = env.get_mut(x).unwrap();
*x_value = b_ev;
x_value.clone()
}
_ => Rc::new(ExprNode::Set(evaluate(a, env), b_ev)),
}
}
_ => e.clone(),
}
}
fn main() {
let e = Rc::new(ExprNode::Plus(
Rc::new(ExprNode::Integer(9)),
Rc::new(ExprNode::Integer(4)),
));
let mut env = HashMap::new();
println!("{:?}", evaluate(&e, &mut env));
}