Rust Functions
Functions are ubiquitous in Rust.
From previous chapters, you can already understand the basic form of Rust functions:
fn <function_name> ( <parameters> ) <function_body>
Rust function names are styled with lowercase letters separated by underscores:
Example
fn main() {
println!("Hello, world!");
another_function();
}
fn another_function() {
println!("Hello, tutorialpro!");
}
Output:
Hello, world!
Hello, tutorialpro!
Note that we defined another_function
after the main
function in our source code. Rust does not care where you define your functions, as long as they are defined somewhere.
Function Parameters
In Rust, if a function needs parameters, you must declare both the parameter names and types:
Example
fn main() {
another_function(5, 6);
}
fn another_function(x: i32, y: i32) {
println!("The value of x is: {}", x);
println!("The value of y is: {}", y);
}
Output:
The value of x is: 5
The value of y is: 6
Function Body: Statements and Expressions
Rust function bodies are made up of a series of statements optionally ending in an expression. So far, we've only seen functions without a final expression, but we've already used expressions as parts of statements.
Statements are actions that perform some action and do not return a value. For example:
let a = 6;
This statement does not return a value, so the following is incorrect:
let a = (let b = 2);
Expressions evaluate to a resulting value. Here are some expressions (assuming the identifiers have been defined):
a = 7
b + 2
c * (a + b)
In Rust, you can write a more complex expression within a block enclosed by {}
:
Example
fn main() {
let x = 5;
let y = {
let x = 3;
x + 1
};
println!("The value of x is: {}", x);
println!("The value of y is: {}", y);
}
Output:
The value of x is: 5
The value of y is: 4
Clearly, this program includes an expression block:
{
let x = 3;
x + 1
};
And you can use function statements within the block, with the last step being an expression whose value is the value of the entire block. This kind of block is called a function body expression.
Note: There is no semicolon after x + 1
, otherwise it would become a statement!
This expression block is a valid function body. Also, in Rust, function definitions can be nested:
Example
fn main() {
fn five() -> i32 {
5
}
println!("The value of five() is: {}", five());
}
Function Return Values
The previous nested example demonstrated how Rust declares return types: after the parameter list with ->
.
In the function body, you can end the function at any time with the return
keyword and a suitable value. This is the most familiar approach for most developers:
Example
fn add(a: i32, b: i32) -> i32 {
return a + b;
}
However, Rust does not support automatic return type deduction! If the return type is not explicitly declared, the function is considered a "pure procedure" and is not allowed to return a value, and return
cannot be followed by a return value expression. This is to ensure that public functions form a visible contract.
Note: A function body expression cannot use the return
keyword.