@@ -515,9 +515,45 @@ let x: int = 5;
515
515
```
516
516
517
517
If I asked you to read this out loud to the rest of the class, you'd say "` x `
518
- is a binding with the type ` int ` and the value ` five ` ." Rust requires you to
519
- initialize the binding with a value before you're allowed to use it. If
520
- we try...
518
+ is a binding with the type ` int ` and the value ` five ` ."
519
+
520
+ By default, bindings are ** immutable** . This code will not compile:
521
+
522
+ ``` {ignore}
523
+ let x = 5i;
524
+ x = 10i;
525
+ ```
526
+
527
+ It will give you this error:
528
+
529
+ ``` {ignore,notrust}
530
+ error: re-assignment of immutable variable `x`
531
+ x = 10i;
532
+ ^~~~~~~
533
+ ```
534
+
535
+ If you want a binding to be mutable, you can use ` mut ` :
536
+
537
+ ``` {rust}
538
+ let mut x = 5i;
539
+ x = 10i;
540
+ ```
541
+
542
+ There is no single reason that bindings are immutable by default, but we can
543
+ think about it through one of Rust's primary focuses: safety. If you forget to
544
+ say ` mut ` , the compiler will catch it, and let you know that you have mutated
545
+ something you may not have cared to mutate. If bindings were mutable by
546
+ default, the compiler would not be able to tell you this. If you _ did_ intend
547
+ mutation, then the solution is quite easy: add ` mut ` .
548
+
549
+ There are other good reasons to avoid mutable state when possible, but they're
550
+ out of the scope of this guide. In general, you can often avoid explicit
551
+ mutation, and so it is preferable in Rust. That said, sometimes, mutation is
552
+ what you need, so it's not verboten.
553
+
554
+ Let's get back to bindings. Rust variable bindings have one more aspect that
555
+ differs from other languages: bindings are required to be initialized with a
556
+ value before you're allowed to use it. If we try...
521
557
522
558
``` {ignore}
523
559
let x;
@@ -611,8 +647,301 @@ concept: `if`.
611
647
612
648
## If
613
649
650
+ Rust's take on ` if ` is not particularly complex, but it's much more like the
651
+ ` if ` you'll find in a dynamically typed language than in a more traditional
652
+ systems language. So let's talk about it, to make sure you grasp the nuances.
653
+
654
+ ` if ` is a specific form of a more general concept, the 'branch.' The name comes
655
+ from a branch in a tree: a decision point, where depending on a choice,
656
+ multiple paths can be taken.
657
+
658
+ In the case of ` if ` , there is one choice that leads down two paths:
659
+
660
+ ``` rust
661
+ let x = 5i ;
662
+
663
+ if x == 5i {
664
+ println! (" x is five!" );
665
+ }
666
+ ```
667
+
668
+ If we changed the value of ` x ` to something else, this line would not print.
669
+ More specifically, if the expression after the ` if ` evaluates to ` true ` , then
670
+ the block is executed. If it's ` false ` , then it is not.
671
+
672
+ If you want something to happen in the ` false ` case, use an ` else ` :
673
+
674
+ ```
675
+ let x = 5i;
676
+
677
+ if x == 5i {
678
+ println!("x is five!");
679
+ } else {
680
+ println!("x is not five :(");
681
+ }
682
+ ```
683
+
684
+ This is all pretty standard. However, you can also do this:
685
+
686
+
687
+ ```
688
+ let x = 5i;
689
+
690
+ let y = if x == 5i {
691
+ 10i
692
+ } else {
693
+ 15i
694
+ };
695
+ ```
696
+
697
+ Which we can (and probably should) write like this:
698
+
699
+ ```
700
+ let x = 5i;
701
+
702
+ let y = if x == 5i { 10i } else { 15i };
703
+ ```
704
+
705
+ This reveals two interesting things about Rust: it is an expression-based
706
+ language, and semicolons are different than in other 'curly brace and
707
+ semicolon'-based languages. These two things are related.
708
+
709
+ ### Expressions vs. Statements
710
+
711
+ Rust is primarily an expression based language. There are only two kinds of
712
+ statements, and everything else is an expression.
713
+
714
+ So what's the difference? Expressions return a value, and statements do not.
715
+ In many languages, ` if ` is a statement, and therefore, ` let x = if ... ` would
716
+ make no sense. But in Rust, ` if ` is an expression, which means that it returns
717
+ a value. We can then use this value to initialize the binding.
718
+
719
+ Speaking of which, bindings are a kind of the first of Rust's two statements.
720
+ The proper name is a ** declaration statement** . So far, ` let ` is the only kind
721
+ of declaration statement we've seen. Let's talk about that some more.
722
+
723
+ In some languages, variable bindings can be written as expressions, not just
724
+ statements. Like Ruby:
725
+
726
+ ``` {ruby}
727
+ x = y = 5
728
+ ```
729
+
730
+ In Rust, however, using ` let ` to introduce a binding is _ not_ an expression. The
731
+ following will produce a compile-time error:
732
+
733
+ ``` {ignore}
734
+ let x = (let y = 5i); // found `let` in ident position
735
+ ```
736
+
737
+ The compiler is telling us here that it was expecting to see the beginning of
738
+ an expression, and a ` let ` can only begin a statement, not an expression.
739
+
740
+ However, re-assigning to a mutable binding is an expression:
741
+
742
+ ``` {rust}
743
+ let mut x = 0i;
744
+ let y = x = 5i;
745
+ ```
746
+
747
+ In this case, we have an assignment expression (` x = 5 ` ) whose value is
748
+ being used as part of a ` let ` declaration statement (` let y = ... ` ).
749
+
750
+ The second kind of statement in Rust is the ** expression statement** . Its
751
+ purpose is to turn any expression into a statement. In practical terms, Rust's
752
+ grammar expects statements to follow other statements. This means that you use
753
+ semicolons to separate expressions from each other. This means that Rust
754
+ looks a lot like most other languages that require you to use semicolons
755
+ at the end of every line, and you will see semicolons at the end of almost
756
+ every line of Rust code you see.
757
+
758
+ What is this exception that makes us say 'almost?' You saw it already, in this
759
+ code:
760
+
761
+ ```
762
+ let x = 5i;
763
+
764
+ let y: int = if x == 5i { 10i } else { 15i };
765
+ ```
766
+
767
+ Note that I've added the type annotation to ` y ` , to specify explicitly that I
768
+ want ` y ` to be an integer.
769
+
770
+ This is not the same as this, which won't compile:
771
+
772
+ ``` {ignore}
773
+ let x = 5i;
774
+
775
+ let y: int = if x == 5 { 10i; } else { 15i; };
776
+ ```
777
+
778
+ Note the semicolons after the 10 and 15. Rust will give us the following error:
779
+
780
+ ``` {ignore,notrust}
781
+ error: mismatched types: expected `int` but found `()` (expected int but found ())
782
+ ```
783
+
784
+ We expected an integer, but we got ` () ` . ` () ` is pronounced 'unit', and is a
785
+ special type in Rust's type system. ` () ` is different than ` null ` in other
786
+ languages, because ` () ` is distinct from other types. For example, in C, ` null `
787
+ is a valid value for a variable of type ` int ` . In Rust, ` () ` is _ not_ a valid
788
+ value for a variable of type ` int ` . It's only a valid value for variables of
789
+ the type ` () ` , which aren't very useful. Remember how we said statements don't
790
+ return a value? Well, that's the purpose of unit in this case. The semicolon
791
+ turns any expression into a statement by throwing away its value and returning
792
+ unit instead.
793
+
794
+ There's one more time in which you won't see a semicolon at the end of a line
795
+ of Rust code. For that, we'll need our next concept: functions.
796
+
614
797
## Functions
615
798
799
+ You've already seen one function so far, the ` main ` function:
800
+
801
+ ``` {rust}
802
+ fn main() {
803
+ }
804
+ ```
805
+
806
+ This is the simplest possible function declaration. As we mentioned before,
807
+ ` fn ` says 'this is a function,' followed by the name, some parenthesis because
808
+ this function takes no arguments, and then some curly braces to indicate the
809
+ body. Here's a function named ` foo ` :
810
+
811
+ ``` {rust}
812
+ fn foo() {
813
+ }
814
+ ```
815
+
816
+ So, what about taking arguments? Here's a function that prints a number:
817
+
818
+ ``` {rust}
819
+ fn print_number(x: int) {
820
+ println!("x is: {}", x);
821
+ }
822
+ ```
823
+
824
+ Here's a complete program that uses ` print_number ` :
825
+
826
+ ``` {rust}
827
+ fn main() {
828
+ print_number(5);
829
+ }
830
+
831
+ fn print_number(x: int) {
832
+ println!("x is: {}", x);
833
+ }
834
+ ```
835
+
836
+ As you can see, function arguments work very similar to ` let ` declarations:
837
+ you add a type to the argument name, after a colon.
838
+
839
+ Here's a complete program that adds two numbers together and prints them:
840
+
841
+ ``` {rust}
842
+ fn main() {
843
+ print_sum(5, 6);
844
+ }
845
+
846
+ fn print_sum(x: int, y: int) {
847
+ println!("sum is: {}", x + y);
848
+ }
849
+ ```
850
+
851
+ You separate arguments with a comma, both when you call the function, as well
852
+ as when you declare it.
853
+
854
+ Unlike ` let ` , you _ must_ declare the types of function arguments. This does
855
+ not work:
856
+
857
+ ``` {ignore}
858
+ fn print_number(x, y) {
859
+ println!("x is: {}", x + y);
860
+ }
861
+ ```
862
+
863
+ You get this error:
864
+
865
+ ``` {ignore,notrust}
866
+ hello.rs:5:18: 5:19 error: expected `:` but found `,`
867
+ hello.rs:5 fn print_number(x, y) {
868
+ ```
869
+
870
+ This is a deliberate design decision. While full-program inference is possible,
871
+ languages which have it, like Haskell, often suggest that documenting your
872
+ types explicitly is a best-practice. We agree that forcing functions to declare
873
+ types while allowing for inference inside of function bodies is a wonderful
874
+ compromise between full inference and no inference.
875
+
876
+ What about returning a value? Here's a function that adds one to an integer:
877
+
878
+ ``` {rust}
879
+ fn add_one(x: int) -> int {
880
+ x + 1
881
+ }
882
+ ```
883
+
884
+ Rust functions return exactly one value, and you declare the type after an
885
+ 'arrow', which is a dash (` - ` ) followed by a greater-than sign (` > ` ).
886
+
887
+ You'll note the lack of a semicolon here. If we added it in:
888
+
889
+ ``` {ignore}
890
+ fn add_one(x: int) -> int {
891
+ x + 1;
892
+ }
893
+ ```
894
+
895
+ We would get an error:
896
+
897
+ ``` {ignore,notrust}
898
+ note: consider removing this semicolon:
899
+ x + 1;
900
+ ^
901
+ error: not all control paths return a value
902
+ fn add_one(x: int) -> int {
903
+ x + 1;
904
+ }
905
+ ```
906
+
907
+ Remember our earlier discussions about semicolons and ` () ` ? Our function claims
908
+ to return an ` int ` , but with a semicolon, it would return ` () ` instead. Rust
909
+ realizes this probably isn't what we want, and suggests removing the semicolon.
910
+
911
+ This is very much like our ` if ` statement before: the result of the block
912
+ (` {} ` ) is the value of the expression. Other expression-oriented languages,
913
+ such as Ruby, work like this, but it's a bit unusual in the systems programming
914
+ world. When people first learn about this, they usually assume that it
915
+ introduces bugs. But because Rust's type system is so strong, and because unit
916
+ is its own unique type, we have never seen an issue where adding or removing a
917
+ semicolon in a return position would cause a bug.
918
+
919
+ But what about early returns? Rust does have a keyword for that, ` return ` :
920
+
921
+ ``` {rust}
922
+ fn foo(x: int) -> int {
923
+ if x < 5 { return x; }
924
+
925
+ x + 1
926
+ }
927
+ ```
928
+
929
+ Using a ` return ` as the last line of a function works, but is considered poor
930
+ style:
931
+
932
+ ``` {rust}
933
+ fn foo(x: int) -> int {
934
+ if x < 5 { return x; }
935
+
936
+ return x + 1;
937
+ }
938
+ ```
939
+
940
+ There are some additional ways to define functions, but they involve features
941
+ that we haven't learned about yet, so let's just leave it at that for now.
942
+
943
+ ## Comments
944
+
616
945
return
617
946
618
947
comments
0 commit comments