Functions in Rust share similarities with those in other languages, but there are also many differences. Below is a very simple function:
fn plus(a: i32, b: i32) -> i32 {
a + b
}
This is an addition function that takes two integers of type i32, calculates their sum, and returns it.
Refer to this example to understand some characteristics of functions in Rust.
Function Declaration
In Rust, the <span>fn</span> keyword is used to declare a function, and the position of the function does not affect its invocation, meaning that the code calling the function can appear before the function declaration.
Function Visibility
- • Default Private Functions are private by default, meaning that without any modifier, they are only visible within the current module and its submodules.
- • Public Functions A function declared with the
<span>pub</span>keyword is a public function. Adding the<span>pub</span>keyword to the<span>plus</span>function:
fn plus(a: i32, b: i32) -> i32 {
a + b
}
This allows it to be called from anywhere.
<span>pub(crate)</span> keyword is a crate-scoped function, meaning it can only be accessed within the current crate. For example, for the <span>plus</span> function, if we want it to be called only within the current crate and not directly called when someone imports this crate, we can use <span>pub(crate)</span> to limit its access scope. The benefit of this is that it can shield the implementation details of internal logic from external access, avoiding unnecessary function exposure to callers and increasing complexity.Parameters and Return Values
In Rust, function parameters are defined using the <span>parameter_name: parameter_type</span> format, and the parameter type cannot be omitted because Rust is a strongly typed language, and all parameters need to know their types. It is important to note that Rust does not support function overloading, meaning you cannot have two functions with the same name in the same <span>.rs</span> file, even if the number or type of parameters is different. Additionally, Rust does not support variable-length parameters; if variable-length parameters are needed, macros can be used to address this (which will be discussed later).
The return value of a Rust function is defined using the <span>-> return_type</span> format, such as in the <span>plus</span> function where <span>-> i32</span> indicates that it returns a value of type i32. When no return value is needed, the return type can be omitted, as shown below:
fn main() {
println!("Hello, world!");
}
However, in reality, this <span>main</span> function does have a return value, which is of type <span>()</span>, which can be understood as <span>void</span> in other languages.<span>()</span> represents an empty tuple; note that it does not represent <span>NULL</span>, as there is no concept of <span>NULL</span> in Rust.
The above function is equivalent to this:
fn main() -> () {
println!("Hello, world!");
return ();
}
In the return statement, the <span>return</span> keyword can be omitted, as in the <span>plus</span> function, where it directly returns <span>a + b</span> without the <span>return</span> keyword. This is also valid, but remember not to add a semicolon at the end, as the return of a function needs a value, not a statement; a statement ending with a semicolon is not a value.
Function Invocation
fn main() {
let sum = plus(1, 2);
println!("{}", sum);
}
In the second line of this <span>main</span> function, the <span>plus</span> function is called, and its return value is assigned to the <span>sum</span> variable. Note that when declaring <span>sum</span>, the type of this variable is not explicitly annotated because the Rust compiler can automatically infer the specific type based on the return value of the function; in this case, the actual type is <span>i32</span>. This is equivalent to the following declaration.
let sum: i32 = plus(1, 2);
Function Naming Conventions
The quality of function names directly affects the readability of the code, so it is important to think carefully before defining a function. We should try to adhere to the following principles:
- • Use snake_case style. That is, use all lowercase letters, with words separated by underscores, preferably not starting with an underscore, and avoid using pinyin.
- • Be concise and semantically clear. Function names should not be too long and should be able to express the main functionality of the function. If it cannot accurately express the functionality, consider whether the function logic is too long and needs to be split.
- • Do not use keywords as function names, as this will cause compilation errors. For example, you cannot define a function named
<span>fn fn()</span>. - • Special function conventions. In Rust, the
<span>new</span>function is a convention for constructor function names, used to indicate the creation of an instance of a struct.
These are the most basic aspects of functions in Rust. In addition, Rust also has associated functions, closures, unsafe functions, etc., which will be explored further later.