3 Functions are pervasive in Rust code. You’ve already seen one of the most
4 important functions in the language: the `main` function, which is the entry
5 point of many programs. You’ve also seen the `fn` keyword, which allows you to
8 Rust code uses *snake case* as the conventional style for function and variable
9 names. In snake case, all letters are lowercase and underscores separate words.
10 Here’s a program that contains an example function definition:
12 <span class="filename">Filename: src/main.rs</span>
16 println!("Hello, world!");
21 fn another_function() {
22 println!("Another function.");
26 Function definitions in Rust start with `fn` and have a set of parentheses
27 after the function name. The curly brackets tell the compiler where the
28 function body begins and ends.
30 We can call any function we’ve defined by entering its name followed by a set
31 of parentheses. Because `another_function` is defined in the program, it can be
32 called from inside the `main` function. Note that we defined `another_function`
33 *after* the `main` function in the source code; we could have defined it before
34 as well. Rust doesn’t care where you define your functions, only that they’re
37 Let’s start a new binary project named *functions* to explore functions
38 further. Place the `another_function` example in *src/main.rs* and run it. You
39 should see the following output:
43 Compiling functions v0.1.0 (file:///projects/functions)
44 Finished dev [unoptimized + debuginfo] target(s) in 0.28 secs
45 Running `target/debug/functions`
50 The lines execute in the order in which they appear in the `main` function.
51 First, the “Hello, world!” message prints, and then `another_function` is
52 called and its message is printed.
54 ### Function Parameters
56 Functions can also be defined to have *parameters*, which are special variables
57 that are part of a function’s signature. When a function has parameters, we can
58 provide it with concrete values for those parameters. Technically, the concrete
59 values are called *arguments*, but in casual conversation people tend to use
60 the words “parameter” and “argument” interchangeably for either the variables
61 in a function’s definition or the concrete values passed in when you call a
64 The following rewritten version of `another_function` shows what parameters
67 <span class="filename">Filename: src/main.rs</span>
74 fn another_function(x: i32) {
75 println!("The value of x is: {}", x);
79 Try running this program; you should get the following output:
83 Compiling functions v0.1.0 (file:///projects/functions)
84 Finished dev [unoptimized + debuginfo] target(s) in 1.21 secs
85 Running `target/debug/functions`
89 The declaration of `another_function` has one parameter named `x`. The type of
90 `x` is specified as `i32`. When `5` is passed to `another_function`, the
91 `println!` macro puts `5` where the pair of curly brackets were in the format
94 In function signatures, you *must* declare the type of each parameter. This is
95 a deliberate decision in Rust’s design: requiring type annotations in function
96 definitions means the compiler almost never needs you to use them elsewhere in
97 the code to figure out what you mean.
99 When you want a function to have multiple parameters, separate the parameter
100 declarations with commas, like this:
102 <span class="filename">Filename: src/main.rs</span>
106 another_function(5, 6);
109 fn another_function(x: i32, y: i32) {
110 println!("The value of x is: {}", x);
111 println!("The value of y is: {}", y);
115 This example creates a function with two parameters, both of which are `i32`
116 types. The function then prints out the values in both of its parameters. Note
117 that function parameters don’t all need to be the same type, they just happen
118 to be in this example.
120 Let’s try running this code. Replace the program currently in your *functions*
121 project’s *src/main.rs* file with the preceding example, and run it using
126 Compiling functions v0.1.0 (file:///projects/functions)
127 Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
128 Running `target/debug/functions`
133 Because we called the function with `5` as the value for `x` and `6` is passed
134 as the value for `y`, the two strings are printed with these values.
138 Function bodies are made up of a series of statements optionally ending in an
139 expression. So far, we’ve only covered functions without an ending expression,
140 but we have seen expressions as parts of statements. Because Rust is an
141 expression-based language, this is an important distinction to understand.
142 Other languages don’t have the same distinctions, so let’s look at what
143 statements and expressions are and how their differences affect the bodies of
146 ### Statements and Expressions
148 We’ve actually already used statements and expressions. *Statements* are
149 instructions that perform some action and do not return a value. *Expressions*
150 evaluate to a resulting value. Let’s look at some examples.
152 Creating a variable and assigning a value to it with the `let` keyword is a
153 statement. In Listing 3-1, `let y = 6;` is a statement:
155 <span class="filename">Filename: src/main.rs</span>
163 <span class="caption">Listing 3-1: A `main` function declaration containing one statement.</span>
165 Function definitions are also statements; the entire preceding example is a
168 Statements do not return values. Therefore, you can’t assign a `let` statement
169 to another variable, as the following code tries to do; you’ll get an error:
171 <span class="filename">Filename: src/main.rs</span>
179 When you run this program, the error you’ll get looks like this:
183 Compiling functions v0.1.0 (file:///projects/functions)
184 error: expected expression, found statement (`let`)
187 2 | let x = (let y = 6);
190 = note: variable declaration using `let` is a statement
193 The `let y = 6` statement does not return a value, so there isn’t anything for
194 `x` to bind to. This is different than in other languages, such as C and Ruby,
195 where the assignment returns the value of the assignment. In those languages,
196 you can write `x = y = 6` and have both `x` and `y` have the value `6`; that is
197 not the case in Rust.
199 Expressions evaluate to something and make up most of the rest of the code that
200 you’ll write in Rust. Consider a simple math operation, such as `5 + 6`, which
201 is an expression that evaluates to the value `11`. Expressions can be part of
202 statements: in Listing 3-1 that had the statement `let y = 6;`, `6` is an
203 expression that evaluates to the value `6`. Calling a function is an
204 expression. Calling a macro is an expression. The block that we use to create
205 new scopes, `{}`, is an expression, for example:
207 <span class="filename">Filename: src/main.rs</span>
218 println!("The value of y is: {}", y);
231 is a block that, in this case, evaluates to `4`. That value gets bound to `y`
232 as part of the `let` statement. Note the `x + 1` line without a semicolon at
233 the end, unlike most of the lines you’ve seen so far. Expressions do not
234 include ending semicolons. If you add a semicolon to the end of an expression,
235 you turn it into a statement, which will then not return a value. Keep this in
236 mind as you explore function return values and expressions next.
238 ### Functions with Return Values
240 Functions can return values to the code that calls them. We don’t name return
241 values, but we do declare their type after an arrow (`->`). In Rust, the return
242 value of the function is synonymous with the value of the final expression in
243 the block of the body of a function. You can return early from a function by
244 using the `return` keyword and specifying a value, but most functions return
245 the last expression implicitly. Here’s an example of a function that returns a
248 <span class="filename">Filename: src/main.rs</span>
258 println!("The value of x is: {}", x);
262 There are no function calls, macros, or even `let` statements in the `five`
263 function—just the number `5` by itself. That’s a perfectly valid function in
264 Rust. Note that the function’s return type is specified, too, as `-> i32`. Try
265 running this code; the output should look like this:
269 Compiling functions v0.1.0 (file:///projects/functions)
270 Finished dev [unoptimized + debuginfo] target(s) in 0.30 secs
271 Running `target/debug/functions`
275 The `5` in `five` is the function’s return value, which is why the return type
276 is `i32`. Let’s examine this in more detail. There are two important bits:
277 first, the line `let x = five();` shows that we’re using the return value of a
278 function to initialize a variable. Because the function `five` returns a `5`,
279 that line is the same as the following:
285 Second, the `five` function has no parameters and defines the type of the
286 return value, but the body of the function is a lonely `5` with no semicolon
287 because it’s an expression whose value we want to return. Let’s look at another
290 <span class="filename">Filename: src/main.rs</span>
296 println!("The value of x is: {}", x);
299 fn plus_one(x: i32) -> i32 {
304 Running this code will print `The value of x is: 6`. What happens if we place a
305 semicolon at the end of the line containing `x + 1`, changing it from an
306 expression to a statement? We’ll get an error:
308 <span class="filename">Filename: src/main.rs</span>
314 println!("The value of x is: {}", x);
317 fn plus_one(x: i32) -> i32 {
322 Running this code produces an error, as follows:
325 error[E0308]: mismatched types
328 7 | fn plus_one(x: i32) -> i32 {
329 | ____________________________^
331 | | - help: consider removing this semicolon
333 | |_^ expected i32, found ()
335 = note: expected type `i32`
339 The main error message, “mismatched types,” reveals the core issue with this
340 code. The definition of the function `plus_one` says that it will return an
341 `i32`, but statements don’t evaluate to a value, which is expressed by `()`,
342 the empty tuple. Therefore, nothing is returned, which contradicts the function
343 definition and results in an error. In this output, Rust provides a message to
344 possibly help rectify this issue: it suggests removing the semicolon, which