This is my first complete project in Rust. It's a command line tool to randomly generate player characters in the table top role-playing game called Traveller. Please review and comment on any questions or criticisms of the code. Thanks
This generally looks really good for a first project! Everything I could come up with really is just nitpicking, and if it works, it works. Make it work first, then clean it up after if there's benefit to doing so. Rust's strictness both makes the first working version usually good enough and makes it easier to refactor confidently if is isn't.
- Commiting IDE configuration files (e.g.
.vscode) is a matter of style, but in an OSS environment where many developers may open the project using many different IDEs, it's typically considered good practice to exclude IDE files from the repo using.git/info/exclude. - You don't specify a license in
Cargo.toml. It's fine to choose to use GPL-3.0-or-later and not the Rust community's default MIT OR Apache-2.0, but you should add the metadata to reflect that. - You don't need to use
extern cratedeclarations anymore; that's only necessary for legacy edition 2015 code. - You don't need to add
# Panicsor# Errorssections to every function's documentation. Whether a function can return an error is part of the signature (i.e. whether it returnsResultor not), and the usual assumption if you don't document panics is that the function is intended not to panic (if used in a manner consistent with the documentation). - There's no requirement to pre-call
rand::rng(); it's marginally faster to do so, but all you're saving is a thread-local access andRc::clone. The actual rng is almost certainly going to dominate that cost. - By implementing
Distribution<Character> for StandardUniform, you can ask an RNG source directly for aCharacterinstead of mutating. - There's no need for the extension traits like
Skills; justimpldirectly on the type. This is allowed since the type your implementing on is from the same crate. - I'm not familiar with the Traveller system, but D&D brain wants to name your
throw_dieasroll_d6instead, to clarify what die is being rolled.
Partial review:
-
Since you're not using the 2015 edition, there's no need for the
extern crate ...lines inmain.rs. -
Your
UPP::random_upp()method is non-idiomatic in several ways:- The purpose of the method is just to create a new
UPP; modifying an existing one doesn't make any sense. The method should be an associated function instead: keep it in theimpl UPPblock, get rid of the&mut selfreceiver, and return a newUPP. - There is zero reason to limit the
rngargument to just aThreadRng. It would be better to instead make the method generic inR: Rngand dorng: R.
- The purpose of the method is just to create a new
-
Character::random_gender()has the same problems asrandom_upp(), and it would also make more sense for it to be associated withGenderinstead ofCharacter. GiveCharacterawith_gender(&mut self, g: Gender)method that the random gender is passed to. -
In
Character::nobility_title(), you can change each{return Some("Foo".to_string())}block to justSome("Foo".to_string()). -
Character::describe_rank()would be better if it returnedOption<String>, withNoneinstead of an empty string, akin tonobility_title().
Not sure I understand how to implement this one, perhaps I need to go back and read the rand book.
Some observations:
UPP::socialcould be anenumCharacter::printout()could be an implementation ofstd::fmt::DisplayCareercould be split into separate traits to make each implementation more concise- Overall some functions are very long and some code blocks seem repetitive. Consider generalising them further.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.