I am new to Rust, so I decided to make a calculator
https://github.com/RealAmogus/rust_calc
How could I have done it better?
76 messages · Page 1 of 1 (latest)
I am new to Rust, so I decided to make a calculator
https://github.com/RealAmogus/rust_calc
How could I have done it better?
well to get some easy stuff out of the way, have you ran cargo fmt and cargo clippy?
these two are the formatter and linter respectively
cargo fmt deleted some of the unnecessary new lines I had
cargo clippy suggests using vec.first() instead of vec.get(0)
I already ran cargo clippy before asking
but is changing vec.get(0) to vec.first() important?
it's more idiomatic, but in this situation doesnt really matter
anyways
let val1 = vec.get(0).unwrap().parse::<f64>();
let val2 = vec.get(2).unwrap().parse::<f64>();
these should be just
let val1 = vec[0].parse::<f64>();
let val2 = vec[2].parse::<f64>();
since these are functionally equivalent
oh
ok ill change that
then
if val1.is_err() || val2.is_err() {
return Err(NotAnOperationError::InvalidValue)
}
let val1 = val1.unwrap();
let val2 = val2.unwrap();
this would be unidiomatic. i would do
let Some((val1, val2)) = val1.ok().zip(val2.ok()) else {
return Err(NotAnOperationError::InvalidValue);
}
or other variations
up to you whether to use match or what
match *vec.get(1).unwrap() { could be using the index syntax, as i stated above
mhm
let input_iter = user_input.split_whitespace();
let mut input_vec: Vec<&str> = Vec::new();
for str in input_iter {
input_vec.push(str);
}
a lot of these parts are unnecessary. you can just do
let input_vec: Vec<&str> = user_input.split_whitespace().collect();
for those if statements at the end i would use the "early returns" idiom
why are you using thread::park
if you run it by directly executing the window will close before you can see the result
so
I just called park();
to prevent that
umm
you have not implemented Error on the struct, yes
cant figure out how
you have to implement Display and Debug, then impl Error
use std::fmt::{Display, Error as fmtError, Formatter};
#[derive(Debug)]
enum NotAnOperationError {
InvalidSign,
InvalidValue,
}
impl Display for NotAnOperationError {
fn fmt(&self, _f: &mut Formatter<'_>) -> Result<(), fmtError> {
Err(fmtError)
}
}
impl Error for NotAnOperationError {}
this works
is it the correct way to do that?
Display is not really correct
you should, you know, actually display something. have you read the docs on Display
I replaced the Err(fmtError);
with
write!(f, "Provide a valid input.");
ignore the ; s
but it doesnt display it
not that really helpful of an error message, but sure
usually you'd match on the enum and display the appropriate message
uh
im probably doing something wrong
use std::thread::park;
use std::io;
use std::error::Error;
use std::fmt::{Display, Error as fmtError, Formatter};
#[derive(Debug)]
enum NotAnOperationError {
InvalidSign,
InvalidValue,
}
impl Display for NotAnOperationError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmtError> {
write!(f, "Provide a valid input.")
}
}
impl Error for NotAnOperationError {}
fn eval_calc(vec: Vec<&str>) -> Result<f64, NotAnOperationError> {
let val1 = vec[0].parse::<f64>();
let val2 = vec[2].parse::<f64>();
let Some((val1, val2)) = val1.ok().zip(val2.ok())
else {
return Err(NotAnOperationError::InvalidValue);
};
match vec[1] {
"+" => Ok(val1 + val2),
"-" => Ok(val1 - val2),
"*" => Ok(val1 * val2),
"/" => Ok(val1 / val2),
"log" => Ok(val2.log(val1)),
"^" => Ok(val1.powf(val2)),
&_ => Err(NotAnOperationError::InvalidSign),
}
}
fn main() -> Result<(), Box<dyn Error>> {
println!(
"Supported operations:
value + value
value - value
value * value
value / value
base log exponent
base ^ power"
);
let mut user_input = String::new();
io::stdin().read_line(&mut user_input)?;
let input_vec: Vec<&str> = user_input.split_whitespace().collect();
if input_vec.len() == 3 {
println!("{}", eval_calc(input_vec)?);
} else {
println!("Provide a valid input.");
}
park();
Ok(())
}
couldnt I just use unwrap_or_else
park is useless since you arent looping anything here btw
and its better to actually not do that and just run the program in the terminal anyway
also why have those error enum at all? if you don't use its enumness properly
I will but I want to get it working first
how should I use them
I am like
really new
to rust
:)
in Display, you aren't really differentiating InvalidSign from InvalidValue. you just print out "Provide a valid input." and call it a day
how new? have you read the book?
its not even printing that right now
parts of it
I did read the enums part
but rn it isnt even printing the "provide a valid input"
it just prints the error enum
use std::error::Error;
use std::fmt::{Display, Error as fmtError, Formatter};
use std::io;
use std::thread::park;
#[derive(Debug)]
enum NotAnOperationError {
InvalidSign,
InvalidValue,
}
impl Display for NotAnOperationError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmtError> {
match self {
NotAnOperationError::InvalidSign => write!(f, "Couldn't recognize the operation."),
NotAnOperationError::InvalidValue => write!(f, "Couldn't parse the input to f64."),
}
}
}
impl Error for NotAnOperationError {}
fn eval_calc(vec: Vec<&str>) -> Result<f64, NotAnOperationError> {
let val1 = vec[0].parse::<f64>();
let val2 = vec[2].parse::<f64>();
let Some((val1, val2)) = val1.ok().zip(val2.ok())
else {
return Err(NotAnOperationError::InvalidValue);
};
match vec[1] {
"+" => Ok(val1 + val2),
"-" => Ok(val1 - val2),
"*" => Ok(val1 * val2),
"/" => Ok(val1 / val2),
"log" => Ok(val2.log(val1)),
"^" => Ok(val1.powf(val2)),
&_ => Err(NotAnOperationError::InvalidSign),
}
}
fn main() -> Result<(), Box<dyn Error>> {
println!(
"Supported operations:
value + value
value - value
value * value
value / value
base log exponent
base ^ power"
);
let mut user_input = String::new();
io::stdin().read_line(&mut user_input)?;
let input_vec: Vec<&str> = user_input.split_whitespace().collect();
if input_vec.len() == 3 {
println!("{}", eval_calc(input_vec)?);
} else {
println!("Provide a valid input.");
}
park();
Ok(())
}
I dont know why but it doesnt display the messages in the display impl
maybe I could try implementing Debug instead of just deriving it?
yeah
it works now
use std::error::Error;
use std::fmt::{Debug, Display, Error as fmtError, Formatter};
use std::io;
use std::thread::park;
enum NotAnOperationError {
InvalidSign,
InvalidValue,
}
impl Debug for NotAnOperationError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmtError> {
match self {
NotAnOperationError::InvalidSign => write!(f, "Couldn't recognize the operation."),
NotAnOperationError::InvalidValue => write!(f, "Couldn't parse the input to f64."),
}
}
}
impl Display for NotAnOperationError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmtError> {
match self {
NotAnOperationError::InvalidSign => write!(f, "Couldn't recognize the operation."),
NotAnOperationError::InvalidValue => write!(f, "Couldn't parse the input to f64."),
}
}
}
impl Error for NotAnOperationError {}
fn eval_calc(vec: Vec<&str>) -> Result<f64, NotAnOperationError> {
let val1 = vec[0].parse::<f64>();
let val2 = vec[2].parse::<f64>();
let Some((val1, val2)) = val1.ok().zip(val2.ok())
else {
return Err(NotAnOperationError::InvalidValue);
};
match vec[1] {
"+" => Ok(val1 + val2),
"-" => Ok(val1 - val2),
"*" => Ok(val1 * val2),
"/" => Ok(val1 / val2),
"log" => Ok(val2.log(val1)),
"^" => Ok(val1.powf(val2)),
&_ => Err(NotAnOperationError::InvalidSign),
}
}
fn main() -> Result<(), Box<dyn Error>> {
println!(
"Supported operations:
value + value
value - value
value * value
value / value
base log exponent
base ^ power"
);
let mut user_input = String::new();
io::stdin().read_line(&mut user_input)?;
let input_vec: Vec<&str> = user_input.split_whitespace().collect();
if input_vec.len() == 3 {
println!("{}", eval_calc(input_vec)?);
} else {
println!("Provide a valid input.");
}
park();
Ok(())
}
oh
I forgot the park();
use std::error::Error;
use std::fmt::{Debug, Display, Error as fmtError, Formatter};
use std::io;
enum NotAnOperationError {
InvalidSign,
InvalidValue,
}
impl Debug for NotAnOperationError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmtError> {
match self {
NotAnOperationError::InvalidSign => write!(f, "Couldn't recognize the operation."),
NotAnOperationError::InvalidValue => write!(f, "Couldn't parse the input to f64."),
}
}
}
impl Display for NotAnOperationError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmtError> {
match self {
NotAnOperationError::InvalidSign => write!(f, "Couldn't recognize the operation."),
NotAnOperationError::InvalidValue => write!(f, "Couldn't parse the input to f64."),
}
}
}
impl Error for NotAnOperationError {}
fn eval_calc(vec: Vec<&str>) -> Result<f64, NotAnOperationError> {
let val1 = vec[0].parse::<f64>();
let val2 = vec[2].parse::<f64>();
let Some((val1, val2)) = val1.ok().zip(val2.ok())
else {
return Err(NotAnOperationError::InvalidValue);
};
match vec[1] {
"+" => Ok(val1 + val2),
"-" => Ok(val1 - val2),
"*" => Ok(val1 * val2),
"/" => Ok(val1 / val2),
"log" => Ok(val2.log(val1)),
"^" => Ok(val1.powf(val2)),
&_ => Err(NotAnOperationError::InvalidSign),
}
}
fn main() -> Result<(), Box<dyn Error>> {
println!(
"Supported operations:
value + value
value - value
value * value
value / value
base log exponent
base ^ power"
);
let mut user_input = String::new();
io::stdin().read_line(&mut user_input)?;
let input_vec: Vec<&str> = user_input.split_whitespace().collect();
if input_vec.len() == 3 {
println!("{}", eval_calc(input_vec)?);
} else {
println!("Provide a valid input.");
}
Ok(())
}
does this look fine? @vernal zodiac
looks good to me