#Can I have some feedback

50 messages ยท Page 1 of 1 (latest)

subtle granite
#

I started using rust a few days ago, and I want some feedback on my first mini project. I am trying to improve the way I structure my project, best practises while making structs and using macros and if there is anything I need to improve on. Thanks in advance >-< https://github.com/steveyxz/console-wordle-rust

GitHub

First rust program to help me learn more about rust - GitHub - steveyxz/console-wordle-rust: First rust program to help me learn more about rust

marsh raven
#

I like that you're doing cargo fmt everytime you run, your editor can probably do that automatically.

#

are you on vscode?

subtle granite
#

nah im on lapcec

#

lapce

#

i use vscode for js tho

#

but i like lapce better for rust

#

because it has similar functionality

#

but it feels faster

#

idk why

marsh raven
#

you could probably search for "rustfmt on save" for that then

subtle granite
#

yea i have that on

#

i just didnt remove it from the bat after i changed the setting ๐Ÿ˜“

#

it only takes like a split second tho so it doesnt really affect it much

#

the code is the main part i need review

marsh raven
#

the

#[macro_use]
extern crate json;

is sort of outdated, you still see it sometimes in docs and tutorials, but you should use use json::{object} and so on instead

tough mango
#

In Cargo.toml, I would recommend against using "*" when specifying the version of dependencies. While in this case, the json crate probably won't significantly change its API, it could at some point, which may suddenly make your program fail to compile next time cargo refreshes the dependencies.

On the point of json, I'd also suggest looking into the serde and serde_json crates. You can use it to deserialize JSON into concrete types (or serialize types into JSON).

This is a few different concepts wrapped together, but you'd like, you can clean up the max_attempt input loop (https://github.com/steveyxz/console-wordle-rust/blob/main/src/main.rs#L39-L74) to something like this:

let max_attempts: usize = loop {
    print_with_style(
        "How many attempts would you like per round? (number 3-20)",
        &main_text_style,
        &terminal,
    );
    
    let input = terminal.read_line().expect("failed to read input"); // If you're not going to handle unwraps, then at least use .expect() instead. Additionally, read_line()'s Ok type, is always String, so you don't have to declare the type manually.
    
    if input.is_empty() { // if the input is empty, break with default; no need to try to parse it.
        break 6;
    }
    
    match input.parse() { // compiler can infer the return type of parse()
        Ok(result) if result >= 3 && result <= 20 => break result, // this uses a "match guard"
        Ok(_) => print_with_style(
            "Make sure to enter a number between 3-20",
            &main_error_style,
            &terminal,
        ),
        Err(_) => print_with_style(
            "Make sure to enter a valid number!",
            &main_error_style,
            &terminal,
        ),
    }
};
```Similar to how you can `return` from a function with a value, you can also `break` out of a loop, and return a value with it.
#

Rest of main.rs look good I think, besides some more occurrences of stuff I mentioned.

#

Small thing, but in https://github.com/steveyxz/console-wordle-rust/blob/main/src/lib.rs#L75, there's a few things you could do here. At the very least, if you ever want a reference to String, you should use &str, not &String. Alternatively, you could just use String, and the caller would possibly need to clone(). Or, you can use generics like this:

pub fn guess<S: ToString>(&mut self, word: S) -> bool {
    self.guessed_words.push(word.to_string());
    // ...
}
```This allows the caller to provide any type that implements the ToString trait. Both `&str` and `String` implement it.

Similarly, in cases where you need a `&str` you can use
```Rust
fn foo<S: AsRef<str>>(text: S) {
    let text = text.as_ref();
    // do stuff
}
#

In all the functions in lib.rs, that return a value, note that you don't have to explicitly write return every time. And conventionally, people don't unless they have to.

You're already doing it with is_over(), but I can show another example using guess(). Plus, in this case, because you're returning true/false depending on a function which already returns true/false, you can also get rid of the if statement entirely.

pub fn guess(&mut self, word: &String) -> bool {
    self.guessed_words.push(word.to_string());
    self.current_guesses += 1;
    
    self.is_over()
}
```(Note there is no semicolon after `is_over()`; that's intentional.)
#

The rest of the code looks good.

Nice job on your first project in Rust! There wasn't really anything wrong with your code, and the use of cargo fmt is great (like limepod mentioned). You don't have to make any of the changes I said above; they're just there for you to consider.

subtle granite
# tough mango In `Cargo.toml`, I would recommend against using `"*"` when specifying the versi...

Thanks for the dependencies trick I was confused about the use of "*" in the version. For the json library I just used the first one in crates.io when i searched json, but I will keep those libraries in mind for future projects. The use of loop and using break {value} is really foreign to me (coming from a java background), and your example was really helpful in understanding both if use of loop inline, and also further extensions of match (i didn't know you could have multiple cases of the same Ok)

subtle granite
subtle granite
subtle granite
#

Thanks for the feedback ๐Ÿ˜„

#

It really helped

tough mango
#

No problem, glad to help.

tough mango
# subtle granite I didn't know this too, I'll make sure to keep it in mind. I didn't think it was...

To be honest, in nearly all cases, you're going to end up cloning the string anyways. Only case where that wouldn't happen, of the provided solutions, was if the argument took a String, and the caller didn't need to reuse the string after calling the function. For &str and String types, to_owned and to_string will implicitly clone the underlying data. So all three solutions are essentially the same performance-wise.

subtle granite
#

I see

#

Another question, if ToString derivable

#

*is

#

Like with #[derive(ToString)]

tough mango
#

(and no, you cannot derive(Display) either) :P

subtle granite
#

I see, implementing Display is very similar to implementing debug right

#

actually its the same

tough mango
#

Debug can be derived, so not really?

subtle granite
#

as in the contents of the implementation are similar?

#

like write!(xxx) or something

tough mango
#

Sorta yeah

subtle granite
#

thanks

#

do you have any recommendations for a graphics library

#

i want to make a basic game

#

like pong

#

preferably i would want a library which isn't just a bunch of binding for opengl

#

or vulkan

tough mango
#

Hmm I'd suggest asking in #games-and-graphics for that. I don't typically write games.

subtle granite
#

ok thanks