25 Rustlings Clippy Solution
The Clippy tool is a collection of lints to analyze your code so you can catch common mistakes and improve your Rust code.
If you used the installation script for Rustlings, Clippy should be already installed.
If not you can install it manually via rustup component add clippy
.
Further information
Clippy1.rs
// clippy1.rs
// The Clippy tool is a collection of lints to analyze your code
// so you can catch common mistakes and improve your Rust code.
//
// For these exercises the code will fail to compile when there are clippy warnings
// check clippy's suggestions from the output to solve the exercise.
// Execute `rustlings hint clippy1` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
use std::f32;
fn main() {
let pi = 3.14f32;
let radius = 5.00f32;
let area = pi * f32::powi(radius, 2);
println!(
"The area of a circle with radius {:.2} is {:.5}!",
radius, area
)
}
Our instructions are straight forward make the code compile and use Clippy's suggestions to make it happen. So let's look at the error's and suggestions.
Clippy1.rs Errors
Progress: [######################################################>-----] 86/94 (90.4 %)
⚠️ Compiling of exercises/clippy/clippy1.rs failed! Please try again. Here's the output:
Checking clippy1 v0.0.1 (/Users/desmo/Projects/rustlings/exercises/clippy)
error: approximate value of `f32::consts::PI` found
--> clippy1.rs:14:14
|
14 | let pi = 3.14f32;
| ^^^^^^^
|
= help: consider using the constant directly
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
= note: `#[deny(clippy::approx_constant)]` on by default
error: could not compile `clippy1` (bin "clippy1") due to previous error
Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.
So Clippy doesn't like us using an approximate value of PI
with 3.14f32
instead it suggests for us to use use the constant directly, there's even a link let's take a look at it in the solution.
Clippy2.rs Solution
We're given the approx_constant link above which if you click, I'll save you the trouble and summarize what is shows:
approx_constant
What it does
Checks for floating point literals that approximate constants which are defined in std::f32::consts
or std::f64::consts
, respectively, suggesting to use the predefined constant.
Why is this bad?
Usually, the definition in the standard library is more precise than what people come up with. If you find that your definition is actually more precise, please file a Rust issue.
Example
let x = 3.14;
let y = 1_f64 / x;
Use instead:
let x = std::f32::consts::PI;
let y = std::f64::consts::FRAC_1_PI;
Applying PI
We clearly see above that Clippy doesn't like us to use our own approximate value and wants us to import the std::f32::consts::PI
from the standard library. So let's do that, but instead of using it in the variable, which is fine as they have done in the example, it might be easier to read and also use later in code if we import it with use
and later just use PI
in our variable...let's try that.
use std::f32::consts::PI;
fn main() {
let pi = PI;
let radius = 5.00f32;
let area = pi * f32::powi(radius, 2);
println!(
"The area of a circle with radius {:.2} is {:.5}!",
radius, area
)
}
And with this we are compiling, of course you are free to use the other method of access PI
directly by not importing it at the top of your code and then only modifying the pi
variable like this:
let pi = std::f32::consts::PI;
Either way will compile and Clippy will be happy.
✅ Successfully compiled exercises/clippy/clippy1.rs!
🎉 🎉 The code is compiling, and 📎 Clippy 📎 is happy! 🎉 🎉
Clippy2.rs
// clippy2.rs
// Execute `rustlings hint clippy2` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
fn main() {
let mut res = 42;
let option = Some(12);
for x in option {
res += x;
}
println!("{}", res);
}
Here' we don't get any additional instructions but with a quick glance at the code, it seems that something doesn't seem quite right, but let's inspect the errors and see if we get additional details.
Clippy2.rs Errors
Checking clippy2 v0.0.1 (/Users/desmo/Projects/rustlings/exercises/clippy)
error: for loop over an `Option`. This is more readably written as an `if let` statement
--> clippy2.rs:9:14
|
9 | for x in option {
| ^^^^^^
|
= note: `-D for-loops-over-fallibles` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(for_loops_over_fallibles)]`
help: to check pattern in a loop use `while let`
|
9 | while let Some(x) = option {
| ~~~~~~~~~~~~~~~ ~~~
help: consider using `if let` to clear intent
|
9 | if let Some(x) = option {
| ~~~~~~~~~~~~ ~~~
error: could not compile `clippy2` (bin "clippy2") due to previous error
So, we're getting a clear error with:
`for loop over an `Option`. This is more readably written as an `if let` statement`
Clippy2.rs Solution
Because we have an Option
here, we should use either if let
or while let
which essentially tells our code that if (or while) there is something inside of our option
variable, we should then put that something inside of option
and increment option
by res
in this case 42, if there is None
then do nothing.
fn main() {
let mut res = 42;
let option = Some(12);
// updated with `if let` here
if let Some(x) = option {
res += x;
}
println!("{}", res);
}
if we were to print this we would see 54
as the output.
So with that updated if let
our code compiles and we make Clippy happy again:
✅ Successfully compiled exercises/clippy/clippy2.rs!
🎉 🎉 The code is compiling, and 📎 Clippy 📎 is happy! 🎉 🎉
Clippy3.rs
// clippy3.rs
// Here's a couple more easy Clippy fixes, so you can see its utility.
// I AM NOT DONE
#[allow(unused_variables, unused_assignments)]
fn main() {
let my_option: Option<()> = None;
if my_option.is_none() {
my_option.unwrap();
}
let my_arr = &[
-1, -2, -3
-4, -5, -6
];
println!("My array! Here it is: {:?}", my_arr);
let my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5);
println!("This Vec is empty, see? {:?}", my_empty_vec);
let mut value_a = 45;
let mut value_b = 66;
// Let's swap these two!
value_a = value_b;
value_b = value_a;
println!("value a: {}; value b: {}", value_a, value_b);
}
We're told that we have a couple of more easy Clippy fixes so we see how useful it is. Alright let's look at the errors.
⚠️ Compiling of exercises/clippy/clippy3.rs failed! Please try again. Here's the output:
Checking clippy3 v0.0.1 (/Users/desmo/Projects/rustlings/exercises/clippy)
error: possibly missing a comma here
--> clippy3.rs:14:19
|
14 | -1, -2, -3
| ^
|
= note: to remove this lint, add a comma or write the expr in a single line
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
= note: `#[deny(clippy::possible_missing_comma)]` on by default
error: this call to `unwrap()` will always panic
--> clippy3.rs:10:9
|
9 | if my_option.is_none() {
| ------------------- because of this check
10 | my_option.unwrap();
| ^^^^^^^^^^^^^^^^^^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
= note: `#[deny(clippy::panicking_unwrap)]` on by default
error: this looks like you are trying to swap `value_a` and `value_b`
--> clippy3.rs:25:5
|
25 | / value_a = value_b;
26 | | value_b = value_a;
| |_____________________^ help: try: `std::mem::swap(&mut value_a, &mut value_b)`
|
= note: or maybe you should use `std::mem::replace`?
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
= note: `#[deny(clippy::almost_swapped)]` on by default
error: used `unwrap()` on `None` value
--> clippy3.rs:10:9
|
10 | my_option.unwrap();
| ^^^^^^^^^^^^^^^^^^
|
help: remove the `None` and `unwrap()`
--> clippy3.rs:8:33
|
8 | let my_option: Option<()> = None;
| ^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap
= note: `-D clippy::unnecessary-literal-unwrap` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_literal_unwrap)]`
error: this let-binding has unit value
--> clippy3.rs:19:5
|
19 | let my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `vec![1, 2, 3, 4, 5].resize(0, 5);`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
= note: `-D clippy::let-unit-value` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]`
error: could not compile `clippy3` (bin "clippy3") due to 5 previous errors
Alright looks like we have a lot of work to do here going through each of them one by one and see how we can get this code to compile.
Clippy3.rs Solution
#[allow(unused_variables, unused_assignments)]
fn main() {
let my_option: Option<()> = None;
if my_option.is_none() {
my_option.unwrap();
}
let my_arr = &[
-1, -2, -3
-4, -5, -6
];
println!("My array! Here it is: {:?}", my_arr);
let my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5);
println!("This Vec is empty, see? {:?}", my_empty_vec);
let mut value_a = 45;
let mut value_b = 66;
// Let's swap these two!
value_a = value_b;
value_b = value_a;
println!("value a: {}; value b: {}", value_a, value_b);
}
Error 1
Our first error focuses on my_arr
where it seems like we're missing a comma.
error: possibly missing a comma here
--> clippy3.rs:14:19
|
14 | -1, -2, -3
| ^
|
= note: to remove this lint, add a comma or write the expr in a single line
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
= note: `#[deny(clippy::possible_missing_comma)]` on by default
So by adding the comma after the -3,
this issue is fixed.
Error 2
This error is highlighting a misuse of the unwrap()
method on an Option
type. Specifically, it's warning against calling unwrap()
on an Option
that is known to be None
, as this will always cause a panic at runtime.
error: this call to `unwrap()` will always panic
--> clippy3.rs:10:9
|
9 | if my_option.is_none() {
| ------------------- because of this check
10 | my_option.unwrap();
| ^^^^^^^^^^^^^^^^^^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
= note: `#[deny(clippy::panicking_unwrap)]` on by default
This code checks if my_option
is None
, and if so, attempts to unwrap
it, which is exactly the pattern Clippy is advising against. It's logically inconsistent to check for None
and then unwrap
it, as unwrap
is meant for situations where you are sure the Option
is Some
. So what do we do, just remove the if
check so this error goes away.
Error 3
Here Clippy understands that we're trying to swap values and advises us to use std::mem::swap
. Again, I prefer to use the use
key word to import just to keep the code a little bit cleaner.
error: this looks like you are trying to swap `value_a` and `value_b`
--> clippy3.rs:25:5
|
25 | / value_a = value_b;
26 | | value_b = value_a;
| |_____________________^ help: try: `std::mem::swap(&mut value_a, &mut value_b)`
|
= note: or maybe you should use `std::mem::replace`?
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
= note: `#[deny(clippy::almost_swapped)]` on by default
So our updated code would look like this.
// import at the top of the file
use std::mem::swap;
// -- snippet -- //
// Swapping Values
let mut value_a = 45;
let mut value_b = 66;
// Let's swap these two!
swap(&mut value_a, &mut value_b);
println!("value a: {}; value b: {}", value_a, value_b);
Error 4
Our final error is related to wanting to create an empty Vec
it looks like currently we are creating and then resizing, which is a waste of effort if all we want is an empty Vector.
error: this let-binding has unit value
--> clippy3.rs:19:5
|
19 | let my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `vec![1, 2, 3, 4, 5].resize(0, 5);`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
= note: `-D clippy::let-unit-value` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]`
There's a couple of ways to solve it but probably the easiest is to just remove the elements from the vector and the .resize()
method at the end.
let my_empty_vec: Vec<i32> = vec![];
We're also asked to define it's type but that's pretty straightforward with Vec<i32>
right before the empty vec![]
macro. Here's the final code for reference.
use std::mem::swap;
#[allow(unused_variables, unused_assignments)]
fn main() {
let my_option: Option<()> = None;
// array
let my_arr = &[
-1, -2, -3,
-4, -5, -6
];
println!("My array! Here it is: {:?}", my_arr);
// Create empty Vector
let my_empty_vec: Vec<i32> = vec![];
println!("This Vec is empty, see? {:?}", my_empty_vec);
// Swapping Values
let mut value_a = 45;
let mut value_b = 66;
// Let's swap these two!
swap(&mut value_a, &mut value_b);
println!("value a: {}; value b: {}", value_a, value_b);
}
with these changes Clippy is once again a happy camper:
✅ Successfully compiled exercises/clippy/clippy3.rs!
🎉 🎉 The code is compiling, and 📎 Clippy 📎 is happy! 🎉 🎉
Conclusion
In conclusion, navigating through Rust's Clippy lints is not only an exercise in resolving compile-time errors but also a journey into the depths of idiomatic Rust programming. Clippy, as a linter, serves a pivotal role in guiding developers towards best practices, ensuring code reliability, and maintaining the high standards of Rust's safety guarantees.
Through the examples of clippy1.rs
, clippy2.rs
, and clippy3.rs
, we saw common pitfalls and learned how to address them effectively. Whether it was using the precise value of PI
in clippy1.rs
, embracing the if let
construct for Option
types in clippy2.rs
, or understanding the importance of proper array syntax and variable swapping in clippy3.rs
, each scenario brought its unique learning experience.
These exercises underscore the importance of attention to detail and the nuances of the Rust language. Clippy acts not just as a linter but as an educator, reinforcing the Rust philosophy of writing clear, efficient, and safe code. As Rust continues to evolve, tools like Clippy will remain invaluable for developers, whether they are beginners just starting their Rust journey or experienced coders refining their craft. In the world of Rust, Clippy is more than a tool; it's a companion on the path to mastering one of the most promising systems programming languages of our time.