02 Rustlings Functions Solution
With function we can learn to write more complex code and lean on the Rust debug errors for help.
Further information
functions1.rs
// functions1.rs
// Execute `rustlings hint functions1` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
fn main() {
call_me();
}
Rust Error for function1.rs
Let's take a look at the compiler output so we can see what it's telling us fix.
⚠️ Compiling of exercises/functions/functions1.rs failed! Please try again. Here's the output:
error[E0425]: cannot find function `call_me` in this scope
--> exercises/functions/functions1.rs:7:5
|
7 | call_me();
| ^^^^^^^ not found in this scope
error: aborting due to previous error
For more information about this error, try `rustc --explain E0425`.
So what is this telling us? It's essentially saying that call me
is not defined within fn main()
because we're trying to call it, but it doesn't know what to do with it. So let's fix it.
function1.rs
Solution
// functions1.rs
// Execute `rustlings hint functions1` or use the `hint` watch subcommand for a hint.
fn main() {
fn call_me() { // we define a basic function called call_me()
}
call_me();
}
It's easy enough we create a functioned called call_me()
inside of our fn main()
so when we call it, the compiler knows where to look. Of course at this point it's not doing much of anything.
We can modify this a little and make the function do something, like this:
fn main() {
fn call_me() {
println!("Call me please") // add a println! with at string inside the call_me() function
}
call_me();
}
Putting a println!
with some text will print out the text when call_me()
is called. In this case: Call me please
or if we wanted to some math, we could do:
// functions1.rs
// Execute `rustlings hint functions1` or use the `hint` watch subcommand for a hint.
fn main() {
fn call_me() {
println!("{}", 4+4) // here we change the string into a simple addition
}
call_me();
}
This would print: 8
function2.rs
// functions2.rs
// Execute `rustlings hint functions2` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
fn main() {
call_me(3);
}
fn call_me(num:) {
for i in 0..num {
println!("Ring! Call number {}", i + 1);
}
}
Rust Errors for function2.rs
⚠️ Compiling of exercises/functions/functions2.rs failed! Please try again. Here's the output:
error: expected type, found `)`
--> exercises/functions/functions2.rs:10:16
|
10 | fn call_me(num:) {
| ^ expected type
error[E0425]: cannot find value `num` in this scope
--> exercises/functions/functions2.rs:11:17
|
11 | for i in 0..num {
| ^^^ not found in this scope
|
help: you might have meant to write `.` instead of `..`
|
11 - for i in 0..num {
11 + for i in 0.num {
|
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0425`.
Alright so I've got a couple of errors here:
- Line 10, there's a type expected, so we fix that by adding
i32
Adding the type solved all of our problems, nothing else do here.
function2.rs
Solution
// functions2.rs
// Execute `rustlings hint functions2` or use the `hint` watch subcommand for a hint.
fn main() {
call_me(3);
}
fn call_me(num: i32) { // added the `i32` type here
for i in 0..num {
println!("Ring! Call number {}", i + 1);
}
}
This reminds us that Rust's function signatures require type annotations. Once we fixed the function's signature we get the following:
Output:
====================
Ring! Call number 1
Ring! Call number 2
Ring! Call number 3
====================
function3.rs
// functions3.rs
// Execute `rustlings hint functions3` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
fn main() {
call_me();
}
fn call_me(num: u32) {
for i in 0..num {
println!("Ring! Call number {}", i + 1);
}
}
Rust errors for function3.rs
⚠️ Compiling of exercises/functions/functions3.rs failed! Please try again. Here's the output:
error[E0061]: this function takes 1 argument but 0 arguments were supplied
--> exercises/functions/functions3.rs:7:5
|
7 | call_me();
| ^^^^^^^-- an argument of type `u32` is missing
|
note: function defined here
--> exercises/functions/functions3.rs:10:4
|
10 | fn call_me(num: u32) {
| ^^^^^^^ --------
help: provide the argument
|
7 | call_me(/* u32 */);
| ~~~~~~~~~~~
error: aborting due to previous error
For more information about this error, try `rustc --explain E0061`.
Once again the Rust compiler comes through with a very clear suggestion pointing out that call_me()
is missing an argument of type u32
it even provides help
in the last segment showing us where to put the u32
: call_me(/* u32 */);
How great is that. So what u32
should we put in there? Let's try 6
.
functions3.rs
Solution
// functions3.rs
// Execute `rustlings hint functions3` or use the `hint` watch subcommand for a hint.
fn main() {
call_me(6); // we've added 6 here
}
fn call_me(num: u32) {
for i in 0..num {
println!("Ring! Call number {}", i + 1);
}
}
And just like that we're back in business. Our fn main()
runs and calls call_me
six times because that's the number we've passed in to call_me(6)
.
Output:
====================
Ring! Call number 1
Ring! Call number 2
Ring! Call number 3
Ring! Call number 4
Ring! Call number 5
Ring! Call number 6
====================
Just to be clear in this case we could put any u32
we wanted, including 0
, but that doesn't print anything. We can't pass in a negative number in this case either because defined a u32
and exceeding the limit of a u32
would also fail.
function4.rs
// functions4.rs
// Execute `rustlings hint functions4` or use the `hint` watch subcommand for a hint.
// This store is having a sale where if the price is an even number, you get
// 10 Rustbucks off, but if it's an odd number, it's 3 Rustbucks off.
// (Don't worry about the function bodies themselves, we're only interested
// in the signatures for now. If anything, this is a good way to peek ahead
// to future exercises!)
// I AM NOT DONE
fn main() {
let original_price = 51;
println!("Your sale price is {}", sale_price(original_price));
}
fn sale_price(price: i32) -> {
if is_even(price) {
price - 10
} else {
price - 3
}
}
fn is_even(num: i32) -> bool {
num % 2 == 0
}
We're getting a little more instruction here, but as always the key lies in looking at the Rust compiler
⚠️ Compiling of exercises/functions/functions4.rs failed! Please try again. Here's the output:
error: expected type, found `{`
--> exercises/functions/functions4.rs:17:30
|
17 | fn sale_price(price: i32) -> {
| ^ expected type
error: aborting due to previous error
Looks pretty straight forward, line 17 is missing a type in the function's signature, looks like we should expect to return an i32
, so let's try that.
fn main() {
let original_price = 51;
println!("Your sale price is {}", sale_price(original_price));
}
fn sale_price(price: i32) -> i32 { // added return type here: `i32`
if is_even(price) {
price - 10
} else {
price - 3
}
}
fn is_even(num: i32) -> bool {
num % 2 == 0
}
And it works. Nothing too difficult, if you look at the is_even
function there the function is returning a bool
instead of an i32
Output:
====================
Your sale price is 48
====================
function5.rs
// functions5.rs
// Execute `rustlings hint functions5` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
fn main() {
let answer = square(3);
println!("The square of 3 is {}", answer);
}
fn square(num: i32) -> i32 {
num * num;
}
function5.rs
Errors
⚠️ Compiling of exercises/functions/functions5.rs failed! Please try again. Here's the output:
error[E0308]: mismatched types
--> exercises/functions/functions5.rs:11:24
|
11 | fn square(num: i32) -> i32 {
| ------ ^^^ expected `i32`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
12 | num * num;
| - help: remove this semicolon to return this value
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
This is once again a very helpful explanation from the compiler, if we look at the help: remove this semicolon to return this value
note, it tells why we are getting the error on line 11. Because with a ;
semicolon this function has no return value and this function expects a return value as we have defined in the function signature. So how do we solve this?
The easiest way is to remove the semicolon as the Rust compiler suggests, but just so we have another solution we can also use the return
keyword. From my understanding it's more idiomatic to just remove the ;
but I wanted to also bring up the possibility of using return
.
The reason this happens in Rust is because the compiler distinguishes between expressions and statements. Expressions return a value based on their operands(s), and statements simply return a ()
type.
function5.rs
Solution
fn main() {
let answer = square(3);
println!("The square of 3 is {}", answer);
}
fn square(num: i32) -> i32 {
num * num
}
Output:
====================
The square of 3 is 9
====================
Conclusion
In this blog post, we've explored various Rust functions and the importance of function signatures, including specifying the correct types for both input parameters and return values. We have also seen how the Rust compiler provides helpful error messages and suggestions to guide us in fixing issues with our code. Additionally, we've briefly touched upon the differences between expressions and statements in Rust, which determine whether a value is returned or not.
Remember that Rust functions are powerful tools for writing clean, maintainable code. Keep practicing and exploring different function patterns, and you'll soon become proficient in writing complex Rust programs.