1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2025-06-23 01:07:40 +02:00

Publish Comprehensive Rust 🦀

This commit is contained in:
Martin Geisler
2022-12-21 16:36:30 +01:00
commit c212a473ba
252 changed files with 8047 additions and 0 deletions
.gitignoreCONTRIBUTING.mdCargo.tomlLICENSE.txtREADME.mdbook.tomlga4.jsrustfmt.toml
src
SUMMARY.mdandroid.md
android
basic-syntax.md
basic-syntax
cargo.md
cargo
concurrency.md
concurrency
control-flow.md
control-flow
credits.mdenums.md
enums
error-handling.md
error-handling
exercises
generics.md
generics
hello-world.md
hello-world
memory-management.md
memory-management
methods.md
methods
modules.md
modules
other-resources.mdownership.md
ownership
pattern-matching.md
pattern-matching
std.md
std
structs.md
structs
structure.mdtesting.md
testing
thanks.mdtraits.md
traits
unsafe.md
unsafe
welcome-day-1.md
welcome-day-1
welcome-day-2.mdwelcome-day-3.mdwelcome-day-4.mdwelcome.mdwhy-rust.md
why-rust
third_party

@ -0,0 +1,26 @@
# Compound Types
| | Types | Literals |
|--------|---------------------|--------------------------|
| Arrays | `[T; N]` | `[20, 30, 40]`, `[0; 3]` |
| Tuples | `(T1, T2, T3, ...)` | `('x', 1.2, 0)` |
Array assignment and access:
```rust,editable
fn main() {
let mut a: [i8; 10] = [42; 10];
a[5] = 0;
println!("a: {:?}", a);
}
```
Tuple assignment and access:
```rust,editable
fn main() {
let t: (i8, bool) = (7, true);
println!("1st index: {}", t.0);
println!("2nd index: {}", t.1);
}
```

@ -0,0 +1,23 @@
# Function Overloading
Overloading is not supported:
* Each function has a single implementation:
* Always takes a fixed number of parameters.
* Always takes a single set of parameter types.
* Default values are not supported:
* All call sites have the same number of arguments.
* Macros are sometimes used as an alternative.
However, function parameters can be generic:
```rust,editable
fn pick_one<T>(a: T, b: T) -> T {
if std::process::id() % 2 == 0 { a } else { b }
}
fn main() {
println!("coin toss: {}", pick_one("heads", "tails"));
println!("cash prize: {}", pick_one(500, 1000));
}
```

@ -0,0 +1,31 @@
# Functions
A Rust version of the famous FizzBuzz interview question:
```rust,editable
fn main() {
fizzbuzz_to(20); // Defined below, no forward declaration needed
}
fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
if rhs == 0 {
return false; // Corner case, early return
}
lhs % rhs == 0 // The last expression is the return value
}
fn fizzbuzz(n: u32) -> () { // No return value means returning the unit type `()`
match (is_divisible_by(n, 3), is_divisible_by(n, 5)) {
(true, true) => println!("fizzbuzz"),
(true, false) => println!("fizz"),
(false, true) => println!("buzz"),
(false, false) => println!("{n}"),
}
}
fn fizzbuzz_to(n: u32) { // `-> ()` is normally omitted
for n in 1..=n {
fizzbuzz(n);
}
}
```

@ -0,0 +1,30 @@
# Methods
Rust has methods, they are simply functions that are associated with a particular type. The
first argument of a method is an instance of the type it is associated with:
```rust,editable
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn inc_width(&mut self, delta: u32) {
self.width += delta;
}
}
fn main() {
let mut rect = Rectangle { width: 10, height: 5 };
println!("old area: {}", rect.area());
rect.inc_width(5);
println!("new area: {}", rect.area());
}
```
* We will look much more at methods in today's exercise and in tomorrow's class.

@ -0,0 +1,19 @@
# Dangling References
Rust will statically forbid dangling references:
```rust,editable,compile_fail
fn main() {
let ref_x: &i32;
{
let x: i32 = 10;
ref_x = &x;
}
println!("ref_x: {ref_x}");
}
```
* A reference is said to "borrow" the value is refers to.
* Rust is tracking the lifetimes of all references to ensure they live long
enough.
* We will talk more about borrowing when we get to ownership.

@ -0,0 +1,18 @@
# References
Like C++, Rust has references:
```rust,editable
fn main() {
let mut x: i32 = 10;
let ref_x: &mut i32 = &mut x;
*ref_x = 20;
println!("x: {x}");
}
```
Some differences from C++:
* We must dereference `ref_x` when assigning to it, similar to C pointers,
* Rust will auto-dereference in some cases, in particular when invoking
methods (try `count_ones`).

@ -0,0 +1,18 @@
# Scalar Types
| | Types | Literals |
|------------------------|--------------------------------------------|-------------------------------|
| Signed integers | `i8`, `i16`, `i32`, `i64`, `i128`, `isize` | `-10`, `0`, `1_000`, `123i64` |
| Unsigned integers | `u8`, `u16`, `u32`, `u64`, `u128`, `usize` | `0`, `123`, `10u16` |
| Floating point numbers | `f32`, `f64` | `3.14`, `-10.0e20`, `2f32` |
| Strings | `&str` | `"foo"`, `r#"\\"#` |
| Unicode scalar values | `char` | `'a'`, `'α'`, `'∞'` |
| Byte strings | `&[u8]` | `b"abc"`, `br#" " "#` |
| Booleans | `bool` | `true`, `false` |
The types have widths as follows:
* `iN`, `uN`, and `fN` are _n_ bits wide,
* `isize` and `usize` are the width of a pointer,
* `char` is 32 bit wide,
* `bool` is 8 bit wide.

@ -0,0 +1,21 @@
# Scopes and Shadowing
You can shadow variables, both those from outer scopes and variables from the
same scope:
```rust,editable
fn main() {
let a = 10;
println!("before: {a}");
{
let a = "hello";
println!("inner scope: {a}");
let a = true;
println!("shadowed in inner scope: {a}");
}
println!("after: {a}");
}
```

@ -0,0 +1,16 @@
# Slices
A slice gives you a view into a larger collection:
```rust,editable
fn main() {
let a: [i32; 6] = [10, 20, 30, 40, 50, 60];
println!("a: {a:?}");
let s: &[i32] = &a[2..4];
println!("s: {s:?}");
}
```
* Slices borrow data from the sliced type.
* Question: What happens if you modify `a[3]`?

@ -0,0 +1,39 @@
# Static and Constant Variables
Global state is managed with static and constant variables
## `const`
You can declare compile-time constants:
```rust,editable
const DIGEST_SIZE: usize = 3;
const ZERO: Option<u8> = Some(42);
fn compute_digest(text: &str) -> [u8; DIGEST_SIZE] {
let mut digest = [ZERO.unwrap_or(0); DIGEST_SIZE];
for (idx, &b) in text.as_bytes().iter().enumerate() {
digest[idx % DIGEST_SIZE] = digest[idx % DIGEST_SIZE].wrapping_add(b);
}
digest
}
fn main() {
let digest = compute_digest("Hello");
println!("Digest: {digest:?}");
}
```
## `static`
You can also declare static variables:
```rust,editable
static BANNER: &str = "Welcome to RustOS 3.14";
fn main() {
println!("{BANNER}");
}
```
We will look at mutating static data in the chapter on Unsafe Rust.

@ -0,0 +1,20 @@
# `String` vs `str`
We can now understand the two string types in Rust:
```rust,editable
fn main() {
let s1: &str = "Hello";
println!("s1: {s1}");
let mut s2: String = String::from("Hello ");
println!("s2: {s2}");
s2.push_str(s1);
println!("s2: {s2}");
}
```
Rust terminology:
* `&str` an immutable reference to a string slice.
* `String` a mutable string buffer

@ -0,0 +1,22 @@
# Type Inference
Rust will look at how the variable is _used_ to determine the type:
```rust,editable
fn takes_u32(x: u32) {
println!("u32: {x}");
}
fn takes_i8(y: i8) {
println!("i8: {y}");
}
fn main() {
let x = 10;
let y = 20;
takes_u32(x);
takes_i8(y);
// takes_u32(y);
}
```

@ -0,0 +1,13 @@
# Variables
Rust provides type safety via static typing. Variable bindings are immutable by
default:
```rust,editable
fn main() {
let x: i32 = 10;
println!("x: {x}");
// x = 20;
// println!("x: {x}");
}
```