3.4.0. Before We Begin
Welcome to Chapter 3 of this Rust self-study series. It has 6 sections:
- Variables and Mutability
- Data Types: Scalar Types
- Data Types: Compound Types
- Functions and Comments (this article)
- Control Flow:
if else - Control Flow: Loops
Through the guessing game in Chapter 2 (beginners who have not read it are strongly encouraged to take a look), you should now have learned the basic Rust syntax. In Chapter 3, we will go one level deeper and learn the general programming concepts in Rust.
If you find this helpful, please like, bookmark, and follow. To keep learning along, follow this series.
3.4.1. The Basics of Functions
- Use the keyword
fnto declare a function. - By convention, function names and variable names use snake case:
- All letters are lowercase, and words are separated with underscores
- Example:
another_function
- Rust does not care whether a custom function is written before or after the place where it is called. As long as the function has been declared and can be called, it works. This is much nicer than some older languages (C/C++: feeling offended). Here is an example: even though the custom function is written after it is declared, it still runs normally.
fn main(){
println!("Hello World");
another_function();
}
fn another_function(){
println!("Another Function");
}
3.4.2. Function Parameters
Function parameters actually have two terms: parameter and argument.
- A parameter is a placeholder declared when defining a function or method, used to receive the value passed in when the function is called. Its purpose is to give the function a general way to handle external data without depending on a specific value.
- An argument is the actual value passed into the function. Its purpose is to provide a concrete value for the function logic to use during execution.
fn main() {
greet("Alice");
}
fn greet(name: &str) {
println!("Hello, {}!", name);
}
In this example:
- The
"Alice"passed togreetfrommainis the argument. It is the actual value passed to the parameternamewhen callinggreet. -
namein thegreetfunction is a parameter, meaning thatgreetexpects a value of type&stras input.
In a function signature, you must declare the type of every parameter, so the compiler does not need to infer it. In the previous example, the &str in name: &str is the type of name.
A function can have multiple parameters, and each parameter is separated by a comma.
3.4.3. Statements and Expressions in Function Bodies
- A function body consists of a series of statements, optionally ending with an expression.
- Rust is an expression-based language, and much of the syntax below is similar to Scala, because both are programming models centered on expressions.
- Statements are instructions that perform some action.
- Expressions evaluate to a value; an expression is itself a value.
- The definition of a function is also a statement.
- Statements do not return a value, so you cannot use
letto assign a statement to a variable.
fn main(){
let x = (let y = 6); // Error: expected expression, found statement (`let`)
}
In this example, the Rust compiler expects the right-hand side to be an expression, but it finds a statement instead, so it reports an error. Some languages allow similar syntax, but Rust does not.
fn main(){
let y = {
let x = 1;
x + 3
};
println!("The value of y is: {}", y);
}
In this example, the code inside the braces after let y = is an expression. The block first defines a variable x and assigns it the value 1, then computes a value through x + 3. Here, x + 3 is an expression, and because it is the last expression in the block, its value (the result of 1 + 3, which is 4) becomes the return value of the entire block. That return value is then assigned to y. When the program runs, it prints The value of y is: 4.
If you add a semicolon ; after x + 3, then x + 3 is no longer an expression but a statement. Because statements do not return a value, the return value of the whole block becomes (), which is the unit type. In Rust, () is a special type whose only value is () itself. Therefore, if you add a semicolon after x + 3, the type of y becomes (), meaning that y no longer stores the calculation result but instead stores a unit value. Note that () is a valid type, but it cannot be printed directly with println!. If you try to print y, the compiler will report an error saying that values of type () cannot be formatted.
3.4.4. Function Return Values
- Declare the return type after the
->symbol, but you cannot name the return value. - In Rust, the return value is the value of the last expression in the function body.
- To return early, use the
returnkeyword and specify a value.
fn machine() -> u32 {
6657
}
fn main(){
let wjq = machine();
println!("The value of wjq is: {}", wjq);
}
In this example, the return type of the machine function is declared as u32. The function body contains only one expression, 6657. Since it is an expression, there is no semicolon after it. And because it is the last expression in the function body (in fact, the only expression), it becomes the function's return value.
3.4.5. Comments
- Single-line comments start with
//. - Multi-line comments use the
/* */structure. Example:
fn machine() -> u32 {
6657
}
/*Let's go G2
Let's go Spirit
Let's go NAVI
*/
fn main(){
let wjq = machine(); // 6657, go, go!
println!("The value of wjq is: {}", wjq);
}
Rust also has an important kind of documentation comment, which we will cover separately later.
Top comments (0)