Skip to content

Commit 748b947

Browse files
steveklabnikalexcrichton
authored andcommitted
Guide: if
1 parent 524f469 commit 748b947

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed

src/doc/guide.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,153 @@ concept: `if`.
611611

612612
## If
613613

614+
Rust's take on `if` is not particularly complex, but it's much more like the
615+
`if` you'll find in a dynamically typed language than in a more traditional
616+
systems language. So let's talk about it, to make sure you grasp the nuances.
617+
618+
`if` is a specific form of a more general concept, the 'branch.' The name comes
619+
from a branch in a tree: a decision point, where depending on a choice,
620+
multiple paths can be taken.
621+
622+
In the case of `if`, there is one choice that leads down two paths:
623+
624+
```rust
625+
let x = 5i;
626+
627+
if x == 5i {
628+
println!("x is five!");
629+
}
630+
```
631+
632+
If we changed the value of `x` to something else, this line would not print.
633+
More specifically, if the expression after the `if` evaluates to `true`, then
634+
the block is executed. If it's `false`, then it is not.
635+
636+
If you want something to happen in the `false` case, use an `else`:
637+
638+
```
639+
let x = 5i;
640+
641+
if x == 5i {
642+
println!("x is five!");
643+
} else {
644+
println!("x is not five :(");
645+
}
646+
```
647+
648+
This is all pretty standard. However, you can also do this:
649+
650+
651+
```
652+
let x = 5i;
653+
654+
let y = if x == 5i {
655+
10i
656+
} else {
657+
15i
658+
};
659+
```
660+
661+
Which we can (and probably should) write like this:
662+
663+
```
664+
let x = 5i;
665+
666+
let y = if x == 5i { 10i } else { 15i };
667+
```
668+
669+
This reveals two interesting things about Rust: it is an expression-based
670+
language, and semicolons are different than in other 'curly brace and
671+
semicolon'-based languages. These two things are related.
672+
673+
### Expressions vs. Statements
674+
675+
Rust is primarily an expression based language. There are only two kinds of
676+
statements, and everything else is an expression.
677+
678+
So what's the difference? Expressions return a value, and statements do not.
679+
In many languages, `if` is a statement, and therefore, `let x = if ...` would
680+
make no sense. But in Rust, `if` is an expression, which means that it returns
681+
a value. We can then use this value to initialize the binding.
682+
683+
Speaking of which, bindings are a kind of the first of Rust's two statements.
684+
The proper name is a **declaration statement**. So far, `let` is the only kind
685+
of declaration statement we've seen. Let's talk about that some more.
686+
687+
In some languages, variable bindings can be written as expressions, not just
688+
statements. Like Ruby:
689+
690+
```{ruby}
691+
x = y = 5
692+
```
693+
694+
In Rust, however, using `let` to introduce a binding is _not_ an expression. The
695+
following will produce a compile-time error:
696+
697+
```{ignore}
698+
let x = (let y = 5i); // found `let` in ident position
699+
```
700+
701+
The compiler is telling us here that it was expecting to see the beginning of
702+
an expression, and a `let` can only begin a statement, not an expression.
703+
704+
However, re-assigning to a mutable binding is an expression:
705+
706+
```{rust}
707+
let mut x = 0i;
708+
let y = x = 5i;
709+
```
710+
711+
In this case, we have an assignment expression (`x = 5`) whose value is
712+
being used as part of a `let` declaration statement (`let y = ...`).
713+
714+
The second kind of statement in Rust is the **expression statement**. Its
715+
purpose is to turn any expression into a statement. In practical terms, Rust's
716+
grammar expects statements to follow other statements. This means that you use
717+
semicolons to separate expressions from each other. This means that Rust
718+
looks a lot like most other languages that require you to use semicolons
719+
at the end of every line, and you will see semicolons at the end of almost
720+
every line of Rust code you see.
721+
722+
What is this exception that makes us say 'almost?' You saw it already, in this
723+
code:
724+
725+
```
726+
let x = 5i;
727+
728+
let y: int = if x == 5i { 10i } else { 15i };
729+
```
730+
731+
Note that I've added the type annotation to `y`, to specify explicitly that I
732+
want `y` to be an integer.
733+
734+
This is not the same as this, which won't compile:
735+
736+
```{ignore}
737+
let x = 5i;
738+
739+
let y: int = if x == 5 { 10i; } else { 15i; };
740+
```
741+
742+
Note the semicolons after the 10 and 15. Rust will give us the following error:
743+
744+
```{ignore,notrust}
745+
error: mismatched types: expected `int` but found `()` (expected int but found ())
746+
```
747+
748+
We expected an integer, but we got `()`. `()` is pronounced 'unit', and is a
749+
special type in Rust's type system. `()` is different than `null` in other
750+
languages, because `()` is distinct from other types. For example, in C, `null`
751+
is a valid value for a variable of type `int`. In Rust, `()` is _not_ a valid
752+
value for a variable of type `int`. It's only a valid value for variables of
753+
the type `()`, which aren't very useful. Remember how we said statements don't
754+
return a value? Well, that's the purpose of unit in this case. The semicolon
755+
turns any expression into a statement by throwing away its value and returning
756+
unit instead.
757+
758+
There's one more time in which you won't see a semicolon at the end of a line
759+
of Rust code. For that, we'll need our next concept: functions.
760+
614761
## Functions
615762

616763
return

0 commit comments

Comments
 (0)