11% Functions
22
3- You've already seen one function so far , the ` main ` function:
3+ Every Rust program has at least one function , the ` main ` function:
44
55``` rust
66fn main () {
77}
88```
99
1010This is the simplest possible function declaration. As we mentioned before,
11- ` fn ` says " this is a function," followed by the name, some parentheses because
11+ ` fn ` says ‘ this is a function’, followed by the name, some parentheses because
1212this function takes no arguments, and then some curly braces to indicate the
13- body. Here' s a function named ` foo ` :
13+ body. Here’ s a function named ` foo ` :
1414
1515``` rust
1616fn foo () {
1717}
1818```
1919
20- So, what about taking arguments? Here' s a function that prints a number:
20+ So, what about taking arguments? Here’ s a function that prints a number:
2121
2222``` rust
2323fn print_number (x : i32 ) {
2424 println! (" x is: {}" , x );
2525}
2626```
2727
28- Here' s a complete program that uses ` print_number ` :
28+ Here’ s a complete program that uses ` print_number ` :
2929
3030``` rust
3131fn main () {
@@ -40,7 +40,7 @@ fn print_number(x: i32) {
4040As you can see, function arguments work very similar to ` let ` declarations:
4141you add a type to the argument name, after a colon.
4242
43- Here' s a complete program that adds two numbers together and prints them:
43+ Here’ s a complete program that adds two numbers together and prints them:
4444
4545``` rust
4646fn main () {
@@ -58,7 +58,7 @@ as when you declare it.
5858Unlike ` let ` , you _ must_ declare the types of function arguments. This does
5959not work:
6060
61- ``` { rust,ignore}
61+ ``` rust,ignore
6262fn print_sum(x, y) {
6363 println!("sum is: {}", x + y);
6464}
@@ -67,8 +67,8 @@ fn print_sum(x, y) {
6767You get this error:
6868
6969``` text
70- hello.rs:5:18: 5:19 expected one of `!`, `:`, or `@`, found `)`
71- hello.rs:5 fn print_number(x, y) {
70+ expected one of `!`, `:`, or `@`, found `)`
71+ fn print_number(x, y) {
7272```
7373
7474This is a deliberate design decision. While full-program inference is possible,
@@ -77,7 +77,7 @@ types explicitly is a best-practice. We agree that forcing functions to declare
7777types while allowing for inference inside of function bodies is a wonderful
7878sweet spot between full inference and no inference.
7979
80- What about returning a value? Here' s a function that adds one to an integer:
80+ What about returning a value? Here’ s a function that adds one to an integer:
8181
8282``` rust
8383fn add_one (x : i32 ) -> i32 {
@@ -86,11 +86,11 @@ fn add_one(x: i32) -> i32 {
8686```
8787
8888Rust functions return exactly one value, and you declare the type after an
89- "arrow," which is a dash (` - ` ) followed by a greater-than sign (` > ` ).
89+ ‘arrow’, which is a dash (` - ` ) followed by a greater-than sign (` > ` ). The last
90+ line of a function determines what it returns. You’ll note the lack of a
91+ semicolon here. If we added it in:
9092
91- You'll note the lack of a semicolon here. If we added it in:
92-
93- ``` {rust,ignore}
93+ ``` rust,ignore
9494fn add_one(x: i32) -> i32 {
9595 x + 1;
9696}
@@ -109,60 +109,99 @@ help: consider removing this semicolon:
109109 ^
110110```
111111
112- Remember our earlier discussions about semicolons and ` () ` ? Our function claims
113- to return an ` i32 ` , but with a semicolon, it would return ` () ` instead. Rust
114- realizes this probably isn't what we want, and suggests removing the semicolon .
112+ This reveals two interesting things about Rust: it is an expression-based
113+ language, and semicolons are different from semicolons in other ‘curly brace
114+ and semicolon’-based languages. These two things are related .
115115
116- This is very much like our ` if ` statement before: the result of the block
117- (` {} ` ) is the value of the expression. Other expression-oriented languages,
118- such as Ruby, work like this, but it's a bit unusual in the systems programming
119- world. When people first learn about this, they usually assume that it
120- introduces bugs. But because Rust's type system is so strong, and because unit
121- is its own unique type, we have never seen an issue where adding or removing a
122- semicolon in a return position would cause a bug.
116+ ## Expressions vs. Statements
123117
124- But what about early returns? Rust does have a keyword for that, ` return ` :
118+ Rust is primarily an expression-based language. There are only two kinds of
119+ statements, and everything else is an expression.
125120
126- ``` rust
127- fn foo (x : i32 ) -> i32 {
128- if x < 5 { return x ; }
121+ So what's the difference? Expressions return a value, and statements do not.
122+ That’s why we end up with ‘not all control paths return a value’ here: the
123+ statement ` x + 1; ` doesn’t return a value. There are two kinds of statements in
124+ Rust: ‘declaration statements’ and ‘expression statements’. Everything else is
125+ an expression. Let’s talk about declaration statements first.
126+
127+ In some languages, variable bindings can be written as expressions, not just
128+ statements. Like Ruby:
129+
130+ ``` ruby
131+ x = y = 5
132+ ```
133+
134+ In Rust, however, using ` let ` to introduce a binding is _ not_ an expression. The
135+ following will produce a compile-time error:
136+
137+ ``` ignore
138+ let x = (let y = 5); // expected identifier, found keyword `let`
139+ ```
140+
141+ The compiler is telling us here that it was expecting to see the beginning of
142+ an expression, and a ` let ` can only begin a statement, not an expression.
143+
144+ Note that assigning to an already-bound variable (e.g. ` y = 5 ` ) is still an
145+ expression, although its value is not particularly useful. Unlike other
146+ languages where an assignment evaluates to the assigned value (e.g. ` 5 ` in the
147+ previous example), in Rust the value of an assignment is an empty tuple ` () ` :
148+
149+ ```
150+ let mut y = 5;
151+
152+ let x = (y = 6); // x has the value `()`, not `6`
153+ ```
154+
155+ The second kind of statement in Rust is the * expression statement* . Its
156+ purpose is to turn any expression into a statement. In practical terms, Rust's
157+ grammar expects statements to follow other statements. This means that you use
158+ semicolons to separate expressions from each other. This means that Rust
159+ looks a lot like most other languages that require you to use semicolons
160+ at the end of every line, and you will see semicolons at the end of almost
161+ every line of Rust code you see.
129162
163+ What is this exception that makes us say "almost"? You saw it already, in this
164+ code:
165+
166+ ``` rust
167+ fn add_one (x : i32 ) -> i32 {
130168 x + 1
131169}
132170```
133171
134- Using a ` return ` as the last line of a function works, but is considered poor
135- style:
172+ Our function claims to return an ` i32 ` , but with a semicolon, it would return
173+ ` () ` instead. Rust realizes this probably isn’t what we want, and suggests
174+ removing the semicolon in the error we saw before.
175+
176+ ## Early returns
177+
178+ But what about early returns? Rust does have a keyword for that, ` return ` :
136179
137180``` rust
138181fn foo (x : i32 ) -> i32 {
139- if x < 5 { return x ; }
182+ return x ;
140183
141- return x + 1 ;
184+ // we never run this code!
185+ x + 1
142186}
143187```
144188
145- The previous definition without ` return ` may look a bit strange if you haven't
146- worked in an expression-based language before, but it becomes intuitive over
147- time. If this were production code, we wouldn't write it in that way anyway,
148- we'd write this:
189+ Using a ` return ` as the last line of a function works, but is considered poor
190+ style:
149191
150192``` rust
151193fn foo (x : i32 ) -> i32 {
152- if x < 5 {
153- x
154- } else {
155- x + 1
156- }
194+ return x + 1 ;
157195}
158196```
159197
160- Because ` if ` is an expression, and it's the only expression in this function,
161- the value will be the result of the ` if ` .
198+ The previous definition without ` return ` may look a bit strange if you haven’t
199+ worked in an expression-based language before, but it becomes intuitive over
200+ time.
162201
163202## Diverging functions
164203
165- Rust has some special syntax for ' diverging functions' , which are functions that
204+ Rust has some special syntax for ‘ diverging functions’ , which are functions that
166205do not return:
167206
168207```
@@ -171,23 +210,18 @@ fn diverges() -> ! {
171210}
172211```
173212
174- ` panic! ` is a macro, similar to ` println!() ` that we' ve already seen. Unlike
213+ ` panic! ` is a macro, similar to ` println!() ` that we’ ve already seen. Unlike
175214` println!() ` , ` panic!() ` causes the current thread of execution to crash with
176215the given message.
177216
178217Because this function will cause a crash, it will never return, and so it has
179- the type ' ` ! ` ' , which is read " diverges." A diverging function can be used
218+ the type ‘ ` ! ` ’ , which is read ‘ diverges’. A diverging function can be used
180219as any type:
181220
182221``` should_panic
183222# fn diverges() -> ! {
184223# panic!("This function never returns!");
185224# }
186-
187225let x: i32 = diverges();
188226let x: String = diverges();
189227```
190-
191- We don't have a good use for diverging functions yet, because they're used in
192- conjunction with other Rust features. But when you see ` -> ! ` later, you'll
193- know what it's called.
0 commit comments