From: Ralf Jung Date: Sat, 13 Jun 2015 11:58:20 +0000 (+0200) Subject: work on Intro; import code from previous parts where appropriate X-Git-Url: https://git.ralfj.de/rust-101.git/commitdiff_plain/3dc9d065dfa259c88b3109717e2c6f6e65a45cc4?ds=inline;hp=315bf91eb0b309b29c732ca7726df1f6ca9f567e work on Intro; import code from previous parts where appropriate --- diff --git a/src/main.rs b/src/main.rs index e151dc1..b093780 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,24 @@ // // I will assume some familiarity with programming, and hence not explain the basic // concepts common to most languages. Instead, I will focus on what makes Rust special. +// +// Why Rust? +// --------- +// +// When you got here, I am kind of assuming that you already decided to give Rust at +// least a look, so that I don't have to do much convincing here ;-) . But just in +// case, here's why I think Rust is worth learning:
+// At this time, Rust is a language with a pretty unique set of goals. Rust aims to +// achieve C++-style control over memory and execution behavior (like, static vs. dynamic +// dispatch), which makes it possible to construct abstractions that carry no run-time +// cost. This is combined this with providing the comfort of high-level functional languages +// and guaranteeing safety (as in, the program will not crash). The vast majority of existing +// languages sacrificies one of these goals for the other. In particular, the +// first requirement rules out a garbage collector: Rust can run "mare metal". +// In fact, Rust rules out more classes of bugs than languages that achieve safety +// with a GC: Besides dangling pointers and double-free, Rust also prevents issues +// such as iterator invalidation and race conditions. +// // // Prerequisites // ------------- @@ -39,19 +57,27 @@ // Course Content // -------------- // -// The actual course is in the partXX.rs files. I suggest you get started with -// [the first part](part00.html), or jump directly to where you left off: +// The actual course is in the partXX.rs files. The part 00-03 cover some basic of the language, +// to give you a feeling for Rust's syntax and pervasive mechanisms like pattern matching and traits. +// Parts 04-?? introduce the heart of the language, the mechanism making it different from anything +// else out there. +// +// I suggest you get started with [the first part](part00.html), or jump directly to where you left off: // // * [Part 00](part00.html) // * [Part 01](part01.html) // * [Part 02](part02.html) // * [Part 03](part03.html) +// * [Part 04](part04.html) (WIP) // * (to be continued) #![allow(dead_code, unused_imports, unused_variables)] mod part00; mod part01; mod part02; mod part03; +mod part04; +mod part05; +mod part06; // To actually run the code of some part (after filling in the blanks, if necessary), simply edit the `main` // function. diff --git a/src/part02.rs b/src/part02.rs index 51c20cf..dc885c0 100644 --- a/src/part02.rs +++ b/src/part02.rs @@ -12,11 +12,12 @@ use std; // meaning "many shapes"). You may know something similar from C++ (where it's called // *templates*) or Java, or one of the many functional languages. So here, we define // a generic type `SomethingOrNothing`. -enum SomethingOrNothing { +pub enum SomethingOrNothing { Something(T), Nothing, } -use self::SomethingOrNothing::{Something,Nothing}; +// Instead of writing out all the variants, we can also just import them all at once. +pub use self::SomethingOrNothing::*; // What this does is to define an entire family of types: We can now write // `SomethingOrNothing` to get back our `NumberOrNothing`, but we // can also write `SomethingOrNothing` or even `SomethingOrNothing>`. @@ -64,7 +65,7 @@ fn call_constructor(x: i32) -> SomethingOrNothing { // For now, just ignore the `Copy`, we will come back to this point later. // A `trait` is a lot like interfaces in Java: You define a bunch of functions // you want to have implemented, and their argument and return types. -trait Minimum : Copy { +pub trait Minimum : Copy { fn min(a: Self, b: Self) -> Self; } @@ -78,7 +79,7 @@ trait Minimum : Copy { // we cannot call `min`. Just try it! There is no reason to believe that `T` provides such an operation. // This is in strong contrast to C++, where the compiler only checks such details when the // function is actually used. -fn vec_min(v: Vec) -> SomethingOrNothing { +pub fn vec_min(v: Vec) -> SomethingOrNothing { let mut min = Nothing; for e in v { min = Something(match min { @@ -100,7 +101,7 @@ impl Minimum for i32 { // This also shows that we can have multiple `impl` blocks for the same type, and we // can provide some methods only for certain instances of a generic type. impl SomethingOrNothing { - fn print(self) { + pub fn print(self) { match self { Nothing => println!("The number is: "), Something(n) => println!("The number is: {}", n), diff --git a/src/part03.rs b/src/part03.rs index a7cfb1a..c468555 100644 --- a/src/part03.rs +++ b/src/part03.rs @@ -62,46 +62,11 @@ fn read_vec() -> Vec { // So much for `read_vec`. If there are any questions left, the documentation of the respective function // should be very helpful. I will not always provide the links, as the documentation is quite easy to navigate // and you should get used to that. -// -// The rest of the code dosn't change, so we just copy it. - -enum SomethingOrNothing { - Something(T), - Nothing, -} -use self::SomethingOrNothing::{Something,Nothing}; - -trait Minimum : Copy { - fn min(a: Self, b: Self) -> Self; -} - -fn vec_min(v: Vec) -> SomethingOrNothing { - let mut min = Nothing; - for e in v { - min = Something(match min { - Nothing => e, - Something(n) => T::min(n, e) - }); - } - min -} - -// `::std::cmp::min` is a way to refer to this function without importing `std`. -// We could also have done `use std::cmp;` and later called `cmp::min`. Try that! -impl Minimum for i32 { - fn min(a: Self, b: Self) -> Self { - ::std::cmp::min(a, b) - } -} -impl SomethingOrNothing { - fn print(self) { - match self { - Nothing => println!("The number is: "), - Something(n) => println!("The number is: {}", n), - }; - } -} +// For the rest of the code, we just re-use part 02 by importing it with `use`. +// I already sneaked a bunch of `pub` in the other module to make this possible: Only +// items declared public can be imported elsewhere. +use part02::{SomethingOrNothing,Something,Nothing,vec_min}; // If you update your `main.rs` to use part 03, `cargo run` should now ask you for some numbers, // and tell you the minimum. Neat, isn't it? @@ -123,7 +88,7 @@ pub fn main() { // as testing whether `(self, other)` is `(Nothing, Nothing)`, which is the case exactly if // both `self` and `other` are `Nothing`. Similar so for the second arm. impl SomethingOrNothing { - fn equals(self, other: Self) -> bool { + pub fn equals(self, other: Self) -> bool { match (self, other) { (Nothing , Nothing ) => true, (Something(n), Something(m)) => n == m, @@ -163,4 +128,4 @@ fn test_vec_min() { // *Hint*: You can figure out the trait bound `read_vec` needs from the documentation of `String::parse`. // Furthermore, `std::cmp::min` works not just for `i32`, but also for `f32`. -// [index](main.html) | [previous](part02.html) | next +// [index](main.html) | [previous](part02.html) | [next](part04.html)