]>
Commit | Line | Data |
---|---|---|
13cf67c4 XL |
1 | ## Functions |
2 | ||
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 | |
6 | declare new functions. | |
7 | ||
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: | |
11 | ||
12 | <span class="filename">Filename: src/main.rs</span> | |
13 | ||
14 | ```rust | |
74b04a01 | 15 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-16-functions/src/main.rs}} |
13cf67c4 XL |
16 | ``` |
17 | ||
18 | Function definitions in Rust start with `fn` and have a set of parentheses | |
19 | after the function name. The curly brackets tell the compiler where the | |
20 | function body begins and ends. | |
21 | ||
22 | We can call any function we’ve defined by entering its name followed by a set | |
23 | of parentheses. Because `another_function` is defined in the program, it can be | |
24 | called from inside the `main` function. Note that we defined `another_function` | |
25 | *after* the `main` function in the source code; we could have defined it before | |
26 | as well. Rust doesn’t care where you define your functions, only that they’re | |
27 | defined somewhere. | |
28 | ||
29 | Let’s start a new binary project named *functions* to explore functions | |
30 | further. Place the `another_function` example in *src/main.rs* and run it. You | |
31 | should see the following output: | |
32 | ||
33 | ```text | |
74b04a01 | 34 | {{#include ../listings/ch03-common-programming-concepts/no-listing-16-functions/output.txt}} |
13cf67c4 XL |
35 | ``` |
36 | ||
37 | The lines execute in the order in which they appear in the `main` function. | |
38 | First, the “Hello, world!” message prints, and then `another_function` is | |
39 | called and its message is printed. | |
40 | ||
41 | ### Function Parameters | |
42 | ||
43 | Functions can also be defined to have *parameters*, which are special variables | |
44 | that are part of a function’s signature. When a function has parameters, you | |
45 | can provide it with concrete values for those parameters. Technically, the | |
46 | concrete values are called *arguments*, but in casual conversation, people tend | |
47 | to use the words *parameter* and *argument* interchangeably for either the | |
48 | variables in a function’s definition or the concrete values passed in when you | |
49 | call a function. | |
50 | ||
51 | The following rewritten version of `another_function` shows what parameters | |
52 | look like in Rust: | |
53 | ||
54 | <span class="filename">Filename: src/main.rs</span> | |
55 | ||
56 | ```rust | |
74b04a01 | 57 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-17-functions-with-parameters/src/main.rs}} |
13cf67c4 XL |
58 | ``` |
59 | ||
60 | Try running this program; you should get the following output: | |
61 | ||
62 | ```text | |
74b04a01 | 63 | {{#include ../listings/ch03-common-programming-concepts/no-listing-17-functions-with-parameters/output.txt}} |
13cf67c4 XL |
64 | ``` |
65 | ||
66 | The declaration of `another_function` has one parameter named `x`. The type of | |
67 | `x` is specified as `i32`. When `5` is passed to `another_function`, the | |
68 | `println!` macro puts `5` where the pair of curly brackets were in the format | |
69 | string. | |
70 | ||
71 | In function signatures, you *must* declare the type of each parameter. This is | |
72 | a deliberate decision in Rust’s design: requiring type annotations in function | |
73 | definitions means the compiler almost never needs you to use them elsewhere in | |
74 | the code to figure out what you mean. | |
75 | ||
76 | When you want a function to have multiple parameters, separate the parameter | |
77 | declarations with commas, like this: | |
78 | ||
79 | <span class="filename">Filename: src/main.rs</span> | |
80 | ||
81 | ```rust | |
74b04a01 | 82 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-18-functions-with-multiple-parameters/src/main.rs}} |
13cf67c4 XL |
83 | ``` |
84 | ||
85 | This example creates a function with two parameters, both of which are `i32` | |
86 | types. The function then prints the values in both of its parameters. Note that | |
87 | function parameters don’t all need to be the same type, they just happen to be | |
88 | in this example. | |
89 | ||
90 | Let’s try running this code. Replace the program currently in your *functions* | |
91 | project’s *src/main.rs* file with the preceding example and run it using `cargo | |
92 | run`: | |
93 | ||
94 | ```text | |
74b04a01 | 95 | {{#include ../listings/ch03-common-programming-concepts/no-listing-18-functions-with-multiple-parameters/output.txt}} |
13cf67c4 XL |
96 | ``` |
97 | ||
98 | Because we called the function with `5` as the value for `x` and `6` is passed | |
99 | as the value for `y`, the two strings are printed with these values. | |
100 | ||
69743fb6 | 101 | ### Function Bodies Contain Statements and Expressions |
13cf67c4 XL |
102 | |
103 | Function bodies are made up of a series of statements optionally ending in an | |
104 | expression. So far, we’ve only covered functions without an ending expression, | |
69743fb6 | 105 | but you have seen an expression as part of a statement. Because Rust is an |
13cf67c4 XL |
106 | expression-based language, this is an important distinction to understand. |
107 | Other languages don’t have the same distinctions, so let’s look at what | |
108 | statements and expressions are and how their differences affect the bodies of | |
109 | functions. | |
110 | ||
13cf67c4 XL |
111 | We’ve actually already used statements and expressions. *Statements* are |
112 | instructions that perform some action and do not return a value. *Expressions* | |
113 | evaluate to a resulting value. Let’s look at some examples. | |
114 | ||
115 | Creating a variable and assigning a value to it with the `let` keyword is a | |
69743fb6 | 116 | statement. In Listing 3-1, `let y = 6;` is a statement. |
13cf67c4 XL |
117 | |
118 | <span class="filename">Filename: src/main.rs</span> | |
119 | ||
120 | ```rust | |
74b04a01 | 121 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-01/src/main.rs}} |
13cf67c4 XL |
122 | ``` |
123 | ||
124 | <span class="caption">Listing 3-1: A `main` function declaration containing one statement</span> | |
125 | ||
126 | Function definitions are also statements; the entire preceding example is a | |
127 | statement in itself. | |
128 | ||
129 | Statements do not return values. Therefore, you can’t assign a `let` statement | |
130 | to another variable, as the following code tries to do; you’ll get an error: | |
131 | ||
132 | <span class="filename">Filename: src/main.rs</span> | |
133 | ||
134 | ```rust,ignore,does_not_compile | |
74b04a01 | 135 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-19-statements-vs-expressions/src/main.rs}} |
13cf67c4 XL |
136 | ``` |
137 | ||
138 | When you run this program, the error you’ll get looks like this: | |
13cf67c4 | 139 | ```text |
ba9703b0 | 140 | {{#include ../listings/ch03-common-programming-concepts/no-listing-19-statements-vs-expressions/output.txt}} |
13cf67c4 XL |
141 | ``` |
142 | ||
143 | The `let y = 6` statement does not return a value, so there isn’t anything for | |
144 | `x` to bind to. This is different from what happens in other languages, such as | |
145 | C and Ruby, where the assignment returns the value of the assignment. In those | |
146 | languages, you can write `x = y = 6` and have both `x` and `y` have the value | |
147 | `6`; that is not the case in Rust. | |
148 | ||
149 | Expressions evaluate to something and make up most of the rest of the code that | |
150 | you’ll write in Rust. Consider a simple math operation, such as `5 + 6`, which | |
151 | is an expression that evaluates to the value `11`. Expressions can be part of | |
152 | statements: in Listing 3-1, the `6` in the statement `let y = 6;` is an | |
153 | expression that evaluates to the value `6`. Calling a function is an | |
154 | expression. Calling a macro is an expression. The block that we use to create | |
155 | new scopes, `{}`, is an expression, for example: | |
156 | ||
157 | <span class="filename">Filename: src/main.rs</span> | |
158 | ||
159 | ```rust | |
74b04a01 | 160 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-20-blocks-are-expressions/src/main.rs}} |
13cf67c4 XL |
161 | ``` |
162 | ||
163 | This expression: | |
164 | ||
165 | ```rust,ignore | |
166 | { | |
167 | let x = 3; | |
168 | x + 1 | |
169 | } | |
170 | ``` | |
171 | ||
172 | is a block that, in this case, evaluates to `4`. That value gets bound to `y` | |
173 | as part of the `let` statement. Note the `x + 1` line without a semicolon at | |
174 | the end, which is unlike most of the lines you’ve seen so far. Expressions do | |
175 | not include ending semicolons. If you add a semicolon to the end of an | |
176 | expression, you turn it into a statement, which will then not return a value. | |
177 | Keep this in mind as you explore function return values and expressions next. | |
178 | ||
179 | ### Functions with Return Values | |
180 | ||
181 | Functions can return values to the code that calls them. We don’t name return | |
182 | values, but we do declare their type after an arrow (`->`). In Rust, the return | |
183 | value of the function is synonymous with the value of the final expression in | |
184 | the block of the body of a function. You can return early from a function by | |
185 | using the `return` keyword and specifying a value, but most functions return | |
186 | the last expression implicitly. Here’s an example of a function that returns a | |
187 | value: | |
188 | ||
189 | <span class="filename">Filename: src/main.rs</span> | |
190 | ||
191 | ```rust | |
74b04a01 | 192 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-21-function-return-values/src/main.rs}} |
13cf67c4 XL |
193 | ``` |
194 | ||
195 | There are no function calls, macros, or even `let` statements in the `five` | |
196 | function—just the number `5` by itself. That’s a perfectly valid function in | |
9fa01778 | 197 | Rust. Note that the function’s return type is specified too, as `-> i32`. Try |
13cf67c4 XL |
198 | running this code; the output should look like this: |
199 | ||
200 | ```text | |
74b04a01 | 201 | {{#include ../listings/ch03-common-programming-concepts/no-listing-21-function-return-values/output.txt}} |
13cf67c4 XL |
202 | ``` |
203 | ||
204 | The `5` in `five` is the function’s return value, which is why the return type | |
205 | is `i32`. Let’s examine this in more detail. There are two important bits: | |
206 | first, the line `let x = five();` shows that we’re using the return value of a | |
207 | function to initialize a variable. Because the function `five` returns a `5`, | |
208 | that line is the same as the following: | |
209 | ||
210 | ```rust | |
211 | let x = 5; | |
212 | ``` | |
213 | ||
214 | Second, the `five` function has no parameters and defines the type of the | |
215 | return value, but the body of the function is a lonely `5` with no semicolon | |
216 | because it’s an expression whose value we want to return. | |
217 | ||
218 | Let’s look at another example: | |
219 | ||
220 | <span class="filename">Filename: src/main.rs</span> | |
221 | ||
222 | ```rust | |
74b04a01 | 223 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-22-function-parameter-and-return/src/main.rs}} |
13cf67c4 XL |
224 | ``` |
225 | ||
226 | Running this code will print `The value of x is: 6`. But if we place a | |
227 | semicolon at the end of the line containing `x + 1`, changing it from an | |
228 | expression to a statement, we’ll get an error. | |
229 | ||
230 | <span class="filename">Filename: src/main.rs</span> | |
231 | ||
232 | ```rust,ignore,does_not_compile | |
74b04a01 | 233 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/src/main.rs}} |
13cf67c4 XL |
234 | ``` |
235 | ||
236 | Compiling this code produces an error, as follows: | |
237 | ||
238 | ```text | |
74b04a01 | 239 | {{#include ../listings/ch03-common-programming-concepts/no-listing-23-statements-dont-return-values/output.txt}} |
13cf67c4 XL |
240 | ``` |
241 | ||
242 | The main error message, “mismatched types,” reveals the core issue with this | |
243 | code. The definition of the function `plus_one` says that it will return an | |
244 | `i32`, but statements don’t evaluate to a value, which is expressed by `()`, | |
9fa01778 | 245 | an empty tuple. Therefore, nothing is returned, which contradicts the function |
13cf67c4 XL |
246 | definition and results in an error. In this output, Rust provides a message to |
247 | possibly help rectify this issue: it suggests removing the semicolon, which | |
248 | would fix the error. |