Skip to content

Commit

Permalink
Merge pull request #1651 from adrian5/cleanup
Browse files Browse the repository at this point in the history
Clean up Chapter 2 (Primitives)
  • Loading branch information
marioidival authored Dec 21, 2022
2 parents 995df09 + 29ee37f commit 251eeb2
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 97 deletions.
38 changes: 19 additions & 19 deletions src/primitives.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,27 @@

Rust provides access to a wide variety of `primitives`. A sample includes:


### Scalar Types

* signed integers: `i8`, `i16`, `i32`, `i64`, `i128` and `isize` (pointer size)
* unsigned integers: `u8`, `u16`, `u32`, `u64`, `u128` and `usize` (pointer
* Signed integers: `i8`, `i16`, `i32`, `i64`, `i128` and `isize` (pointer size)
* Unsigned integers: `u8`, `u16`, `u32`, `u64`, `u128` and `usize` (pointer
size)
* floating point: `f32`, `f64`
* Floating point: `f32`, `f64`
* `char` Unicode scalar values like `'a'`, `'α'` and `'∞'` (4 bytes each)
* `bool` either `true` or `false`
* and the unit type `()`, whose only possible value is an empty tuple: `()`
* The unit type `()`, whose only possible value is an empty tuple: `()`

Despite the value of a unit type being a tuple, it is not considered a
compound type because it does not contain multiple values.
Despite the value of a unit type being a tuple, it is not considered a compound
type because it does not contain multiple values.

### Compound Types

* arrays like `[1, 2, 3]`
* tuples like `(1, true)`
* Arrays like `[1, 2, 3]`
* Tuples like `(1, true)`

Variables can always be *type annotated*. Numbers may additionally be
annotated via a *suffix* or *by default*. Integers default to `i32` and
floats to `f64`. Note that Rust can also infer types from context.
Variables can always be *type annotated*. Numbers may additionally be annotated
via a *suffix* or *by default*. Integers default to `i32` and floats to `f64`.
Note that Rust can also infer types from context.

```rust,editable,ignore,mdbook-runnable
fn main() {
Expand All @@ -36,26 +35,27 @@ fn main() {
// Or a default will be used.
let default_float = 3.0; // `f64`
let default_integer = 7; // `i32`
// A type can also be inferred from context
let mut inferred_type = 12; // Type i64 is inferred from another line
// A type can also be inferred from context.
let mut inferred_type = 12; // Type i64 is inferred from another line.
inferred_type = 4294967296i64;
// A mutable variable's value can be changed.
let mut mutable = 12; // Mutable `i32`
mutable = 21;
// Error! The type of a variable can't be changed.
mutable = true;
// Variables can be overwritten with shadowing.
let mutable = true;
}
```

### See also:

[the `std` library][std], [`mut`][mut], [`inference`][inference], and [`shadowing`][shadowing]
[the `std` library][std], [`mut`][mut], [`inference`][inference], and
[`shadowing`][shadowing]

[std]: https://doc.rust-lang.org/std/
[mut]: variable_bindings/mut.md
Expand Down
55 changes: 27 additions & 28 deletions src/primitives/array.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,66 +5,65 @@ memory. Arrays are created using brackets `[]`, and their length, which is known
at compile time, is part of their type signature `[T; length]`.

Slices are similar to arrays, but their length is not known at compile time.
Instead, a slice is a two-word object, the first word is a pointer to the data,
and the second word is the length of the slice. The word size is the same as
usize, determined by the processor architecture e.g. 64 bits on an x86-64.
Slices can be used to borrow a section of an array, and have the type signature
`&[T]`.
Instead, a slice is a two-word object; the first word is a pointer to the data,
the second word the length of the slice. The word size is the same as usize,
determined by the processor architecture, e.g. 64 bits on an x86-64. Slices can
be used to borrow a section of an array and have the type signature `&[T]`.

```rust,editable,ignore,mdbook-runnable
use std::mem;
// This function borrows a slice
// This function borrows a slice.
fn analyze_slice(slice: &[i32]) {
println!("first element of the slice: {}", slice[0]);
println!("the slice has {} elements", slice.len());
println!("First element of the slice: {}", slice[0]);
println!("The slice has {} elements", slice.len());
}
fn main() {
// Fixed-size array (type signature is superfluous)
// Fixed-size array (type signature is superfluous).
let xs: [i32; 5] = [1, 2, 3, 4, 5];
// All elements can be initialized to the same value
// All elements can be initialized to the same value.
let ys: [i32; 500] = [0; 500];
// Indexing starts at 0
println!("first element of the array: {}", xs[0]);
println!("second element of the array: {}", xs[1]);
// Indexing starts at 0.
println!("First element of the array: {}", xs[0]);
println!("Second element of the array: {}", xs[1]);
// `len` returns the count of elements in the array
println!("number of elements in array: {}", xs.len());
// `len` returns the count of elements in the array.
println!("Number of elements in array: {}", xs.len());
// Arrays are stack allocated
println!("array occupies {} bytes", mem::size_of_val(&xs));
// Arrays are stack allocated.
println!("Array occupies {} bytes", mem::size_of_val(&xs));
// Arrays can be automatically borrowed as slices
println!("borrow the whole array as a slice");
// Arrays can be automatically borrowed as slices.
println!("Borrow the whole array as a slice.");
analyze_slice(&xs);
// Slices can point to a section of an array
// They are of the form [starting_index..ending_index]
// starting_index is the first position in the slice
// ending_index is one more than the last position in the slice
println!("borrow a section of the array as a slice");
// Slices can point to a section of an array.
// They are of the form [starting_index..ending_index].
// `starting_index` is the first position in the slice.
// `ending_index` is one more than the last position in the slice.
println!("Borrow a section of the array as a slice.");
analyze_slice(&ys[1 .. 4]);
// Example of empty slice `&[]`
// Example of empty slice `&[]`:
let empty_array: [u32; 0] = [];
assert_eq!(&empty_array, &[]);
assert_eq!(&empty_array, &[][..]); // same but more verbose
assert_eq!(&empty_array, &[][..]); // Same but more verbose
// Arrays can be safely accessed using `.get`, which returns an
// `Option`. This can be matched as shown below, or used with
// `.expect()` if you would like the program to exit with a nice
// message instead of happily continue.
for i in 0..xs.len() + 1 { // OOPS, one element too far
for i in 0..xs.len() + 1 { // Oops, one element too far!
match xs.get(i) {
Some(xval) => println!("{}: {}", i, xval),
None => println!("Slow down! {} is too far!", i),
}
}
// Out of bound indexing causes runtime error
// Out of bound indexing causes runtime error.
//println!("{}", xs[5]);
}
```
11 changes: 9 additions & 2 deletions src/primitives/literals.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ notation using these prefixes respectively: `0x`, `0o` or `0b`.
Underscores can be inserted in numeric literals to improve readability, e.g.
`1_000` is the same as `1000`, and `0.000_001` is the same as `0.000001`.

Rust also supports scientific [E-notation][enote], e.g. `1e6`, `7.6e-4`. The
associated type is `f64`.

We need to tell the compiler the type of the literals we use. For now,
we'll use the `u32` suffix to indicate that the literal is an unsigned 32-bit
integer, and the `i32` suffix to indicate that it's a signed 32-bit integer.

The operators available and their precedence [in Rust][rust op-prec] are similar to other
[C-like languages][op-prec].
The operators available and their precedence [in Rust][rust op-prec] are similar
to other [C-like languages][op-prec].

```rust,editable
fn main() {
Expand All @@ -25,6 +28,9 @@ fn main() {
println!("1 - 2 = {}", 1i32 - 2);
// TODO ^ Try changing `1i32` to `1u32` to see why the type is important
// Scientific notation
println!("1e4 is {}, -2.5e-3 is {}", 1e4, -2.5e-3);
// Short-circuiting boolean logic
println!("true AND false is {}", true && false);
println!("true OR false is {}", true || false);
Expand All @@ -42,5 +48,6 @@ fn main() {
}
```

[enote]: https://en.wikipedia.org/wiki/Scientific_notation#E_notation
[rust op-prec]: https://doc.rust-lang.org/reference/expressions.html#expression-precedence
[op-prec]: https://en.wikipedia.org/wiki/Operator_precedence#Programming_languages
95 changes: 47 additions & 48 deletions src/primitives/tuples.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ using parentheses `()`, and each tuple itself is a value with type signature
use tuples to return multiple values, as tuples can hold any number of values.

```rust,editable
// Tuples can be used as function arguments and as return values
// Tuples can be used as function arguments and as return values.
fn reverse(pair: (i32, bool)) -> (bool, i32) {
// `let` can be used to bind the members of a tuple to variables
// `let` can be used to bind the members of a tuple to variables.
let (int_param, bool_param) = pair;
(bool_param, int_param)
Expand All @@ -19,79 +19,78 @@ fn reverse(pair: (i32, bool)) -> (bool, i32) {
struct Matrix(f32, f32, f32, f32);
fn main() {
// A tuple with a bunch of different types
// A tuple with a bunch of different types.
let long_tuple = (1u8, 2u16, 3u32, 4u64,
-1i8, -2i16, -3i32, -4i64,
0.1f32, 0.2f64,
'a', true);
// Values can be extracted from the tuple using tuple indexing
println!("long tuple first value: {}", long_tuple.0);
println!("long tuple second value: {}", long_tuple.1);
// Values can be extracted from the tuple using tuple indexing.
println!("Long tuple first value: {}", long_tuple.0);
println!("Long tuple second value: {}", long_tuple.1);
// Tuples can be tuple members
// Tuples can be tuple members.
let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);
// Tuples are printable
// Tuples are printable.
println!("tuple of tuples: {:?}", tuple_of_tuples);
// But long Tuples (more than 12 elements) cannot be printed
// let too_long_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
// println!("too long tuple: {:?}", too_long_tuple);
// But long Tuples (more than 12 elements) cannot be printed.
//let too_long_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
//println!("Too long tuple: {:?}", too_long_tuple);
// TODO ^ Uncomment the above 2 lines to see the compiler error
let pair = (1, true);
println!("pair is {:?}", pair);
println!("Pair is {:?}", pair);
println!("the reversed pair is {:?}", reverse(pair));
println!("Uhe reversed pair is {:?}", reverse(pair));
// To create one element tuples, the comma is required to tell them apart
// from a literal surrounded by parentheses
println!("one element tuple: {:?}", (5u32,));
println!("just an integer: {:?}", (5u32));
// from a literal surrounded by parentheses.
println!("One element tuple: {:?}", (5u32,));
println!("Just an integer: {:?}", (5u32));
//tuples can be destructured to create bindings
// Tuples can be destructured to create bindings.
let tuple = (1, "hello", 4.5, true);
let (a, b, c, d) = tuple;
println!("{:?}, {:?}, {:?}, {:?}", a, b, c, d);
let matrix = Matrix(1.1, 1.2, 2.1, 2.2);
println!("{:?}", matrix);
}
```

### Activity

1. *Recap*: Add the `fmt::Display` trait to the `Matrix` struct in the above example,
so that if you switch from printing the debug format `{:?}` to the display
format `{}`, you see the following output:

```text
( 1.1 1.2 )
( 2.1 2.2 )
```
You may want to refer back to the example for [print display][print_display].
2. Add a `transpose` function using the `reverse` function as a template, which
accepts a matrix as an argument, and returns a matrix in which two elements
have been swapped. For example:
```rust,ignore
println!("Matrix:\n{}", matrix);
println!("Transpose:\n{}", transpose(matrix));
```
results in the output:
```text
Matrix:
( 1.1 1.2 )
( 2.1 2.2 )
Transpose:
( 1.1 2.1 )
( 1.2 2.2 )
```
1. *Recap*: Add the `fmt::Display` trait to the `Matrix` struct in the above
example, so that if you switch from printing the debug format `{:?}` to the
display format `{}`, you see the following output:

```text
( 1.1 1.2 )
( 2.1 2.2 )
```

You may want to refer back to the example for [print display][print_display].
2. Add a `transpose` function using the `reverse` function as a template, which
accepts a matrix as an argument, and returns a matrix in which two elements
have been swapped. For example:

```rust,ignore
println!("Matrix:\n{}", matrix);
println!("Transpose:\n{}", transpose(matrix));
```

Results in the output:

```text
Matrix:
( 1.1 1.2 )
( 2.1 2.2 )
Transpose:
( 1.1 2.1 )
( 1.2 2.2 )
```

[print_display]: ../hello/print/print_display.md

0 comments on commit 251eeb2

Please sign in to comment.