Use rustfmt. I know the code you've presented is formatted correctly now, but that's because I reformatted it for you over on Stack Overflow (I wouldn't have touched it here).
Read and address the compiler's warning messages!
warning: unused variable: `b`
--> src/main.rs:13:12
|
13 | Ok(b) => {
| ^ help: consider using `_b` instead
|
= note: #[warn(unused_variables)] on by default
warning: unused variable: `err`
--> src/main.rs:22:13
|
22 | Err(err) => panic!("incorrect"),
| ^^^ help: consider using `_err` instead
warning: function cannot return without recursing
--> src/main.rs:10:1
|
10 | fn shell(input: &mut String, version: &String) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
...
16 | shell(input, version);
| --------------------- recursive call site
...
19 | shell(input, &version);
| ---------------------- recursive call site
|
= note: #[warn(unconditional_recursion)] on by default
= help: a `loop` may express intention better if this is on purpose
Finished dev [unoptimized + debuginfo] target(s) in 2.16s
Running `target/debug/playground`
Don't have infinite recursion; that's almost always a bad idea and you will run out of stack space. Write an infinite loop instead.
There's no reason to put input
outside of the function, as it's only ever used inside it.
Use clippy. It will point out things like:
warning: writing `&String` instead of `&str` involves a new object where a slice will do.
--> src/main.rs:9:19
|
9 | fn shell(version: &String) {
| ^^^^^^^ help: change this to: `&str`
|
= note: #[warn(clippy::ptr_arg)] on by default
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
warning: needlessly taken reference of both operands
--> src/main.rs:15:16
|
15 | if &input.trim() == &"ver" || &input.trim() == &"what are you" {
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(clippy::op_ref)] on by default
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
help: use the values directly
|
15 | if input.trim() == "ver" || &input.trim() == &"what are you" {
| ^^^^^^^^^^^^ ^^^^^
See also:
Use Result::expect
instead of doing the match
yourself. This has the beenfit of printing out the underlying error message as well.
Store the result of trim
to avoid doing the work multiple times.
Consider using a match
on the trimmed string to decide what to work on.
use std::io;
fn main() {
let version = "0.0.1";
shell(version);
}
fn shell(version: &str) {
let mut input = String::new();
loop {
input.clear();
io::stdin().read_line(&mut input).expect("incorrect");
let input = input.trim();
match input {
"ver" | "what are you" => {
println!("C ute R ust A mateur B eginner Shell ver: {}", version)
}
_ => println!("Command '{}' Not Recognized", input),
}
}
}
Now we can consider how best to use enums here. An enum is good for a type that can be one of many values. You have that structure in your "command" decisions. You could create an enum from those strings:
use std::io;
fn main() {
let version = "0.0.1";
shell(version);
}
fn shell(version: &str) {
let mut input = String::new();
loop {
input.clear();
io::stdin().read_line(&mut input).expect("incorrect");
let command = input.trim().parse::<Command>();
use Command::*;
match command {
Ok(Version) | Ok(WhatAreYou) => {
println!("C ute R ust A mateur B eginner Shell ver: {}", version)
}
Err(_) => println!("Command '{}' Not Recognized", input),
}
}
}
#[derive(Debug)]
enum Command {
Version,
WhatAreYou,
}
impl std::str::FromStr for Command {
type Err = ();
fn from_str(input: &str) -> Result<Self, Self::Err> {
use Command::*;
Ok(match input {
"ver" => Version,
"what are you" => WhatAreYou,
_ => return Err(()),
})
}
}