Clippy
useful hints to make the code better.
cargo clippy
Types
replace &Vec<i32>
with &[i32]
// change this
fn foo(numbers: &Vec<i32>) {
...
}
// to that
fn foo(numbers: &[i32]) {
...
}
Tait as parameter
trait Summary {
fn summarize() {...}
}
pub fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}
// item has to implement two traits
fn some_func(item: impl SomeTrait + OtherTrait) -> bool {
item.some_function() && item.other_function()
}
usefull traits
From trait
To convert a &str into you struct.
struct MyData {
value: i32
}
impl std::convert::From(&str) for MyData {
fn from(value &str) -> Self {
...
}
}
then you can make this:
let line: &str = ....
let data = MyData::from(line);
pattern matching on vectors
If you want to match on different vectors you have to compare is as_slice().
let counts: Vec<i32> = get_counts(cards);
let result = match counts.as_slice() {
[5] => Type::FiveOfKind,
[4, 1] => Type::FourOfKind,
[3, 2] => Type::FullHouse,
[3, 1, 1] => Type::ThreeOfKind,
[2, 2, 1] => Type::TwoPair,
[2, 1, 1, 1] => Type::OnePair,
[1, 1, 1, 1, 1] => Type::HighCard,
_ => {
panic!("bad counts")
}
};
pattern matchin on multiple cases
let cmd = ...
match cmd {
'C' | 'c' => {
// this will be executed on 'C' or 'c'
}
'x' => { }
}
pattern matching on Option<> without moving
the Some(ref p)
instead of Some(p)
avoids moving the value.
let optional_point = Some(Point { x: 100, y: 200 });
match optional_point {
Some(ref p) => println!("Co-ordinates are {},{}", p.x, p.y),
_ => panic!("No match!"),
}
Error
You should return a Result<a, b>
if a function can create an error. a
is the type of the ok value, and b
is the type of the error value
pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
let processing_fee = 1;
let cost_per_item = 5;
// that ? imideately leaves the function if parsing returns an error
let qty = item_quantity.parse::<i32>()?;
Ok(qty * cost_per_item + processing_fee)
}
If in a function several different errors can appear, than you can return Result<a, Box<dyn Error>>>
fn main() -> Result<(), Box<dyn Error>> {
...
}
generics
Set the generic type T in struct
and impl
.
struct Wrapper<T> {
value: T,
}
// TODO: Adapt the struct's implementation to be generic over the wrapped value.
impl<T> Wrapper<T> {
fn new(value: T) -> Self {
Wrapper { value }
}
}
lifetime
pub struct HighScores<'a> {
scores: &'a [u32],
}
impl<'a> HighScores<'a> {
pub fn new(scores: &'a [u32]) -> Self {
HighScores { scores: scores }
}
}
lifetime on functions
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
testing
test if a function panics
#[test]
#[should_panic]
fn greater_than_100() {
Guess::new(200);
}