The biggest problem with the code is the use of &str
in the ExpressionNode
.
The simplest fix is to change it to String
. You can see the fix for that below.
This also allows removal of all the lifetime annotations.
There’s also a second fix in that code that is important.
let value: &str = *rand::thread_rng().choose(&operators).unwrap();
if value == "ELEM"{
let value = rand::thread_rng().gen::<f64>().to_string();
}
should be updating value
, so the assignment within the if should not contain let
, and the first assignment should be let mut value
.
If you’re not happy with all the assignments that are happening when switching to a String
, you have two other options – use a Cow
string or use a enum for the contained value type so that it can contain a string or a float, something like – val: Either<&str, f64>
(There’s a version using this at the end of this answer).
The string based version:
use rand::Rng;
#[derive(Debug)]
struct ExpressionNode {
val: String,
left: Option<Box<ExpressionNode>>,
right: Option<Box<ExpressionNode>>,
}
fn create_expression(operators: &[&str], p: i32) -> Option<Box<ExpressionNode>> {
if p == 0 {
let value = String::from(rand::thread_rng().gen::<f64>().to_string());
let new_node = ExpressionNode {
val: value,
left: None,
right: None,
};
return Some(Box::new(new_node));
}
let mut value = rand::thread_rng().choose(&operators).unwrap().to_string();
if value == "ELEM" {
value = rand::thread_rng().gen::<f64>().to_string();
}
let new_node = ExpressionNode {
val: value,
left: create_expression(operators.clone(), p - 1),
right: create_expression(operators.clone(), p - 1),
};
Some(Box::new(new_node))
}
fn main() {
let v = vec!["a", "b", "c", "ELEM"];
let tree = create_expression(&v, 3);
println!("tree = {:?}", tree)
}
For comparison, here’s a version using Either<&str, f64>
:
use either::Either;
use rand::Rng;
#[derive(Debug)]
struct ExpressionNode<'a> {
val: Either<&'a str, f64>,
left: Option<Box<ExpressionNode<'a>>>,
right: Option<Box<ExpressionNode<'a>>>,
}
fn create_expression<'a>(operators: &[&'a str], p: i32) -> Option<Box<ExpressionNode<'a>>> {
if p == 0 {
let value = rand::thread_rng().gen::<f64>();
let new_node = ExpressionNode {
val: Either::Right(value),
left: None,
right: None,
};
return Some(Box::new(new_node));
}
let v = *rand::thread_rng().choose(&operators).unwrap();
let value = if v == "ELEM" {
Either::Right(rand::thread_rng().gen::<f64>())
} else {
Either::Left(v)
};
let new_node = ExpressionNode {
val: value,
left: create_expression(operators.clone(), p - 1),
right: create_expression(operators.clone(), p - 1),
};
Some(Box::new(new_node))
}
fn main() {
let v = vec!["a", "b", "c", "ELEM"];
let tree = create_expression(&v, 3);
println!("tree = {:?}", tree)
}