Populate
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "comprehensive_rust"
|
||||||
|
version = "0.1.0"
|
32
Cargo.toml
Normal file
32
Cargo.toml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
[package]
|
||||||
|
name = "comprehensive_rust"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "move-semantics"
|
||||||
|
path = "src/move-semantics.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "moves-in-function-calls"
|
||||||
|
path = "src/moves-in-function-calls.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "copying"
|
||||||
|
path = "src/copying.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "lifetimes-function-calls"
|
||||||
|
path = "src/lifetimes-function-calls.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "lifetimes-structs"
|
||||||
|
path = "src/lifetimes-structs.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "library"
|
||||||
|
path = "src/exercises/library.rs"
|
17
src/day1/copying.rs
Normal file
17
src/day1/copying.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// https://google.github.io/comprehensive-rust/ownership/copy-clone.html
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
struct Point(i32, i32);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Copied by default
|
||||||
|
let x = 42;
|
||||||
|
let y = x;
|
||||||
|
println!("x: {x}");
|
||||||
|
println!("y: {y}");
|
||||||
|
|
||||||
|
// implements the Copy trait
|
||||||
|
let p1 = Point(3, 4);
|
||||||
|
let p2 = p1;
|
||||||
|
println!("p1: {p1:?}");
|
||||||
|
println!("p2: {p2:?}");
|
||||||
|
}
|
13
src/day1/exercises/iterators-ownership.rs
Normal file
13
src/day1/exercises/iterators-ownership.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// https://google.github.io/comprehensive-rust/exercises/day-1/iterators-and-ownership.html
|
||||||
|
|
||||||
|
|
||||||
|
// Traits are like interfaces: they describe behavior (methods) for a type. The Iterator trait
|
||||||
|
// simply says that you can call next until you get None back:
|
||||||
|
// pub trait Iterator {
|
||||||
|
// type Item;
|
||||||
|
// fn next(&mut self) -> Option<Self::Item>;
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
}
|
87
src/day1/exercises/library.rs
Normal file
87
src/day1/exercises/library.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// https://google.github.io/comprehensive-rust/exercises/day-1/book-library.html
|
||||||
|
struct Library {
|
||||||
|
books: Vec<Book>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Book {
|
||||||
|
title: String,
|
||||||
|
year: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Book {
|
||||||
|
// This is a constructor, used below.
|
||||||
|
fn new(title: &str, year: u16) -> Book {
|
||||||
|
Book {
|
||||||
|
title: String::from(title),
|
||||||
|
year,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This makes it possible to print Book values with {}.
|
||||||
|
impl std::fmt::Display for Book {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{} ({})", self.title, self.year)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Library {
|
||||||
|
fn new() -> Library {
|
||||||
|
Library {
|
||||||
|
books: vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(self) -> usize {
|
||||||
|
self.books.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.books.len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_book(&mut self, book: Book) {
|
||||||
|
self.books.push(book)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_books(&self) {
|
||||||
|
for book in self.books.iter() {
|
||||||
|
println!("book: {book}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn oldest_book(&self) -> Option<&Book> {
|
||||||
|
let mut oldest : Option<&Book> = None;
|
||||||
|
for book in self.books.iter() {
|
||||||
|
if oldest.is_none() {
|
||||||
|
oldest = Option::from(book)
|
||||||
|
} else if book.year < oldest.unwrap().year {
|
||||||
|
oldest = Option::from(book)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oldest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// This shows the desired behavior. Uncomment the code below and
|
||||||
|
// implement the missing methods. You will need to update the
|
||||||
|
// method signatures, including the "self" parameter!
|
||||||
|
let mut library = Library::new();
|
||||||
|
|
||||||
|
println!("Our library is empty: {}", library.is_empty());
|
||||||
|
|
||||||
|
library.add_book(Book::new("Lord of the Rings", 1954));
|
||||||
|
library.add_book(Book::new("Alice's Adventures in Wonderland", 1865));
|
||||||
|
|
||||||
|
library.print_books();
|
||||||
|
|
||||||
|
match library.oldest_book() {
|
||||||
|
Some(book) => println!("My oldest book is {book}"),
|
||||||
|
None => println!("My library is empty!"),
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Our library has {} books", library.len());
|
||||||
|
}
|
18
src/day1/lifetimes-function-calls.rs
Normal file
18
src/day1/lifetimes-function-calls.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// https://google.github.io/comprehensive-rust/ownership/lifetimes-function-calls.html
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Point(i32, i32);
|
||||||
|
|
||||||
|
// 'a is a generic parameter, it is inferred by the compiler.
|
||||||
|
// Lifetimes start with ' and 'a is a typical default name.
|
||||||
|
// Read &'a Point as “a borrowed Point which is valid for at least the lifetime a”.
|
||||||
|
// The at least part is important when parameters are in different scopes.
|
||||||
|
fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {
|
||||||
|
if p1.0 < p2.0 { p1 } else { p2 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let p1: Point = Point(10, 10);
|
||||||
|
let p2: Point = Point(20, 20); // Put into different scope
|
||||||
|
let p3: &Point = left_most(&p1, &p2);
|
||||||
|
println!("left-most point: {:?}", p3);
|
||||||
|
}
|
18
src/day1/lifetimes-structs.rs
Normal file
18
src/day1/lifetimes-structs.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// https://google.github.io/comprehensive-rust/ownership/lifetimes-data-structures.html
|
||||||
|
//
|
||||||
|
// If a data type stores borrowed data, it must be annotated with a lifetime:
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Highlight<'doc>(&'doc str);
|
||||||
|
|
||||||
|
fn erase(text: String) {
|
||||||
|
println!("Bye {text}!");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let text = String::from("The quick brown fox jumps over the lazy dog.");
|
||||||
|
let fox = Highlight(&text[4..19]);
|
||||||
|
let dog = Highlight(&text[35..43]);
|
||||||
|
// erase(text);
|
||||||
|
println!("{fox:?}");
|
||||||
|
println!("{dog:?}");
|
||||||
|
}
|
7
src/day1/move-semantics.rs
Normal file
7
src/day1/move-semantics.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// https://google.github.io/comprehensive-rust/ownership/move-semantics.html
|
||||||
|
fn main() {
|
||||||
|
let s1: String = String::from("Hello!");
|
||||||
|
let s2: String = s1;
|
||||||
|
println!("s2: {s2}");
|
||||||
|
// println!("s1: {s1}");
|
||||||
|
}
|
10
src/day1/moves-in-functions-calls.rs
Normal file
10
src/day1/moves-in-functions-calls.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// https://google.github.io/comprehensive-rust/ownership/moves-function-calls.html
|
||||||
|
fn say_hello(name: String) {
|
||||||
|
println!("Hello {name}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let name = String::from("Alice");
|
||||||
|
say_hello(name);
|
||||||
|
// say_hello(name);
|
||||||
|
}
|
10
src/day2/destructure-arrays.rs
Normal file
10
src/day2/destructure-arrays.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#[rustfmt::skip]
|
||||||
|
fn main() {
|
||||||
|
let triple = [0, -2, 3];
|
||||||
|
println!("Tell me about {triple:?}");
|
||||||
|
match triple {
|
||||||
|
[0, y, z] => println!("First is 0, y = {y}, and z = {z}"),
|
||||||
|
[1, ..] => println!("First is 1 and the rest were ignored"),
|
||||||
|
_ => println!("All elements were ignored"),
|
||||||
|
}
|
||||||
|
}
|
26
src/day2/destructure-enum.rs
Normal file
26
src/day2/destructure-enum.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
enum Result {
|
||||||
|
Ok(i32),
|
||||||
|
Err(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn divide_in_two(n: i32) -> Result {
|
||||||
|
if n % 2 == 0 {
|
||||||
|
Result::Ok(n / 2)
|
||||||
|
} else {
|
||||||
|
Result::Err(format!("cannot divide {} into two equal parts", n))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut n = 100;
|
||||||
|
match divide_in_two(n) {
|
||||||
|
Result::Ok(half) => println!("{n} divided in two is {half}"),
|
||||||
|
Result::Err(msg) => println!("sorry, an error happened: {msg}"),
|
||||||
|
}
|
||||||
|
|
||||||
|
n = 105;
|
||||||
|
match divide_in_two(n) {
|
||||||
|
Result::Ok(half) => println!("{n} divided in two is {half}"),
|
||||||
|
Result::Err(msg) => println!("sorry, an error happened: {msg}"),
|
||||||
|
}
|
||||||
|
}
|
14
src/day2/destructure-struct.rs
Normal file
14
src/day2/destructure-struct.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
struct Foo {
|
||||||
|
x: (u32, u32),
|
||||||
|
y: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
fn main() {
|
||||||
|
let foo = Foo { x: (1, 2), y: 3 };
|
||||||
|
match foo {
|
||||||
|
Foo { x: (1, b), y } => println!("x.0 = 1, b = {b}, y = {y}"),
|
||||||
|
Foo { y: 2, x: i } => println!("y = 2, i = {i:?}"),
|
||||||
|
Foo { y, .. } => println!("y = {y}, other fields were ignored"),
|
||||||
|
}
|
||||||
|
}
|
18
src/day2/enum_sizes.rs
Normal file
18
src/day2/enum_sizes.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use std::mem::{align_of, size_of};
|
||||||
|
|
||||||
|
macro_rules! dbg_size {
|
||||||
|
($t:ty) => {
|
||||||
|
println!("{}: size {} bytes, align: {} bytes",
|
||||||
|
stringify!($t), size_of::<$t>(), align_of::<$t>());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Foo {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// adding a variang-payload will change the size :)
|
||||||
|
dbg_size!(Foo);
|
||||||
|
}
|
22
src/day2/enums.rs
Normal file
22
src/day2/enums.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
fn generate_random_number() -> i32 {
|
||||||
|
4 // Chosen by fair dice roll. Guaranteed to be random.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum CoinFlip {
|
||||||
|
Heads,
|
||||||
|
Tails,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flip_coin() -> CoinFlip {
|
||||||
|
let random_number = generate_random_number();
|
||||||
|
if random_number % 2 == 0 {
|
||||||
|
return CoinFlip::Heads;
|
||||||
|
} else {
|
||||||
|
return CoinFlip::Tails;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("You got: {:?}", flip_coin());
|
||||||
|
}
|
23
src/day2/field-shorthand.rs
Normal file
23
src/day2/field-shorthand.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// https://google.github.io/comprehensive-rust/structs/field-shorthand.html
|
||||||
|
// If you already have variables with the right names, then you can create the struct using a shorthand:
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Person {
|
||||||
|
name: String,
|
||||||
|
age: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Person {
|
||||||
|
fn new(name: String, age: u8) -> Person {
|
||||||
|
Person { name, age }
|
||||||
|
}
|
||||||
|
|
||||||
|
// This WONT compile:
|
||||||
|
// fn newBad(nameBad: String, ageBad: u8) -> Person {
|
||||||
|
// Person { nameBad, ageBad }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let peter = Person::new(String::from("Peter"), 27);
|
||||||
|
println!("{peter:?}");
|
||||||
|
}
|
13
src/day2/match-guards.rs
Normal file
13
src/day2/match-guards.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// When matching, you can add a guard to a pattern. This is an arbitrary Boolean expression which will be executed if the pattern matches:
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
fn main() {
|
||||||
|
let pair = (2, -2);
|
||||||
|
println!("Tell me about {pair:?}");
|
||||||
|
match pair {
|
||||||
|
(x, y) if x == y => println!("These are twins"),
|
||||||
|
(x, y) if x + y == 0 => println!("Antimatter, kaboom!"),
|
||||||
|
(x, _) if x % 2 == 1 => println!("The first one is odd"),
|
||||||
|
_ => println!("No correlation..."),
|
||||||
|
}
|
||||||
|
}
|
19
src/day2/methods.rs
Normal file
19
src/day2/methods.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
struct Person {
|
||||||
|
name : String,
|
||||||
|
age: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Person {
|
||||||
|
fn say_hello(&self) {
|
||||||
|
println!("Hello my name is {}", self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let christian = Person {
|
||||||
|
name : String::from("Christian"),
|
||||||
|
age: 25,
|
||||||
|
};
|
||||||
|
christian.say_hello()
|
||||||
|
}
|
11
src/day2/pattern-matching.rs
Normal file
11
src/day2/pattern-matching.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fn main() {
|
||||||
|
let input = 'x';
|
||||||
|
|
||||||
|
match input {
|
||||||
|
'q' => println!("Quitting"),
|
||||||
|
'a' | 's' | 'w' | 'd' => println!("Moving around"),
|
||||||
|
'0'..='9' => println!("Number input"),
|
||||||
|
_ => println!("Something else"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
50
src/day2/receivers.rs
Normal file
50
src/day2/receivers.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// https://google.github.io/comprehensive-rust/methods/example.html
|
||||||
|
//
|
||||||
|
// The &self below indicates that the method borrows the object immutably. There are other possible receivers for a method:
|
||||||
|
//
|
||||||
|
// * &self: borrows the object from the caller using a shared and immutable reference. The object can be used again afterwards.
|
||||||
|
// * &mut self: borrows the object from the caller using a unique and mutable reference. The object can be used again afterwards.
|
||||||
|
// * self: takes ownership of the object and moves it away from the caller. The method becomes the owner of the object. The object will be drop (deallocated) when the method returns, unless it’s ownership is explicitly transmitted.
|
||||||
|
// * No receiver: this becomes a static method on the struct. Typically used to create constructors which are called new by convention.
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Race {
|
||||||
|
name: String,
|
||||||
|
laps: Vec<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Race {
|
||||||
|
fn new(name: &str) -> Race { // No receiver, a static method
|
||||||
|
Race { name: String::from(name), laps: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_lap(&mut self, lap: i32) { // Exclusive borrowed read-write access to self
|
||||||
|
self.laps.push(lap);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_laps(&self) { // Shared and read-only borrowed access to self
|
||||||
|
println!("Recorded {} laps for {}:", self.laps.len(), self.name);
|
||||||
|
for (idx, lap) in self.laps.iter().enumerate() {
|
||||||
|
println!("Lap {idx}: {lap} sec");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish(self) { // Exclusive ownership of self
|
||||||
|
let total = self.laps.iter().sum::<i32>();
|
||||||
|
println!("Race {} is finished, total lap time: {}", self.name, total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut race = Race::new("Monaco Grand Prix");
|
||||||
|
race.add_lap(70);
|
||||||
|
race.add_lap(68);
|
||||||
|
race.print_laps();
|
||||||
|
race.add_lap(71);
|
||||||
|
race.print_laps();
|
||||||
|
race.finish();
|
||||||
|
|
||||||
|
// using `race` after here is invalid since ownership was moved to the finish method
|
||||||
|
//
|
||||||
|
// race.print_laps()
|
||||||
|
}
|
15
src/day2/structs.rs
Normal file
15
src/day2/structs.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// https://google.github.io/comprehensive-rust/structs.html
|
||||||
|
|
||||||
|
struct Person {
|
||||||
|
name: String,
|
||||||
|
age: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let peter = Person {
|
||||||
|
name: String::from("Christian"),
|
||||||
|
age: 25,
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("{} is {} years old", peter.name, peter.age);
|
||||||
|
}
|
19
src/day2/tuple-structs.rs
Normal file
19
src/day2/tuple-structs.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// If the field names are unimportant, you can use a tuple struct:
|
||||||
|
struct Point(i32, i32);
|
||||||
|
|
||||||
|
// This is often used for single-field wrappers (called newtypes).
|
||||||
|
// Single-field wrappers are similar to type-aliases from Golang.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Newtons(f64);
|
||||||
|
|
||||||
|
fn compute_thruster_force() -> Newtons {
|
||||||
|
todo!("Ask a rocket scientist at NASA")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let p = Point(17, 23);
|
||||||
|
println!("({}, {})", p.0, p.1);
|
||||||
|
|
||||||
|
let force = compute_thruster_force();
|
||||||
|
println!("{:?}", force)
|
||||||
|
}
|
24
src/day2/variant-payloads.rs
Normal file
24
src/day2/variant-payloads.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
enum WebEvent {
|
||||||
|
PageLoad, // Variant without payload
|
||||||
|
KeyPress(char), // Tuple struct variant
|
||||||
|
Click { x: i64, y: i64 }, // Full struct variant
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
fn inspect(event: WebEvent) {
|
||||||
|
match event {
|
||||||
|
WebEvent::PageLoad => println!("page loaded"),
|
||||||
|
WebEvent::KeyPress(c) => println!("pressed '{c}'"),
|
||||||
|
WebEvent::Click { x, y } => println!("clicked at x={x}, y={y}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let load = WebEvent::PageLoad;
|
||||||
|
let press = WebEvent::KeyPress('x');
|
||||||
|
let click = WebEvent::Click { x: 20, y: 80 };
|
||||||
|
|
||||||
|
inspect(load);
|
||||||
|
inspect(press);
|
||||||
|
inspect(click);
|
||||||
|
}
|
Reference in New Issue
Block a user