03 Rustlings if Solution
if
, is the most basic but still very versatile type of control flow, these next couple of exercises will go through this little word.
Additional Reading
if1.rs
// if1.rs
// Execute `rustlings hint if1` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
pub fn bigger(a: i32, b: i32) -> i32 {
// Complete this function to return the bigger number!
// Do not use:
// - another function call
// - additional variables
}
// Don't mind this for now :)
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ten_is_bigger_than_eight() {
assert_eq!(10, bigger(10, 8));
}
#[test]
fn fortytwo_is_bigger_than_thirtytwo() {
assert_eq!(42, bigger(32, 42));
}
}
Alright looks like we have our first real writing of some basic code -- we need to create an if
statement that will compare 2 numbers or variables a
or b
and return which one is bigger.
if1.rs
errors
⚠️ Compiling of exercises/if/if1.rs failed! Please try again. Here's the output:
error[E0308]: mismatched types
--> exercises/if/if1.rs:6:34
|
6 | pub fn bigger(a: i32, b: i32) -> i32 {
| ------ ^^^ expected `i32`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
|
note: consider returning one of these bindings
--> exercises/if/if1.rs:6:15
|
6 | pub fn bigger(a: i32, b: i32) -> i32 {
| ^ ^
error: aborting due to previous error
Let's look at what the rust_errors
are telling us here.
The line ^^^ expected
i32, found
()``is essentially telling us that there is no return expression because there is nothing in the body of the functionbigger
.
The solution is pretty simple, it's to add an if
a < b
expression.
if1.rs
Solution
pub fn bigger(a: i32, b: i32) -> i32 {
if a < b {
b
} else {
a
}
}
This compiles but the hint reminds me that it can also be done in one line, let's try that, it works just fine and looks like this
pub fn bigger(a: i32, b:i32) -> i32 {
if a < b { b } else { a }
}
I'm also reminded that :
- in Rust the
if
condition doesn't need to be surrounded by parentheses if/else
conditionals are expressions- Each condition is followed by a
{}
block
Okay, let's move on to the next exercise.
if2.rs
// if2.rs
// Step 1: Make me compile!
// Step 2: Get the bar_for_fuzz and default_to_baz tests passing!
// Execute `rustlings hint if2` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
pub fn foo_if_fizz(fizzish: &str) -> &str {
if fizzish == "fizz" {
"foo"
} else {
1
}
}
// No test changes needed!
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn foo_for_fizz() {
assert_eq!(foo_if_fizz("fizz"), "foo")
}
#[test]
fn bar_for_fuzz() {
assert_eq!(foo_if_fizz("fuzz"), "bar")
}
#[test]
fn default_to_baz() {
assert_eq!(foo_if_fizz("literally anything"), "baz")
}
}
if2.rs
errors
⚠️ Compiling of exercises/if/if2.rs failed! Please try again. Here's the output:
error[E0308]: mismatched types
--> exercises/if/if2.rs:13:9
|
9 | pub fn foo_if_fizz(fizzish: &str) -> &str {
| ---- expected `&str` because of return type
...
13 | 1
| ^ expected `&str`, found integer
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
The first comments state that we first have to make the code compile, so the first thing to do in this case is to add the bar
by replacing the 1
which the Rust compile clearly states that it expected an &str
and this is an integer.
// if2.rs
// Step 1: Make me compile!
// Step 2: Get the bar_for_fuzz and default_to_baz tests passing!
// Execute `rustlings hint if2` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
pub fn foo_if_fizz(fizzish: &str) -> &str {
if fizzish == "fizz" {
"foo"
} else {
"bar" // add bar to get it to compile
}
}
// No test changes needed!
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn foo_for_fizz() {
assert_eq!(foo_if_fizz("fizz"), "foo")
}
#[test]
fn bar_for_fuzz() {
assert_eq!(foo_if_fizz("fuzz"), "bar")
}
#[test]
fn default_to_baz() {
assert_eq!(foo_if_fizz("literally anything"), "baz")
}
}
Once we replace this with bar
it compiles, but it still doesn't pass the test, which is our step 2. in the comments.
⚠️ Testing of exercises/if/if2.rs failed! Please try again. Here's the output:
running 3 tests
test tests::bar_for_fuzz ... ok
test tests::foo_for_fizz ... ok
test tests::default_to_baz ... FAILED
successes:
successes:
tests::bar_for_fuzz
tests::foo_for_fizz
failures:
---- tests::default_to_baz stdout ----
thread 'tests::default_to_baz' panicked at 'assertion failed: `(left == right)`
left: `"bar"`,
right: `"baz"`', exercises/if/if2.rs:34:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
tests::default_to_baz
test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
So here we see that the first two test are passing bar_for_fuzz
and foo_for_fizz
but default_to_baz
is not. So let's take a closer look at the tests and see why this is happening.
foo_for_fizz
test
#[test]
fn foo_for_fizz() {
assert_eq!(foo_if_fizz("fizz"), "foo") // first test clearly defined in our `if` statement
}
which is in our code with
if fizzish == "fizz" {
"foo"
}
bar_for_fuzz
test
#[test]
fn bar_for_fuzz() {
assert_eq!(foo_if_fizz("fuzz"), "bar") // if we have "fuzz" we should get "bar"
}
This tells us that if have Fuzz
then we get bar, but this is working only because we have "bar"
as our else
not because we have "fuzz"
defined.
We do so by adding an else if
statement like this:
else if fizzish == "fuzz" {
"bar"
}
This will meet the conditions of our second test
default_to_baz
test
#[test]
fn default_to_baz() {
assert_eq!(foo_if_fizz("literally anything"), "baz")
}
In our final test we see that it's saying whatever else, doesn't matter what it is, just give me "baz"
so we can easily do that by adding our final else
condition to our foo_if_fizz
function, that would look like this:
pub fn foo_if_fizz(fizzish: &str) -> &str {
if fizzish == "fizz" {
"foo"
} else if fizzish == "fuzz" {
"bar"
} else { // whatever else it is, just make it `"baz"`
"baz"
}
}
This gets our code to compile and pass it's tests successfully.
Progress: [########>---------------------------------------------------] 14/94
✅ Successfully tested exercises/if/if2.rs!
🎉 🎉 The code is compiling, and the tests pass! 🎉 🎉
Alright, I guess we get our first quiz after this 😧.
Conclusion
In this blog post, we delved into Rust if
expressions, which are a fundamental part of the language's control flow. We explored how to use if
, else if
, and else
statements to create conditionals and solve problems in Rust. Additionally, we learned about Rust's unique features, such as not requiring parentheses around if
conditions and the treatment of if/else
conditionals as expressions. By understanding and mastering Rust if
expressions, you'll be better equipped to write efficient and clean Rust code for various applications.