@@ -611,6 +611,153 @@ concept: `if`.
611
611
612
612
## If
613
613
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
+
614
761
## Functions
615
762
616
763
return
0 commit comments