// a garbage collector) or vice versa. Rust can run without dynamic allocation (i.e., without
// a heap), and even without an operating system. In fact, Rust rules out more classes of bugs
// than languages that achieve safety with a garbage collector: Besides dangling pointers and
-// double-free, Rust also prevents issues such as iterator invalidation and data races.
+// double-free, Rust also prevents issues such as iterator invalidation and data races. Finally,
+// it cleans up behind you, and deallocates resources (memory, but also file descriptors and really
+// anything) when you don't need them anymore.
//
//
// Getting started
// Now we want to *iterate* over the list. Rust has some nice syntax for iterators:
for el in vec {
- // So `el` is al element of the list. We need to update `min` accordingly, but how do we get the current
+ // So `el` is an element of the list. We need to update `min` accordingly, but how do we get the current
// number in there? This is what pattern matching can do:
match min {
// In this case (*arm*) of the `match`, `min` is currently nothing, so let's just make it the number `el`.
min = NumberOrNothing::Number(new_min); /*@*/
}
}
+ //@ Notice that Rust makes sure you did not forget to handle any case in your `match`. We say
+ //@ that the pattern matching has to be *exhaustive*.
}
// Finally, we return the result of the computation.
return min;
// Indeed, we can: The following line tells Rust to take
// the constructors of `NumberOrNothing` into the local namespace.
-// Try moving that above the function, and removing all the occurrences `NumberOrNothing::`.
+// Try moving that above the function, and removing all the occurrences of `NumberOrNothing::`.
use self::NumberOrNothing::{Number,Nothing};
// To call this function, we now just need a list. Of course, ultimately we want to ask the user for
// a list of numbers, but for now, let's just hard-code something.
-//@ `vec!` is a *macro* (as you can tell from the `!`) that constructs a constant `Vec<_>` with the given
+//@ `vec!` is a *macro* (as indicated by `!`) that constructs a constant `Vec<_>` with the given
//@ elements.
fn read_vec() -> Vec<i32> {
vec![18,5,7,1,9,27] /*@*/
// Finally, try `cargo run` on the console to run it.
//@ Yay, it said "1"! That's actually the right answer. Okay, we could have
-//@ computed that ourselves, but that's besides the point. More importantly:
+//@ computed that ourselves, but that's beside the point. More importantly:
//@ You completed the first part of the course.
//@ [index](main.html) | previous | [raw source](https://www.ralfj.de/git/rust-101.git/blob_plain/HEAD:/workspace/src/part00.rs) | [next](part01.html)
//@ So we can just write `i * i`, the expression that returns the square if `i`!
//@ This is very close to how mathematicians write down functions (but with more types).
-// Conditionals are also just expressions. You can compare this to the ternary `? :` operator
+// Conditionals are also just expressions. This is comparable to the ternary `? :` operator
// from languages like C.
fn abs(i: i32) -> i32 { if i >= 0 { i } else { -i } }
fn vec_min(v: Vec<i32>) -> NumberOrNothing {
//@ Remember that helper function `min_i32`? Rust allows us to define such helper functions *inside* other
//@ functions. This is just a matter of namespacing, the inner function has no access to the data of the outer
- //@ one. Still, being able to nicely group functions can be very useful.
+ //@ one. Still, being able to nicely group functions can significantly increase readability.
fn min_i32(a: i32, b: i32) -> i32 {
if a < b { a } else { b } /*@*/
}
// You will have to replace `part00` by `part01` in the `main` function in
// `main.rs` to run this code.
-// **Exercise 01.1**: Write a funtion `vec_sum` that computes the sum of all values of a `Vec<i32>`.
+// **Exercise 01.1**: Write a function `vec_sum` that computes the sum of all values of a `Vec<i32>`.
// **Exercise 01.2**: Write a function `vec_print` that takes a vector and prints all its elements.
//@ `SomethingOrNothing<i32>` to get back our `NumberOrNothing`.
type NumberOrNothing = SomethingOrNothing<i32>;
//@ However, we can also write `SomethingOrNothing<bool>` or even `SomethingOrNothing<SomethingOrNothing<i32>>`.
-//@ In fact, such a type is so useful that it is already present in the standard library: It's called an
+//@ In fact, a type like `SomethingOrNothing` is so useful that it is already present in the standard library: It's called an
//@ *option type*, written `Option<T>`. Go check out its [documentation](https://doc.rust-lang.org/stable/std/option/index.html)!
-//@ (And don't worry, there's indeed lots of material mentioned there that we did not cover yet.)
+//@ (And don't worry, there's indeed lots of material mentioned there that we have not covered yet.)
// ## Generic `impl`, Static functions
//@ The types are so similar, that we can provide a generic function to construct a `SomethingOrNothing<T>`
}
// ## Traits
-//@ Now that we have a generic `SomethingOrNothing`, wouldn't it be nice to also gave a generic
+//@ Now that we have a generic `SomethingOrNothing`, wouldn't it be nice to also have a generic
//@ `vec_min`? Of course, we can't take the minimum of a vector of *any* type. It has to be a type
//@ supporting a `min` operation. Rust calls such properties that we may demand of types *traits*.
//@ 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. <br/>
-//@ The function `min` takes to arguments of the same type, but I made the
+//@ The function `min` takes two arguments of the same type, but I made the
//@ first argument the special `self` argument. I could, alternatively, have
//@ made `min` a static function as follows: `fn min(a: Self, b: Self) -> Self`.
-//@ However, in Rust one typically prefers methods over static function wherever possible.
+//@ However, in Rust one typically prefers methods over static functions wherever possible.
pub trait Minimum : Copy {
fn min(self, b: Self) -> Self;
}
//@ Before going on, take a moment to ponder the flexibility of Rust's take on abstraction:
//@ We just defined our own, custom trait (interface), and then implemented that trait
//@ *for an existing type*. With the hierarchical approach of, e.g., C++ or Java,
-//@ that's not possible: We cannot make an existing type suddenly also inherit from our abstract base class.
+//@ that's not possible: We cannot make an existing type also inherit from our abstract base class after the fact.
//@
//@ In case you are worried about performance, note that Rust performs *monomorphisation*
//@ of generic functions: When you call `vec_min` with `T` being `i32`, Rust essentially goes
// Now we want to *iterate* over the list. Rust has some nice syntax for iterators:
for el in vec {
- // So `el` is al element of the list. We need to update `min` accordingly, but how do we get the current
+ // So `el` is an element of the list. We need to update `min` accordingly, but how do we get the current
// number in there? This is what pattern matching can do:
match min {
// In this case (*arm*) of the `match`, `min` is currently nothing, so let's just make it the number `el`.
// Indeed, we can: The following line tells Rust to take
// the constructors of `NumberOrNothing` into the local namespace.
-// Try moving that above the function, and removing all the occurrences `NumberOrNothing::`.
+// Try moving that above the function, and removing all the occurrences of `NumberOrNothing::`.
use self::NumberOrNothing::{Number,Nothing};
// To call this function, we now just need a list. Of course, ultimately we want to ask the user for
// ## Expression-based programming
fn sqr(i: i32) -> i32 { i * i }
-// Conditionals are also just expressions. You can compare this to the ternary `? :` operator
+// Conditionals are also just expressions. This is comparable to the ternary `? :` operator
// from languages like C.
fn abs(i: i32) -> i32 { if i >= 0 { i } else { -i } }
// You will have to replace `part00` by `part01` in the `main` function in
// `main.rs` to run this code.
-// **Exercise 01.1**: Write a funtion `vec_sum` that computes the sum of all values of a `Vec<i32>`.
+// **Exercise 01.1**: Write a function `vec_sum` that computes the sum of all values of a `Vec<i32>`.
// **Exercise 01.2**: Write a function `vec_print` that takes a vector and prints all its elements.