RUst - initial commit

This commit is contained in:
Sasza Stanczew 2026-09-14 07:27:59 +02:00
parent 2b2cdcacf5
commit 0b2b0a65cd
45 changed files with 23729 additions and 0 deletions

View file

@ -1,5 +1,6 @@
# Trainings # Trainings
To jest lista traningów jakie odbyłem To jest lista traningów jakie odbyłem
## Fujitsu
### Atakowanie i Ochrona Aplikacji Webowych - 08-09-02.2022 ### Atakowanie i Ochrona Aplikacji Webowych - 08-09-02.2022
### Agile - 28.04.2023 ### Agile - 28.04.2023
@ -8,3 +9,6 @@ To jest lista traningów jakie odbyłem
### Zaawansowane Tehcniki Programowania C++ - 26-26.04.2024 ### Zaawansowane Tehcniki Programowania C++ - 26-26.04.2024
### PythonAI 25.03-21.05.2025 7 dni w 3 turach ### PythonAI 25.03-21.05.2025 7 dni w 3 turach
## Ericsson
### Rust 14-16.09.2026

View file

@ -0,0 +1,7 @@
FROM infotrainingdev/rust-bs-notebook:latest
# [Optional] Uncomment this section to install additional packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends your-package-list-here
WORKDIR /root

View file

@ -0,0 +1,37 @@
{
"name": "Rust",
"build": {
"dockerfile": "Dockerfile",
},
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Set *default* container specific settings.json values on container create.
"settings": {
"files.watcherExclude": {
"**/target/**": true
},
"rust-analyzer.checkOnSave.command": "clippy"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"vadimcn.vscode-lldb",
"rust-lang.rust-analyzer",
"ms-toolsai.jupyter",
"ms-toolsai.vscode-jupyter-powertoys"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "chown -R $(whoami) /usr/local/cargo/",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
//"remoteUser": "vscode"
}

View file

@ -0,0 +1,2 @@
[workspace]
members = ["code/hello-world", "exercises/primes", "exercises/vector"]

View file

@ -0,0 +1,47 @@
# Programowanie w języku Rust - Szkolenie
## Docs
* https://doc.rust-lang.org/book/
* https://doc.rust-lang.org/std/index.html
## Konfiguracja środowiska
Proszę wybrać jedną z poniższych opcji:
### Lokalna
Przed szkoleniem należy zainstalować:
* Rust - https://www.rust-lang.org/tools/install
* [Visual Studio Code](https://code.visualstudio.com/)
* Zainstalować wtyczki
* rust-analyzer
* Jupyter
* Live Share
* Rust REPL - `evcxr_repl`
```bash
cargo install evcxr_repl
cargo install evcxr_jupyter
evcxr_jupyter --install
```
### Docker + Visual Studio Code
Jeśli uczestnicy szkolenia korzystają w pracy z Docker'a, to należy zainstalować:
#### Docker
* Instalacja Docker Desktop - https://www.docker.com/get-started/
#### Visual Studio Code
* [Visual Studio Code](https://code.visualstudio.com/)
* Zainstalować wtyczki
* Live Share
* Dev Containers ([wymagania](https://code.visualstudio.com/docs/devcontainers/containers#_system-requirements))
* po instalacji wtyczki - należy otworzyć w VS Code folder zawierający sklonowane repozytorium i
z palety poleceń (Ctrl+Shift+P) wybrać opcję **Dev Containers: Rebuild and Reopen in Container**

View file

@ -0,0 +1,9 @@
[package]
name = "hello-world"
version = "0.1.0"
edition = "2021"
[dependencies]
[dev-dependencies]
rstest = "0.23.0"

View file

@ -0,0 +1,5 @@
fn main() {
let mut message = "Hello, world!".to_string();
message += "!!";
println!("{message}");
}

View file

@ -0,0 +1,6 @@
[package]
name = "primes"
version = "0.1.0"
edition = "2021"
[dependencies]

View file

@ -0,0 +1,55 @@
// TODO
#[test]
fn test_is_prime() {
// assert!(!is_prime(0));
// assert!(!is_prime(1));
// assert!(is_prime(2));
// assert!(is_prime(3));
// assert!(is_prime(5));
// assert!(is_prime(7));
// assert!(is_prime(11));
// assert!(is_prime(13));
// assert!(is_prime(17));
// assert!(is_prime(19));
// assert!(!is_prime(4));
// assert!(!is_prime(6));
// assert!(!is_prime(8));
// assert!(!is_prime(9));
// assert!(!is_prime(10));
// assert!(is_prime(113));
}
#[test]
fn test_n_primes() {
// let primes = n_primes(0);
// assert_eq!(primes, Vec::new());
// let primes = n_primes(10);
// assert_eq!(primes, vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29]);
// let primes = n_primes(20);
// assert_eq!(primes, vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71]);
}
#[test]
fn test_primes_in_range() {
// let primes = primes_in_range(2..100);
// assert_eq!(primes, vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
// 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
// 73, 79, 83, 89, 97]);
}
#[test]
fn test_all_primes() {
// let primes = all_primes().take(10).collect::<Vec<u32>>();
// assert_eq!(primes, vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29]);
}
fn main() {
// println!("First 100 primes:");
// for prime in all_primes().take(100) {
// println!("{}", prime);
// }
}

View file

@ -0,0 +1,178 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Iterators"
]
},
{
"cell_type": "markdown",
"id": "09116649",
"metadata": {},
"source": [
"1. Use iterator methods to sum the values in a vector."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9fc4b114",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" let values = vec![1, 2, 3, 4];\n",
" let total: i32 = __;\n",
"\n",
" assert_eq!(total, 10);\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();\n"
]
},
{
"cell_type": "markdown",
"id": "c1558bef",
"metadata": {},
"source": [
"2. Transform each item using `map()` and collect the results into a new vector."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3a7a9e2b",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" let values = vec![1, 2, 3];\n",
" let doubled: Vec<i32> = __;\n",
"\n",
" assert_eq!(doubled, vec![2, 4, 6]);\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();\n"
]
},
{
"cell_type": "markdown",
"id": "829e3f48",
"metadata": {},
"source": [
"3. Filter the iterator to keep only even numbers."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "47285545",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" let values = vec![1, 2, 3, 4, 5];\n",
" let evens: Vec<i32> = __;\n",
"\n",
" assert_eq!(evens, vec![2, 4]);\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();\n"
]
},
{
"cell_type": "markdown",
"id": "545e9a65",
"metadata": {},
"source": [
"4. Use `enumerate()` to find the index of the first value greater than 5."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "622ea110",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" let values = vec![2, 4, 6, 8];\n",
" let idx = __;\n",
"\n",
" assert_eq!(idx, Some(2));\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"id": "fbde588e",
"metadata": {},
"source": [
"5. Calculate sum of `Things` that are even using iterator adaptors\n",
" "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3c3cd0dc",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"#[derive(Clone, Debug, PartialEq, Eq)]\n",
"struct Thing(u64);\n",
"\n",
"let collection: Vec<Thing> = vec![Thing(1), Thing(2), Thing(665), Thing(42), Thing(3), Thing(4)];\n",
"\n",
"let result: u64 = __;\n",
"\n",
"assert_eq!(result, 48);"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "Rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View file

@ -0,0 +1,469 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Variables"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Binding & mutablity"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1. A variable can be used only if it has been initialized."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fix the error below with least amount of modification to the code\n",
"fn main() {\n",
" let x: i32; // Uninitialized but used, ERROR !\n",
" let y: i32; // Uninitialized but also unused, only a Warning !\n",
"\n",
" assert_eq!(x, 5);\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2. Use mut to mark a variable as mutable."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"\n",
"// Fill the blanks in the code to make it compile\n",
"fn main() {\n",
" let __ __ = 1;\n",
" __ += 2; \n",
" \n",
" assert_eq!(x, 3);\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Destructuring"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3. We can use a pattern with let to destructure a tuple to separate variables."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fix the error below with least amount of modification\n",
"fn main() {\n",
" let (x, y) = (1, 2);\n",
" x += 2;\n",
"\n",
" assert_eq!(x, 3);\n",
" assert_eq!(y, 2);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"4. Use tuple, slice, and struct patterns as the left-hand side of an assignment."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" let (x, y);\n",
" (x,..) = (3, 4);\n",
" [.., y] = [1, 2];\n",
" // Fill the blank to make the code work\n",
" assert_eq!([x,y], __);\n",
"\n",
" println!(\"Success!\");\n",
"} \n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Basic Types"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1. Types are inferred by the compiler."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Remove something to make it work\n",
"fn main() {\n",
" let x: i32 = 5;\n",
" let mut y: u32 = 5;\n",
"\n",
" y = x;\n",
" \n",
" let z = 10; // Type of z ? \n",
" assert!((&z as &dyn std::any::Any).is::<__>());\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2. Cast types using the `as` keyword."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fill the blank\n",
"fn main() {\n",
" let v: u16 = 38_u8 as __;\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3. Guess the type inferred by the compiler."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Get the type of given variable, return a string representation of the type , e.g \"i8\", \"u8\", \"i32\", \"u32\"\n",
"fn type_of<T>(_: &T) -> String {\n",
" format!(\"{}\", std::any::type_name::<T>())\n",
"}\n",
"\n",
"// Modify `assert_eq!` to make it work\n",
"fn main() {\n",
" let x = 5;\n",
" assert_eq!(\"__\".to_string(), type_of(&x));\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2. Type `char` represents a single Unicode scalar value."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"\n",
"// Make it work\n",
"use std::mem::size_of_val;\n",
"\n",
"fn main() {\n",
" let c1 = 'a';\n",
" assert_eq!(size_of_val(&c1), __); \n",
"\n",
" let c2 = '❤'; // heart utf-8\n",
" assert_eq!(size_of_val(&c2), __); \n",
"\n",
" println!(\"Success!\");\n",
"} \n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3. Unit type `()` has only one value `()`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Make it work, don't modify `implicitly_ret_unit` !\n",
"fn main() {\n",
" let _v: () = ();\n",
"\n",
" let v = (1, 2);\n",
" assert_eq!(v, implicitly_ret_unit());\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"fn implicitly_ret_unit() {\n",
" println!(\"I will return a ()\");\n",
"}\n",
"\n",
"// Don't use this one\n",
"fn explicitly_ret_unit() -> () {\n",
" println!(\"I will return a ()\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"use std::mem::size_of_val;\n",
"\n",
"fn main() {\n",
" let unit: () = ();\n",
" assert!(size_of_val(&unit) == __);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Statements & Expressions"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Make it work with two ways\n",
"fn main() {\n",
" let v = {\n",
" let mut x = 1;\n",
" x += 2\n",
" };\n",
" \n",
" assert_eq!(v, 3);\n",
" \n",
" println!(\"Success!\");\n",
" }\n",
"\n",
" main();"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" let s = sum(1 , 2);\n",
" assert_eq!(s, 3);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"fn sum(x: i32, y: i32) -> i32 {\n",
" x + y;\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Functions"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" // Don't modify the following two lines!\n",
" let (x, y) = (1, 2);\n",
" let s = sum(x, y);\n",
"\n",
" assert_eq!(s, 3);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"fn sum(x, y: i32) {\n",
" x + y;\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" print();\n",
" }\n",
" \n",
" // Replace i32 with another type\n",
" fn print() -> i32 {\n",
" println!(\"Success!\");\n",
" }\n",
"\n",
" main();"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "Rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View file

@ -0,0 +1,313 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Ownership"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" // Use as many approaches as you can to make it work\n",
" let x = String::from(\"Hello world\");\n",
" let y = x;\n",
" println!(\"{}, {}\", x, y);\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Don't modify code in main!\n",
"fn main() {\n",
" let s1 = String::from(\"Hello world\");\n",
" let s2 = take_ownership(s1);\n",
"\n",
" println!(\"{}\", s2);\n",
"}\n",
"\n",
"// Only modify the code below!\n",
"fn take_ownership(s: String) {\n",
" println!(\"{}\", s);\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" let s = give_ownership();\n",
" println!(\"{}\", s);\n",
"}\n",
"\n",
"// Only modify the code below!\n",
"fn give_ownership() -> String {\n",
" let s = String::from(\"Hello world\");\n",
" // Convert String to Vec\n",
" let _s = s.into_bytes();\n",
" s\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fix the error without removing any code\n",
"fn main() {\n",
" let s = String::from(\"Hello World\");\n",
"\n",
" print_str(s);\n",
"\n",
" println!(\"{}\", s);\n",
"}\n",
"\n",
"fn print_str(s: String) {\n",
" println!(\"{}\",s)\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Don't use clone, use copy instead\n",
"fn main() {\n",
" let x = (1, 2, (), \"hello\".to_string());\n",
" let y = x.clone();\n",
" println!(\"{:?}, {:?}\", x, y);\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// make the necessary variable mutable\n",
"fn main() {\n",
" let s = String::from(\"Hello \");\n",
" \n",
" let s1 = s;\n",
"\n",
" s1.push_str(\"World!\");\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Reference & Borrowing"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Reference"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" let x = 5;\n",
" \n",
" // Fill the blank\n",
" let p = __;\n",
" \n",
" println!(\"the memory address of x is {:p}\", p); // One possible output: 0x16fa3ac84\n",
" }\n",
"\n",
" main();"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fix error\n",
"fn main() {\n",
" let mut s = String::from(\"hello, \");\n",
"\n",
" borrow_object(s);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"fn borrow_object(s: &String) {}\n",
"\n",
"main();"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fix error\n",
"fn main() {\n",
" let mut s = String::from(\"hello, \");\n",
"\n",
" push_str(s);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"fn push_str(s: &mut String) {\n",
" s.push_str(\"world\")\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Borrowing"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Remove something to make it work\n",
"// Don't remove a whole line !\n",
"fn main() {\n",
" let mut s = String::from(\"hello\");\n",
"\n",
" let r1 = &mut s;\n",
" let r2 = &mut s;\n",
"\n",
" println!(\"{}, {}\", r1, r2);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" // Fix error by modifying this line\n",
" let s = String::from(\"hello, \");\n",
"\n",
" borrow_object(&mut s);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"fn borrow_object(s: &mut String) {}\n",
"\n",
"main();"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "Rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View file

@ -0,0 +1,282 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# String"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fix error without adding new line\n",
"fn main() {\n",
" let s: str = \"hello, world\";\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fill the blank\n",
"fn main() {\n",
" let mut s = __;\n",
" s.push_str(\"hello, world\");\n",
" s.push('!');\n",
"\n",
" assert_eq!(s, \"hello, world!\");\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fix all errors without adding newline\n",
"fn main() {\n",
" let s = String::from(\"hello\");\n",
" s.push(',');\n",
" s.push(\" world\");\n",
" s += \"!\".to_string();\n",
"\n",
" println!(\"{}\", s);\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"4."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fix error with at least two solutions\n",
"fn main() {\n",
" let s = \"hello, world\";\n",
" greetings(s)\n",
"}\n",
"\n",
"fn greetings(s: String) {\n",
" println!(\"{}\", s)\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Array"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" // Fill the blank with proper array type\n",
" let arr: __ = [1, 2, 3, 4, 5];\n",
"\n",
" // Modify the code below to make it work\n",
" assert!(arr.len() == 4);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" // We can ignore parts of the array type or even the whole type, let the compiler infer it for us\n",
" let arr0 = [1, 2, 3];\n",
" let arr: [_; 3] = ['a', 'b', 'c'];\n",
" \n",
" // Fill the blank\n",
" // Arrays are stack allocated, `std::mem::size_of_val` returns the bytes which an array occupies\n",
" // A char takes 4 bytes in Rust: Unicode char\n",
" assert!(std::mem::size_of_val(&arr) == __);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Slice"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fix the errors, DON'T add new lines!\n",
"fn main() {\n",
" let arr = [1, 2, 3];\n",
" let s1: [i32] = arr[0..2];\n",
"\n",
" let s2: str = \"hello, world\" as str;\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" let arr: [i32; 5] = [1, 2, 3, 4, 5];\n",
" // Fill the blanks to make the code work\n",
" let slice: __ = __;\n",
" assert_eq!(slice, &[2, 3, 4]);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "Rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View file

@ -0,0 +1,442 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Struct"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fix the error\n",
"struct Person {\n",
" name: String,\n",
" age: u8,\n",
" hobby: String\n",
"}\n",
"\n",
"fn main() {\n",
" let age = 30;\n",
" let p = Person {\n",
" name: String::from(\"sunface\"),\n",
" age,\n",
" };\n",
"\n",
" println!(\"Success!\");\n",
"} \n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fix the errors and fill the blanks\n",
"struct Color(i32, i32, i32);\n",
"\n",
"fn main() {\n",
" let v = (0, 127, 255);\n",
" check_color(v);\n",
"\n",
" println!(\"Success!\");\n",
"} \n",
"\n",
"fn check_color(p: Color) {\n",
" let (x, _, _) = p;\n",
" assert_eq!(x, 0);\n",
" assert_eq!(p.1, 127);\n",
" assert_eq!(__, 255);\n",
" }\n",
"\n",
" main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"\n",
"// Fill the blank and fix the error without adding/removing new line\n",
"struct Person {\n",
" name: String,\n",
" age: u8,\n",
"}\n",
"fn main() {\n",
" let age = 18;\n",
" let p = Person {\n",
" name: String::from(\"john\"),\n",
" age,\n",
" };\n",
"\n",
" // How can you believe sunface is only 18? \n",
" p.age = 30;\n",
"\n",
" // Fill the blank\n",
" __ = String::from(\"John\");\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"4."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fill the blank to make the code work\n",
"struct User {\n",
" active: bool,\n",
" username: String,\n",
" email: String,\n",
" sign_in_count: u64,\n",
"}\n",
"fn main() {\n",
" let u1 = User {\n",
" email: String::from(\"someone@example.com\"),\n",
" username: String::from(\"sunface\"),\n",
" active: true,\n",
" sign_in_count: 1,\n",
" };\n",
"\n",
" let u2 = set_email(u1);\n",
"\n",
" println!(\"Success!\");\n",
"} \n",
"\n",
"fn set_email(u: User) -> User {\n",
" User {\n",
" email: String::from(\"contact@im.dev\"),\n",
" __\n",
" }\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"5."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fill the blanks to make the code work\n",
"#[__]\n",
"struct Rectangle {\n",
" width: u32,\n",
" height: u32,\n",
"}\n",
"\n",
"fn main() {\n",
" let scale = 2;\n",
" let rect1 = Rectangle {\n",
" width: dbg!(30 * scale), // Print debug info to stderr and assign the value of `30 * scale` to `width`\n",
" height: 50,\n",
" };\n",
"\n",
" dbg!(&rect1); // Print debug info to stderr\n",
"\n",
" println!(__, rect1); // Print debug info to stdout\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Enum"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fix the errors\n",
"enum Number {\n",
" Zero,\n",
" One,\n",
" Two,\n",
"}\n",
"\n",
"enum Number1 {\n",
" Zero = 0,\n",
" One,\n",
" Two,\n",
"}\n",
"\n",
"// C-like enum\n",
"enum Number2 {\n",
" Zero = 0,\n",
" One = 1,\n",
" Two = 2,\n",
"}\n",
"\n",
"\n",
"fn main() {\n",
" // An enum variant can be converted to a integer by `as`\n",
" assert_eq!(Number::One, Number1::One);\n",
" assert_eq!(Number1::One, Number2::One);\n",
"\n",
" println!(\"Success!\");\n",
"} \n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fill in the blank\n",
"enum Message {\n",
" Quit,\n",
" Move { x: i32, y: i32 },\n",
" Write(String),\n",
" ChangeColor(i32, i32, i32),\n",
"}\n",
"\n",
"fn main() {\n",
" let msg1 = Message::Move{__}; // Instantiating with x = 1, y = 2 \n",
" let msg2 = Message::Write(__); // Instantiating with \"hello, world!\"\n",
"\n",
" println!(\"Success!\");\n",
"} \n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"\n",
"// Fill in the blank and fix the error\n",
"enum Message {\n",
" Quit,\n",
" Move { x: i32, y: i32 },\n",
" Write(String),\n",
" ChangeColor(i32, i32, i32),\n",
"}\n",
"\n",
"fn main() {\n",
" let msg = Message::Move{x: 1, y: 2};\n",
"\n",
" if let Message::Move{__} = msg {\n",
" assert_eq!(a, b);\n",
" } else {\n",
" panic!(\"NEVER LET THIS RUN!\");\n",
" }\n",
"\n",
" println!(\"Success!\");\n",
"} \n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"4."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fill in the blank and fix the errors\n",
"enum Message {\n",
" Quit,\n",
" Move { x: i32, y: i32 },\n",
" Write(String),\n",
" ChangeColor(i32, i32, i32),\n",
"}\n",
"\n",
"fn main() {\n",
" let msgs: __ = [\n",
" Message::Quit,\n",
" Message::Move{x:1, y:3},\n",
" Message::ChangeColor(255,255,0)\n",
" ];\n",
"\n",
" for msg in msgs {\n",
" show_message(msg)\n",
" }\n",
"} \n",
"\n",
"fn show_message(msg: Message) {\n",
" println!(\"{}\", msg);\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Impl"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1. Implement functions for `struct`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"struct ContactEntry(String, String);\n",
"\n",
"// TODO: implement functions for ContactEntry\n",
"\n",
"fn main() {\n",
" let c1 = ContactEntry::new(\"John\", \"666-66-66-66\");\n",
" \n",
" assert_eq!(c1.name(), \"John\");\n",
" assert_eq!(c1.phone(), \"666-66-66-66\"); \n",
"}"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "Rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View file

@ -0,0 +1,213 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Match"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"// Fill the blanks\n",
"enum Direction {\n",
" East,\n",
" West,\n",
" North,\n",
" South,\n",
"}\n",
"\n",
"fn main() {\n",
" let direction = Direction::South;\n",
" match direction {\n",
" Direction::East => println!(\"East\"),\n",
" __ => { // Matching South or North here\n",
" println!(\"South or North\");\n",
" },\n",
" _ => println!(__),\n",
" };\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2. Match is an expression, so we can use it in assignments"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fn main() {\n",
" let boolean = true;\n",
"\n",
" // Fill the blank with a match expression:\n",
" //\n",
" // boolean = true -> binary = 1\n",
" // boolean = false -> binary = 0\n",
" let binary = __;\n",
"\n",
" assert_eq!(binary, 1);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
" main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3. Using match to get the data an enum variant holds."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"// Fill in the blanks\n",
"enum Message {\n",
" Quit,\n",
" Move { x: i32, y: i32 },\n",
" Write(String),\n",
" ChangeColor(i32, i32, i32),\n",
"}\n",
"\n",
"fn main() {\n",
" let msgs = [\n",
" Message::Quit,\n",
" Message::Move{x:1, y:3},\n",
" Message::ChangeColor(255,255,0)\n",
" ];\n",
"\n",
" for msg in msgs {\n",
" show_message(msg)\n",
" }\n",
"\n",
" println!(\"Success!\");\n",
"} \n",
"\n",
"fn show_message(msg: Message) {\n",
" match msg {\n",
" __ => { // match Message::Move\n",
" assert_eq!(a, 1);\n",
" assert_eq!(b, 3);\n",
" },\n",
" Message::ChangeColor(_, g, b) => {\n",
" assert_eq!(g, __);\n",
" assert_eq!(b, __);\n",
" }\n",
" __ => println!(\"no data in these variants\")\n",
" }\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# If let"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"4."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fn main() {\n",
" let o = Some(7);\n",
"\n",
" // Remove the whole `match` block, using `if let` instead \n",
" match o {\n",
" Some(i) => {\n",
" println!(\"This is a really long string and `{:?}`\", i);\n",
"\n",
" println!(\"Success!\");\n",
" }\n",
" _ => {}\n",
" };\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"5."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"// Fill in the blank\n",
"enum Foo {\n",
" Bar(u8)\n",
"}\n",
"\n",
"fn main() {\n",
" let a = Foo::Bar(1);\n",
"\n",
" __ {\n",
" println!(\"foobar holds the value: {}\", i);\n",
"\n",
" println!(\"Success!\");\n",
" }\n",
"}\n",
"\n",
"main();"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View file

@ -0,0 +1,118 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Errors"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// FILL in the blanks and FIX the errors\n",
"use std::num::ParseIntError;\n",
"use std::num::IntErrorKind::InvalidDigit\n",
"\n",
"fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {\n",
" let n1 = n1_str.parse::<i32>();\n",
" let n2 = n2_str.parse::<i32>();\n",
" \n",
" n1 * n2\n",
"}\n",
"\n",
"fn main() {\n",
" let result = multiply(\"10\", \"2\");\n",
" assert_eq!(result, Ok(20));\n",
"\n",
" let result = multiply(\"t\", \"2\");\n",
" assert_eq!(result.err().unwrap().kind(), &InvalidDigit);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"use std::fs;\n",
"use std::io;\n",
"use std::num;\n",
"\n",
"enum CliError {\n",
" IoError(io::Error),\n",
" ParseError(num::ParseIntError),\n",
"}\n",
"\n",
"impl From<io::Error> for CliError {\n",
" // TODO: implement the trait\n",
"}\n",
" \n",
"impl From<num::ParseIntError> for CliError {\n",
" // TODO: implement the trait\n",
"}\n",
"\n",
"fn open_and_parse_file(file_name: &str) -> Result<i32, CliError> {\n",
" // ? automatically converts io::Error to CliError\n",
" let contents = fs::read_to_string(&file_name)?;\n",
" // num::ParseIntError -> CliError\n",
" let num: i32 = contents.trim().parse()?;\n",
" Ok(num)\n",
"}\n",
"\n",
"fn main() {\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "Rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View file

@ -0,0 +1,421 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Traits"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fill in the two impl blocks to make the code work.\n",
"// DON'T modify the code in `main`.\n",
"trait Greetings {\n",
" fn say_hi(&self) -> String {\n",
" String::from(\"Hi\")\n",
" }\n",
"\n",
" fn say_something(&self) -> String;\n",
"}\n",
"\n",
"struct Student {}\n",
"\n",
"impl Greetings for Student {\n",
"}\n",
"\n",
"struct Teacher {}\n",
"\n",
"impl Greetings for Teacher {\n",
"}\n",
"\n",
"fn main() {\n",
" let s = Student {};\n",
" assert_eq!(s.say_hi(), \"Hi\");\n",
" assert_eq!(s.say_something(), \"I'm a good student\");\n",
"\n",
" let t = Teacher {};\n",
" assert_eq!(t.say_hi(), \"Hi, I'm your new teacher\");\n",
" assert_eq!(t.say_something(), \"I'm not a bad teacher\");\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"struct Fender {}\n",
"struct Gibson {}\n",
"\n",
"trait Guitar {\n",
" fn sound(&self) -> String;\n",
"}\n",
"\n",
"impl Guitar for Fender {\n",
" fn sound(&self) -> String {\n",
" \"like Jimmy!\".to_string()\n",
" }\n",
"}\n",
"\n",
"impl Guitar for Gibson {\n",
" fn sound(&self) -> String {\n",
" \"like Slash!\".to_string()\n",
" }\n",
"}\n",
"\n",
"// Returns some struct that implements Guitar, but we don't know which one at compile time.\n",
"// FIX the errors here, you can make a fake random, or you can use trait object.\n",
"fn random_guitar(random_number: f64) -> impl Guitar {\n",
" if random_number < 0.5 {\n",
" Fender {}\n",
" } else {\n",
" Gibson {}\n",
" }\n",
"}\n",
"\n",
"fn main() {\n",
" let random_number = 0.234;\n",
" let guitar = random_guitar(random_number);\n",
" println!(\"You've randomly chosen an guitar, and it sounds {}\", guitar.sound());\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3. Trait bound"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"struct Fender {}\n",
"struct Gibson {}\n",
"\n",
"trait Guitar {\n",
" fn sound(&self) -> String;\n",
"}\n",
"\n",
"impl Guitar for Fender {\n",
" fn sound(&self) -> String {\n",
" \"like Jimmy!\".to_string()\n",
" }\n",
"}\n",
"\n",
"impl Guitar for Gibson {\n",
" fn sound(&self) -> String {\n",
" \"like Slash!\".to_string()\n",
" }\n",
"}\n",
"\n",
"\n",
"// Implement `fn use_guitar` with trait bound in two ways.\n",
"fn use_guitar<G>(g: &G) {\n",
" println!(\"Sounds {}\", g.sound());\n",
"}\n",
"\n",
"// Implement `fn sum` with trait bound in two ways.\n",
"fn sum<T>(x: T, y: T) -> T {\n",
" x + y\n",
"}\n",
"\n",
"fn main() {\n",
" let g = Fender{};\n",
" use_guitar(&g);\n",
" assert_eq!(sum(1, 2), 3);\n",
"\n",
" \n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"4."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// FIX the errors.\n",
"struct Pair<T> {\n",
" x: T,\n",
" y: T,\n",
"}\n",
"\n",
"impl<T> Pair<T> {\n",
" fn new(x: T, y: T) -> Self {\n",
" Self {\n",
" x,\n",
" y,\n",
" }\n",
" }\n",
"}\n",
"\n",
"impl<T: std::fmt::Debug + PartialOrd> Pair<T> {\n",
" fn cmp_display(&self) {\n",
" if self.x >= self.y {\n",
" println!(\"The largest member is x = {:?}\", self.x);\n",
" } else {\n",
" println!(\"The largest member is y = {:?}\", self.y);\n",
" }\n",
" }\n",
"}\n",
"\n",
"struct Unit(i32);\n",
"\n",
"fn main() {\n",
" let pair = Pair{\n",
" x: Unit(1),\n",
" y: Unit(3)\n",
" };\n",
"\n",
" pair.cmp_display();\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"5. Array with trait objects"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"trait Guitar {\n",
" fn sound(&self);\n",
"}\n",
"\n",
"struct Stratocaster;\n",
"\n",
"impl Stratocaster {\n",
" fn get_name(&self) {\n",
" println!(\"Fender Stratocaster\");\n",
" }\n",
"}\n",
"\n",
"struct LesPaul;\n",
"\n",
"impl LesPaul {\n",
" fn get_name(&self) {\n",
" println!(\"Gibson Les Paul\");\n",
" }\n",
"}\n",
"\n",
"impl Guitar for Stratocaster {\n",
" fn sound(&self) {\n",
" println!(\"{}\", \"Sounds like Jimmy!\");\n",
" }\n",
"}\n",
"\n",
"impl Guitar for LesPaul {\n",
" fn sound(&self) {\n",
" println!(\"{}\", \"Sounds like Slash!\");\n",
" }\n",
"}\n",
"\n",
"fn main() {\n",
" // // FILL in the blank to make the code work.\n",
" let s = Stratocaster{};\n",
" let lp1 = LesPaul{};\n",
" let blacky = Stratocaster{};\n",
"\n",
" let guitars: [__; 3]= [__];\n",
"\n",
" // Iterate through the guitars and make them sound.\n",
" todo!();\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"6. &dyn & Box<dyn>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// FILL in the blanks.\n",
"trait Draw {\n",
" fn draw(&self) -> String;\n",
"}\n",
"\n",
"impl Draw for u8 {\n",
" fn draw(&self) -> String {\n",
" format!(\"u8: {}\", *self)\n",
" }\n",
"}\n",
"\n",
"impl Draw for f64 {\n",
" fn draw(&self) -> String {\n",
" format!(\"f64: {}\", *self)\n",
" }\n",
"}\n",
"\n",
"fn main() {\n",
" let x = 1.1f64;\n",
" let y = 8u8;\n",
"\n",
" // Draw x.\n",
" draw_with_box(__);\n",
"\n",
" // Draw y.\n",
" draw_with_ref(&y);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"fn draw_with_box(x: Box<__>) {\n",
" x.draw();\n",
"}\n",
"\n",
"fn draw_with_ref(x: __) {\n",
" x.draw();\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"7. Static and Dynamic dispatch"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"\n",
"trait Foo {\n",
" fn method(&self) -> String;\n",
"}\n",
"\n",
"impl Foo for u8 {\n",
" fn method(&self) -> String { format!(\"u8: {}\", *self) }\n",
"}\n",
"\n",
"impl Foo for String {\n",
" fn method(&self) -> String { format!(\"string: {}\", *self) }\n",
"}\n",
"\n",
"// IMPLEMENT below with generics. (static polymorphism)\n",
"fn static_dispatch...\n",
"\n",
"// Implement below with trait objects. (dynamic polymorphism)\n",
"fn dynamic_dispatch...\n",
"\n",
"fn main() {\n",
" let x = 5u8;\n",
" let y = \"Hello\".to_string();\n",
"\n",
" static_dispatch(x);\n",
" dynamic_dispatch(&y);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "Rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View file

@ -0,0 +1,202 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "19ddc3b6",
"metadata": {},
"source": [
"# Generics\n",
"\n",
"## Functions"
]
},
{
"cell_type": "markdown",
"id": "dc4012b9",
"metadata": {},
"source": [
"1."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1f850fa6",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"\n",
"// Fill in the blanks to make it work\n",
"struct A; // Concrete type `A`.\n",
"struct S(A); // Concrete type `S`.\n",
"struct SGen<T>(T); // Generic type `SGen`.\n",
"\n",
"fn reg_fn(_s: S) {}\n",
"\n",
"fn gen_spec_t(_s: SGen<A>) {}\n",
"\n",
"fn gen_spec_i32(_s: SGen<i32>) {}\n",
"\n",
"fn generic<T>(_s: SGen<T>) {}\n",
"\n",
"fn main() {\n",
" // Using the non-generic functions\n",
" reg_fn(__); // Concrete type.\n",
" gen_spec_t(__); // Implicitly specified type parameter `A`.\n",
" gen_spec_i32(__); // Implicitly specified type parameter `i32`.\n",
"\n",
" // Explicitly specified type parameter `char` to `generic()`.\n",
" generic::<char>(__);\n",
"\n",
" // Implicitly specified type parameter `char` to `generic()`.\n",
" generic(__);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"id": "584e4753",
"metadata": {},
"source": [
"2."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2f005be9",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Implement the generic function below.\n",
"fn sum\n",
"\n",
"fn main() {\n",
" assert_eq!(5, sum(2i8, 3i8));\n",
" assert_eq!(50, sum(20, 30));\n",
" assert_eq!(2.46, sum(1.23, 1.23));\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"id": "ad822adf",
"metadata": {},
"source": [
"## Struct and impl"
]
},
{
"cell_type": "markdown",
"id": "a3df7fa0",
"metadata": {},
"source": [
"3."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "52333cde",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Implement struct Point to make it work.\n",
"\n",
"fn main() {\n",
" let pt_integer = Point { x: 5, y: 10 };\n",
" println!(\"pt_integer: {:?}\", pt_integer);\n",
" assert_eq!(pt_integer.x(), 5);\n",
" assert_eq!(pt_integer.y(), 10);\n",
"\n",
" let pt_float = Point { x: 1.0, y: 4.0 };\n",
" println!(\"pt_float: {:?}\", pt_float);\n",
" assert_eq!(pt_float.x(), 1.0);\n",
" assert_eq!(pt_float.y(), 4.0);\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"id": "a1621757",
"metadata": {},
"source": [
"4."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0e5292ca",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"// Fix the errors to make the code work.\n",
"struct Point<T> {\n",
" x: T,\n",
" y: T,\n",
"}\n",
"\n",
"impl Point<f32> {\n",
" fn distance_from_origin(&self) -> f32 {\n",
" (self.x.powi(2) + self.y.powi(2)).sqrt()\n",
" }\n",
"}\n",
"\n",
"fn main() {\n",
" let p = Point{x: 5, y: 10};\n",
" println!(\"{}\",p.distance_from_origin());\n",
"\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "Rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View file

@ -0,0 +1,187 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Closures"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1. Define a closure that adds two numbers and use it in `main`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "900b12e8",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"\n",
"fn main() {\n",
" let add = __;\n",
" \n",
" let result = add(2, 3);\n",
" assert_eq!(result, 5);\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();\n"
]
},
{
"cell_type": "markdown",
"id": "81717c46",
"metadata": {},
"source": [
"2. Create a closure that captures a variable from the surrounding scope."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "15a2bd11",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" let multiplier = 3;\n",
" let multiply = __;\n",
"\n",
" assert_eq!(multiply(4), 12);\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();\n"
]
},
{
"cell_type": "markdown",
"id": "8a3becbc",
"metadata": {},
"source": [
"3. Pass a closure into a generic function that accepts `Fn(i32) -> i32`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "015aebe2",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn apply<F>(f: F, value: i32) -> i32\n",
"where\n",
" F: Fn(i32) -> i32,\n",
"{\n",
" f(value)\n",
"}\n",
"\n",
"fn main() {\n",
" let add_one = __;\n",
" let result = apply(add_one, 10);\n",
"\n",
" assert_eq!(result, 11);\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();\n"
]
},
{
"cell_type": "markdown",
"id": "5ba5c844",
"metadata": {},
"source": [
"4. Use a mutable closure that updates a captured counter each time it is called."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b37b49eb",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" let mut counter = 0;\n",
" let mut increment = __;\n",
"\n",
" assert_eq!(increment(), 1);\n",
" assert_eq!(increment(), 2);\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();\n"
]
},
{
"cell_type": "markdown",
"id": "637a4a78",
"metadata": {},
"source": [
"5. Create a `move` closure that takes ownership of a captured `String`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "58d65ccc",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" let message = String::from(\"Hello\");\n",
" let consume = __;\n",
"\n",
" let result = consume();\n",
" assert_eq!(result, \"Hello world!!!\");\n",
" println!(\"Success!\");\n",
"}\n",
"\n",
"main();"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "Rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View file

@ -0,0 +1,6 @@
[package]
name = "vector"
version = "0.1.0"
edition = "2021"
[dependencies]

View file

@ -0,0 +1,11 @@
mod vector;
// use vector::Vector2D;
fn main() {
// let v1 = Vector2D::new(1.0, 2.0);
// let v2 = Vector2D::new(1.0, 2.0);
// println!("v1 == v2: {}", v1 == v2);
// println!("v1 + v2: {:?}", v1 + v2);
}

View file

@ -0,0 +1,143 @@
#[cfg(test)]
mod tests_vector2d {
// use super::*;
// #[test]
// fn explicit_construction() {
// let v = Vector2D { x: 1.0, y: 2.0 };
// assert_eq!(v.x, 1.0);
// assert_eq!(v.y, 2.0);
// }
// #[test]
// fn new_method() {
// let v = Vector2D::new(1.0, 2.0);
// assert_eq!(v.x, 1.0);
// assert_eq!(v.y, 2.0);
// }
// #[test]
// fn default_trait() {
// let v = Vector2D::default();
// assert_eq!(v.x, 0.0);
// assert_eq!(v.y, 0.0);
// }
// #[test]
// fn is_copyable() {
// let v = Vector2D::new(1.0, 2.0);
// let v2 = v;
// assert_eq!(v, v2);
// }
// #[test]
// fn is_clonable() {
// let v = Vector2D::new(1.0, 2.0);
// let v2 = v.clone();
// assert_eq!(v, v2);
// }
// #[test]
// fn debug_format() {
// let v = Vector2D::new(1.0, 2.0);
// assert_eq!(format!("{:?}", v), "Vector2D { x: 1.0, y: 2.0 }");
// }
// #[test]
// fn length() {
// let v = Vector2D::new(3.0, 4.0);
// assert_eq!(v.length(), 5.0);
// }
// #[test]
// fn scale() {
// let v = Vector2D::new(1.0, 2.0);
// let scaled_v = v.scale(2.0);
// assert_eq!(scaled_v, Vector2D::new(2.0, 4.0));
// }
// #[test]
// fn partial_eq() {
// let v1 = Vector2D::new(1.0, 2.0);
// let v2 = Vector2D::new(1.0, 2.0);
// assert_eq!(v1, v2);
// }
// #[test]
// fn zero_associated_constant() {
// let z = Vector2D::ZERO;
// assert_eq!(z, Vector2D::new(0.0, 0.0));
// }
// #[test]
// fn unit_vectors() {
// let unit_x = Vector2D::UNIT_X;
// assert!(unit_x.x == 1.0 && unit_x.y == 0.0);
// let unit_y = Vector2D::UNIT_Y;
// assert!(unit_y.x == 0.0 && unit_y.y == 1.0);
// }
// #[test]
// fn negation() {
// let v = Vector2D::new(1.0, 2.0);
// let neg_v = -v;
// assert_eq!(neg_v, Vector2D::new(-1.0, -2.0));
// }
// #[test]
// fn addition() {
// let v1 = Vector2D::new(1.0, 2.0);
// let v2 = Vector2D::new(3.0, 4.0);
// let v3 = v1 + v2;
// assert_eq!(v3, Vector2D::new(4.0, 6.0));
// }
// #[test]
// fn subtraction() {
// let v1 = Vector2D::new(1.0, 2.0);
// let v2 = Vector2D::new(3.0, 4.5);
// let v3 = v1 - v2;
// assert_eq!(v3, Vector2D::new(-2.0, -2.5));
// }
// #[test]
// fn scalar_product() {
// let v1 = Vector2D::new(1.0, 2.0);
// let v2: Vector2D = Vector2D::new(2.0, 3.0);
// let product = v1 * v2;
// assert_eq!(product, 8.0);
// }
// #[test]
// fn multiplication_with_scalar() {
// let v = Vector2D::new(1.0, 2.0);
// let v_scaled = v * 2.0;
// assert_eq!(v_scaled, Vector2D::new(2.0, 4.0));
// }
// #[test]
// #[should_panic]
// fn index() {
// let v = Vector2D::new(1.0, 2.0);
// assert_eq!(v[0], 1.0);
// assert_eq!(v[1], 2.0);
// let _ = v[2];
// }
// #[test]
// fn index_mut() {
// let mut v = Vector2D::new(1.0, 2.0);
// v[0] = 3.0;
// v[1] = 4.0;
// assert_eq!(v, Vector2D::new(3.0, 4.0));
// }
// #[test]
// fn convert_from_tuple() {
// let v_tuple = (1.0, 2.0);
// let v = Vector2D::from(v_tuple);
// assert_eq!(v, Vector2D::new(1.0, 2.0));
// }
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,674 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Control flow"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Statements & Expressions\n",
"\n",
"### Statements\n",
"\n",
"* Statements must end with a semicolon"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"y = 30\n"
]
}
],
"source": [
"let x = 10;\n",
"let mut y = 20;\n",
"y += x;\n",
"println!(\"y = {y}\");"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Expressions\n",
"\n",
"* Rust is an **expression-oriented language**, which means that most pieces of code are in fact expressions\n",
"* A code block is also an expression, which returns the value of its last expression if we omit the semicolon"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"result = 30\n"
]
}
],
"source": [
"let result = {\n",
" let a = 10;\n",
" let b = 20;\n",
" a + b // no semicolon before end of the block\n",
"};\n",
"\n",
"println!(\"result = {}\", result);"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"let result = {\n",
" let a = 10;\n",
" let b = 20;\n",
" a + b; // now result of an expression is ()\n",
"};\n",
"\n",
"result"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conditional Statements with `if` and `else`"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The number 7 is odd.\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"let n = 7;\n",
"\n",
"if n % 2 == 0 {\n",
" println!(\"The number {n} is even.\");\n",
"} else {\n",
" println!(\"The number {n} is odd.\");\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### `if-else` as an expression\n",
"\n",
"* if else condition is an expression that returns a value\n",
"* all branches always must return a value of the same type"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"data": {
"text/plain": [
"\"adult\""
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"let age = 44;\n",
"let is_adult = if age >= 18 { true } else { false };\n",
"let description = if is_adult { \"adult\" } else { \"minor\" };\n",
"description"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## `while` loop"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Current count: 0\n",
"Current count: 1\n",
"Current count: 2\n",
"Current count: 3\n",
"Current count: 4\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"let mut count = 0;\n",
"\n",
"while count < 5 {\n",
" println!(\"Current count: {}\", count);\n",
" count += 1;\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Infinity `loop`\n",
"\n",
"Use loop to write infinite loops. It executes the block repeatedly forever (or until a break or return is reached, or the thread panics)."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1 * 1 = 1\n",
"3 * 3 = 9\n",
"5 * 5 = 25\n",
"7 * 7 = 49\n",
"9 * 9 = 81\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"let mut n = 0;\n",
"let mut power: u32;\n",
"let max_power = 100;\n",
"\n",
"loop {\n",
" n += 1;\n",
" power = n * n;\n",
"\n",
" if power >= max_power {\n",
" break; \n",
" }\n",
"\n",
" if power % 2 == 0 {\n",
" continue;\n",
" }\n",
"\n",
" println!(\"{} * {} = {}\", n, n, power); \n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Nested loops\n",
"\n",
"* When loops are nested inside each other, the `break` and `continue` statements apply to the immediate enclosing loop. \n",
"* Any loop statement (also the while and for loop) can be preceded by a label (denoted as labelname:) to allow us to jump to the next or outer enclosing loop"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Enter the outer loop\n",
"Enter the inner loop\n",
"Exited the outer loop\n"
]
}
],
"source": [
"'outer: loop {\n",
" println!(\"Enter the outer loop\");\n",
" 'inner: loop {\n",
" println!(\"Enter the inner loop\");\n",
" break 'outer; // breaks the outer loop\n",
" }\n",
" println!(\"This will never be printed...\");\n",
"}\n",
"println!(\"Exited the outer loop\");"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## `for` loops"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* looping where variable `i` begins from a start value `a` to an end value `b` (exclusive)\n",
"* each subsequent value is bound to the variable `i` and used in the next loop iteration"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"i = 0\n",
"i = 1\n",
"i = 2\n",
"i = 3\n",
"i = 4\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"for i in 0..5 {\n",
" println!(\"i = {}\", i);\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* inclusive version of `for`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"i = 1\n",
"i = 2\n",
"i = 3\n",
"i = 4\n",
"i = 5\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"for i in 1..=5 {\n",
" println!(\"i = {}\", i);\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* if we don't need the value of the variable `i` in the loop, we can replace it with an `_` (underscore):"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Do it again!\n",
"Do it again!\n",
"Do it again!\n",
"Do it again!\n",
"Do it again!\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"for _ in 0..5 { println!(\"Do it again!\"); } "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* iteration in reverse using `(a..b).rev()`"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"i: 10\n",
"i: 9\n",
"i: 8\n",
"i: 7\n",
"i: 6\n",
"i: 5\n",
"i: 4\n",
"i: 3\n",
"i: 2\n",
"i: 1\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"for i in (1..=10).rev() {\n",
" println!(\"i: {}\", i);\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Looping through the collection with `for`"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"item: 1\n",
"item: 64\n",
"item: 42\n",
"item: 665\n",
"item: -123\n",
"item: -2\n",
"item: 6\n",
"item: 0\n",
"item: 57\n",
"item: -1\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"let data: [i32; 10] = [1, 64, 42, 665, -123, -2, 6, 0, 57, -1];\n",
"\n",
"for item in data {\n",
" println!(\"item: {}\", item);\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2 is prime!\n",
"3 is prime!\n",
"5 is prime!\n",
"7 is prime!\n",
"11 is prime!\n",
"13 is prime!\n",
"17 is prime!\n",
"19 is prime!\n",
"23 is prime!\n",
"29 is prime!\n",
"31 is prime!\n",
"37 is prime!\n",
"41 is prime!\n",
"43 is prime!\n",
"47 is prime!\n",
"53 is prime!\n",
"59 is prime!\n",
"61 is prime!\n",
"67 is prime!\n",
"71 is prime!\n",
"73 is prime!\n",
"79 is prime!\n",
"83 is prime!\n",
"89 is prime!\n",
"97 is prime!\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"let max_prime = 100;\n",
"\n",
"for n in 2..=max_prime {\n",
" let mut is_prime = true;\n",
" for d in 2..=((n as f64).sqrt() as i32) {\n",
" if n % d == 0 {\n",
" is_prime = false;\n",
" break;\n",
" }\n",
" }\n",
"\n",
" if is_prime {\n",
" println!(\"{} is prime!\", n);\n",
" }\n",
"}"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "Rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View file

@ -0,0 +1,912 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Ownership\n",
"\n",
"* Memory is managed through a system of **ownership** with a set of rules that the compiler checks. \n",
"* If any of the rules are violated, the program won’t compile. \n",
"* None of the features of ownership will slow down your program while it’s running.\n",
"\n",
"## Ownership rules\n",
"\n",
"* Each value in Rust has an owner.\n",
"* There can only be one owner at a time.\n",
"* When the owner goes out of scope, the value will be dropped.\n",
"\n",
"## Variable scope\n",
"\n",
"* The **variable** is valid from the point at which it’s declared until the end of the current **scope**\n",
"* There are two important points in time here:\n",
" * when `s` comes into scope, it is valid.\n",
" * it remains valid until it goes out of scope."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Rusty Cage!\n"
]
}
],
"source": [
"{\n",
" let mut s = String::from(\"Rusty\"); // s allocates memory on the heap\n",
" s.push_str(\" Cage!\"); // ... do something with 's'\n",
" println!(\"{}\", s);\n",
" \n",
"} // 's' goes out of scope, and memory is deallocated"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Copy & Move for objects"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Copy\n",
"\n",
"* If a type implements the `Copy` trait, variables that use it do not move, but rather are trivially copied, making them still valid after assignment to another variable.\n",
"\n",
"* Primitive types that implement `Copy` trait are:\n",
" * all the integer types, such as `u32`.\n",
" * the Boolean type, `bool`, with values `true` and `false`.\n",
" * all the floating-point types, such as `f64`.\n",
" * the character type, `char`.\n",
" * tuples, if they only contain types that also implement `Copy`. For example, `(i32, i32)` implements `Copy`, but `(i32, String)` does not.\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x=10; y=10\n"
]
}
],
"source": [
"let x = 10;\n",
"let y = x;\n",
"\n",
"println!(\"x={x}; y={y}\");"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Move\n",
"\n",
"* Objects that allocate memory on heap are moved by default (shallow copy is disabled by default)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Rusty\n"
]
}
],
"source": [
"let s1 = String::from(\"Rusty\");\n",
"let s2 = s1;\n",
"\n",
"println!(\"{s2}\");"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"ename": "Error",
"evalue": "borrow of moved value: `s1`",
"output_type": "error",
"traceback": [
"\u001b[31m[E0382] Error:\u001b[0m borrow of moved value: `s1`",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_17:1:1\u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;100m1\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mS\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mR\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m ",
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m move occurs because `s1` has type `String`, which does not implement the `Copy` trait",
" \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54m1\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;68m│\u001b[0m ",
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m value moved here",
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;68m│\u001b[0m ",
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m help: consider cloning the value if the performance cost is acceptable: `.clone()`",
"\u001b[38;5;246m───╯\u001b[0m"
]
}
],
"source": [
"let s1 = String::from(\"Rusty\");\n",
"let s2 = s1;\n",
"\n",
"s1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* How it works\n",
"\n",
"<img src=\"images/rust-move.png\" alt=\"rust-move\" height=\"400\" align=\"center\" />"
]
},
{
"cell_type": "markdown",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"source": [
"* if we do want to make a deep copy the heap data of the `String`, not just the stack data, we can use a common method called `clone()`."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"s1 = hello, s2 = hello\n"
]
}
],
"source": [
"let s1 = String::from(\"hello\");\n",
"let s2 = s1.clone();\n",
"\n",
"println!(\"s1 = {s1}, s2 = {s2}\");"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"images/rust-clone.png\" alt=\"rust-clone\" height=\"400\" align=\"center\" />"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Move and Indexed Content\n",
"\n",
"* When we move a vector, the vector itself is moved, but its indexed content cannot be moved."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"ename": "Error",
"evalue": "cannot move out of index of `Vec<String>`",
"output_type": "error",
"traceback": [
"\u001b[31m[E0507] Error:\u001b[0m cannot move out of index of `Vec<String>`",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_6:1:1 \u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mw\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54m[\u001b[0m\u001b[38;5;54m0\u001b[0m\u001b[38;5;54m]\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;68m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m help: consider borrowing here: `&`",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m│\u001b[0m \u001b[38;5;68m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m move occurs because value has type `String`, which does not implement the `Copy` trait",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m help: consider cloning the value if the performance cost is acceptable: `.clone()`",
"\u001b[38;5;246m───╯\u001b[0m"
]
},
{
"ename": "Error",
"evalue": "cannot move out of index of `Vec<String>`",
"output_type": "error",
"traceback": [
"\u001b[31m[E0507] Error:\u001b[0m cannot move out of index of `Vec<String>`",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_6:1:1 \u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mw\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54m[\u001b[0m\u001b[38;5;54m1\u001b[0m\u001b[38;5;54m]\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;68m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m help: consider borrowing here: `&`",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m│\u001b[0m \u001b[38;5;68m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m move occurs because value has type `String`, which does not implement the `Copy` trait",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m help: consider cloning the value if the performance cost is acceptable: `.clone()`",
"\u001b[38;5;246m───╯\u001b[0m"
]
}
],
"source": [
"let mut words = vec![\"hello\".to_string(), \"world\".to_string(), \"!!!\".to_string()];\n",
"\n",
"let first_word = words[0];\n",
"let second_word = words[1];"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* We can move (consume) items of a vector in a loop:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[\"hello\", \"world\", \"!!!\"]\n"
]
}
],
"source": [
"let mut target_words: Vec<String> = Vec::new();\n",
"\n",
"let mut words = vec![\"hello\".to_string(), \"world\".to_string(), \"!!!\".to_string()];\n",
"\n",
"for word in words {\n",
" target_words.push(word);\n",
"}\n",
"\n",
"println!(\"{:?}\", target_words);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Ownership and functions\n",
"\n",
"* The mechanics of passing a value to a function are similar to those when assigning a value to a variable\n",
"* Passing a variable to a function will move or copy, just as assignment does"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"number = 3.14159\n",
"pi = 3.14159\n",
"text = TEXT\n"
]
}
],
"source": [
"fn takes_ownership(text: String) {\n",
" println!(\"text = {text}\");\n",
"} \n",
"\n",
"fn takes_copy(number: f64) {\n",
" println!(\"number = {number}\");\n",
"}\n",
"\n",
"fn main() {\n",
" let pi = 3.14159;\n",
" takes_copy(pi);\n",
" println!(\"pi = {pi}\");\n",
"\n",
" let text = String::from(\"TEXT\");\n",
" takes_ownership(text);\n",
" // println!(\"text = {text}\"); // comment-out this line\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Return Values and Scope\n",
"\n",
"* Returning values can also transfer ownership"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Ownership!!!\n",
"Ownership!!!\n"
]
}
],
"source": [
"fn gives_ownership() -> String {\n",
" let text = String::from(\"Ownership!!!\");\n",
"\n",
" text\n",
"}\n",
"\n",
"fn transfers_ownership(text: String) -> String {\n",
" text\n",
"}\n",
"\n",
"fn main() {\n",
" let txt1 = gives_ownership();\n",
" let txt2 = transfers_ownership(txt1);\n",
" // println!(\"{txt1}\"); // comment-out this line\n",
" println!(\"{txt2}\");\n",
"\n",
" println!(\"{}\", transfers_ownership(gives_ownership())); \n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# References & Borrowing\n",
"\n",
"* A reference lets you access a value without affecting its ownership. References come in two kinds:\n",
" * A **shared reference** lets you read but not modify its referent. However, you can have as many shared references to a particular value at a time as you like. The expression `&e` yields a shared reference to `e`’s value; if `e` has the type `T`, then `&e` has the type `&T`, pronounced “ref T”. Shared references are `Copy`\n",
" * If you have a **mutable reference** to a value, you may both read and modify the value. However, you may not have any other references of any sort to that value active at the same time. The expression `&mut e` yields a mutable reference to `e`’s value; you write its type as `&mut T`, which is pronounced “ref mute T”. Mutable references are not `Copy`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* In Rust, references are created explicitly with the `&` operator, and dereferenced explicitly with the `*` operator:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"{\n",
" let x = 10;\n",
" let rx = &x; // &x is a shared reference to x\n",
" \n",
" assert!(*rx == 10); // explcitly dereference rx\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* To create a mutable reference, use the `&mut` operator:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"{\n",
" let mut y = 42;\n",
" let ry = &mut y; // &mut y is a mutable reference to y\n",
" *ry += 10;\n",
" \n",
" assert!(y == 52);\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assigning References"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Assigning to a Rust reference makes it point at a new value:"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"{\n",
" let flag = true;\n",
"\n",
" let x = 10;\n",
" let y = 20;\n",
" let mut r: &i32 = &x;\n",
"\n",
" if flag { r = &y; }\n",
"\n",
" assert!(*r == 10 || *r == 20);\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### References to References\n",
"\n",
"* Rust permits references to references.\n",
"* Explicit dereferencing requires as many `*` as levels of indirections\n",
"* The `.` operator follows as many references as it takes to find its target."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
"struct Point { x: i32, y: i32 }\n",
"\n",
"fn ref_to_ref() {\n",
" let point = Point { x: 1000, y: 729 };\n",
"\n",
" let ry: &i32 = &point.y;\n",
" let rry: &&i32 = &ry;\n",
" let rrry: &&&i32 = &rry;\n",
" assert!(***rrry == 729);\n",
"\n",
" let r: &Point = &point;\n",
" let rr: &&Point = &r;\n",
" let rrr: &&&Point = &rr;\n",
" assert!(rrr.y == 729);\n",
"}\n",
"\n",
"ref_to_ref();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Comparing References\n",
"\n",
"* Like the `.` operator, Rust’s comparison operators “see through” any number of references, as long as both operands have the same type.\n",
"* If you actually want to know whether two references point to the same memory, you can use `std::ptr::eq`, which compares them as addresses:"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"{\n",
" let x = 10;\n",
" let y = 10;\n",
"\n",
" let rx = &x;\n",
" let ry = &y;\n",
"\n",
" assert!(rx == ry); // their referents are equal\n",
" assert!(!std::ptr::eq(rx, ry)); // but occupy different addresses\n",
" \n",
" let rrx = &rx;\n",
" let rry = &ry;\n",
"\n",
" assert!(**rrx <= **rry); // explicit dereferencing using **\n",
" assert!(rrx == rry); // implicit dereferencing using **\n",
" assert!(rrx <= rry);\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### References Are Never Null\n",
"* Rust references are never null. \n",
" * there’s no analogue to C’s `NULL` or C++’s `nullptr`\n",
" * and Rust won’t convert integers to references (outside of unsafe code), so you can’t convert zero into a reference."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Borrowing References to Arbitrary Expressions\n",
"\n",
"* Rust lets you borrow a reference (apply `&`) to the value of any sort of expression:"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [],
"source": [
"fn factorial(n: usize) -> usize {\n",
" (1..n+1).fold(1, |a, b| a * b)\n",
"}\n",
"\n",
"fn main() {\n",
" let r = &factorial(6);\n",
"\n",
" // Arithmetic operators can see through one level of references.\n",
" assert_eq!(r + &1009, 1729);\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Rust simply creates an anonymous variable to hold the expression’s value, and makes the reference point to that. The lifetime of this anonymous variable depends on what you do with the reference:\n",
"\n",
" * if you immediately assign the reference to a variable in a `let` statement (or make it part of some struct or array that is being immediately assigned), then Rust makes the anonymous variable live as long as the variable the `let` initializes. In the preceding example, Rust would do this for the referent of `r`.\n",
" * Otherwise, the anonymous variable lives to the end of the enclosing statement. In our example, the anonymous variable created to hold `1009` lasts only to the end of the `assert_eq!` statement."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Reference safety\n",
"\n",
"### Borrowing a Local \n",
"\n",
"* You can’t borrow a reference to a local variable and take it out of the variable’s scope:"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"ename": "Error",
"evalue": "`x` does not live long enough",
"output_type": "error",
"traceback": [
"\u001b[31m[E0597] Error:\u001b[0m `x` does not live long enough",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_29:1:1 \u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m4\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m┬\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m binding `x` declared here",
" \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;54mx\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m borrowed value does not live long enough",
" \u001b[38;5;246m7 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m}\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m┬\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m `x` dropped here while still borrowed",
" \u001b[38;5;240m │\u001b[0m ",
" \u001b[38;5;246m9 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;37m*\u001b[0m\u001b[38;5;37mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;37m─\u001b[0m\u001b[38;5;37m┬\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m borrow later used here",
"\u001b[38;5;246m───╯\u001b[0m"
]
}
],
"source": [
"{\n",
" let r;\n",
"\n",
" {\n",
" let x = 42;\n",
" r = &x;\n",
" }\n",
"\n",
" assert!(*r == 1);\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Receiving References as Parameters"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Static variables\n",
"\n",
"* Rust’s equivalent of a global variable is called a **static**\n",
"* It’s a value that’s created when the program starts and lasts until it terminates\n",
"* Every static must be initialized\n",
"* **Mutable statics** are inherently not thread-safe (after all, any thread can access a static at any time), and even in single-threaded programs, they can fall prey to other sorts of reentrancy problems. For these reasons, you may access a mutable static only within an `unsafe` block.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Assignment to static reference\n",
"\n",
"* Static references can only refer to other statics - this avoids dangling reference\n",
"* In the code below variable `p` has some lifetime (but it is not a static) `=>` Rust rejects this code - assignment `p` to `STASH` could lead to dangling reference "
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"ename": "Error",
"evalue": "lifetime may not live long enough",
"output_type": "error",
"traceback": [
"\u001b[31mError:\u001b[0m lifetime may not live long enough",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_9:1:1\u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m┬\u001b[0m ",
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m let's call the lifetime of this reference `'1`",
" \u001b[38;5;246m ·\u001b[0m ",
" \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mS\u001b[0m\u001b[38;5;100mT\u001b[0m\u001b[38;5;100mA\u001b[0m\u001b[38;5;100mS\u001b[0m\u001b[38;5;100mH\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100m=\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100mp\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m ",
" \u001b[38;5;246m ·\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m assignment requires that `'1` must outlive `'static`",
"\u001b[38;5;246m───╯\u001b[0m"
]
}
],
"source": [
"static mut STASH: &i32 = &128;\n",
"\n",
"fn put_on_stash(p: &i32) {\n",
" unsafe {\n",
" STASH = p;\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* In order to compile `put_on_stash()` function we have annotate that `p` is a reference to static data"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"static mut STASH: &i32 = &10;\n",
"\n",
"fn put_on_stash(p: &'static i32) {\n",
" unsafe {\n",
" STASH = p;\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"665"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"static SOME_DATA: i32 = 665;\n",
"\n",
"put_on_stash(&SOME_DATA);\n",
"\n",
"unsafe { *STASH }"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Returning references"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Functions can return references\n",
"* Dangling references are reported at compile time"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"fn smallest(v: &[i32]) -> &i32 {\n",
" let mut smallest_value: &i32 = &v[0];\n",
"\n",
" for value in &v[1..] {\n",
" if *value < *smallest_value {\n",
" smallest_value = value;\n",
" } \n",
" }\n",
" smallest_value\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"ename": "Error",
"evalue": "cannot find function `smallest` in this scope",
"output_type": "error",
"traceback": [
"\u001b[31m[E0425] Error:\u001b[0m cannot find function `smallest` in this scope",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_30:1:1 \u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249m)\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
"\u001b[38;5;246m───╯\u001b[0m"
]
}
],
"source": [
"let v;\n",
"{\n",
" let data = [5, 345, 1, 4, 42, 665];\n",
" v = smallest(&data)\n",
"}\n",
"assert!(*v == 1);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Correct version of the snippet above"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"ename": "Error",
"evalue": "cannot find function `smallest` in this scope",
"output_type": "error",
"traceback": [
"\u001b[31m[E0425] Error:\u001b[0m cannot find function `smallest` in this scope",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_31:1:1 \u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
"\u001b[38;5;246m───╯\u001b[0m"
]
}
],
"source": [
"{\n",
" let data = [5, 345, 1, 4, 42, 665];\n",
" let v = smallest(&data);\n",
" assert!(*v == 1);\n",
"}"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,564 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Structs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* A *struct* assembles several values of assorted types together into a single value, so you can deal with them as a unit. \n",
"* Given a struct, you can read and modify its individual components. \n",
"* A struct can have methods associated with it that operate on its components."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Named-Field Structs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Declaring a Struct"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"// A rectangle of eight-bit grayscale pixels.\n",
"struct GrayscaleMap {\n",
" pixels: Vec<u8>,\n",
" size: (usize, usize)\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Creating a Struct Value"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"let width = 800;\n",
"let height = 600;\n",
"\n",
"let image = GrayscaleMap {\n",
" pixels: vec![0; width * height],\n",
" size: (width, height)\n",
"};"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"fn create_image(size: (usize, usize)) -> GrayscaleMap {\n",
" let pixels = vec![0; size.0 * size.1];\n",
" GrayscaleMap{pixels, size} // struct expression\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Accessing Struct Fields"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"let image = create_image((800, 600));\n",
"\n",
"assert!(image.size == (800, 600));\n",
"assert!(image.pixels.len() == image.size.0 * image.size.1);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Visibility of Struct"
]
},
{
"cell_type": "markdown",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"source": [
"* Structs are private by default, visible only in the module where they’re declared. \n",
"* You can make a struct visible outside its module by prefixing its definition with `pub`"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"// A rectangle of eight-bit grayscale pixels.\n",
"pub struct GrayscaleMap {\n",
" pub pixels: Vec<u8>,\n",
" pub size: (usize, usize)\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Tuple-Like Structs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* The second kind of struct type is called a tuple-like struct, because it resembles a tuple:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"The type of the variable image was redefined, so was lost.\n"
]
}
],
"source": [
"struct BoundingBox(usize, usize);\n",
"\n",
"let image_bbox = BoundingBox(800, 600);\n",
"\n",
"assert!(image_bbox.0 * image_bbox.1 == 480_000);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Individual elements of a tuple-like struct may be public or not:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"pub struct BoundingBox(pub usize, pub usize);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Tuple-Like Struct as Newtypes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Tuple-like structs allow you to create types that behave like tuples but have a name and can implement traits\n",
"* This allows you to create newtypes for stricter type checking\n",
"* This is a workaround for the *orphan rule* - [New Type Pattern](https://doc.rust-lang.org/book/ch20-02-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"The type of the variable image_bbox was redefined, so was lost.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Distance traveled: 50 kilometers\n"
]
}
],
"source": [
"struct Distance(f64);\n",
"struct Velocity(f64);\n",
"struct Time(f64);\n",
"\n",
"// A newtype for stricter type checking\n",
"fn calculate_distance(velocity: Velocity, time: Time) -> Distance {\n",
" Distance(velocity.0 * time.0)\n",
"}\n",
"\n",
"let velocity = Velocity(10.0);\n",
"let time = Time(5.0);\n",
"let distance = calculate_distance(velocity, time);\n",
"\n",
"println!(\"Distance traveled: {} kilometers\", distance.0);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Unit-Like Structs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* The third kind of struct is a little obscure: it declares a struct type with no elements at all:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"struct Onesuch;\n",
"\n",
"let o = Onesuch;"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* This allows to create types that can act as tags or markers"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Defining Methods - `impl`"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"pub struct Queue {\n",
" older: Vec<char>,\n",
" younger: Vec<char>\n",
"}\n",
"\n",
"impl Queue {\n",
" pub fn push(&mut self, c: char) {\n",
" self.younger.push(c);\n",
" }\n",
"\n",
" pub fn pop(&mut self) -> Option<char> {\n",
" if self.older.is_empty() {\n",
" if self.younger.is_empty() {\n",
" return None;\n",
" }\n",
"\n",
" use std::mem::swap;\n",
" swap(&mut self.older, &mut self.younger);\n",
" self.older.reverse();\n",
" }\n",
"\n",
" self.older.pop()\n",
" }\n",
"\n",
" pub fn is_empty(&self) -> bool {\n",
" self.older.is_empty() && self.younger.is_empty()\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"let mut q = Queue{ older: Vec::new(), younger: Vec::new() };\n",
"\n",
"q.push('@');\n",
"q.push('$');\n",
"assert!(q.pop() == Some('@'));\n",
"\n",
"q.push('*');\n",
"assert!(q.pop() == Some('$'));\n",
"assert!(q.pop() == Some('*'));\n",
"assert!(q.pop() == None);\n",
"\n",
"assert!(q.is_empty());"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"impl Queue {\n",
" pub fn split(self) -> (Vec<char>, Vec<char>) {\n",
" (self.older, self.younger)\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"let mut q = Queue { older: Vec::new(), younger: Vec::new() };\n",
"q.push('Q');\n",
"q.push('U');\n",
"assert!(q.pop() == Some('Q'));\n",
"q.push('X');\n",
"\n",
"let (older, younger) = q.split();\n",
"\n",
"assert_eq!(older, vec!['U']);\n",
"assert_eq!(younger, vec!['X']);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### `new` Method"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Constructor function - doesn't take `self` as an argument (**static function**)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"impl Queue {\n",
" pub fn new() -> Self {\n",
" Queue { older: Vec::new(), younger: Vec::new() }\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"let mut q = Queue::new();\n",
"\n",
"q.push('a');\n",
"q.push('b');\n",
"q.push('c');\n",
"\n",
"assert_eq!(q.pop(), Some('a'));\n",
"assert_eq!(q.pop(), Some('b'));\n",
"assert_eq!(q.pop(), Some('c'));\n",
"assert_eq!(q.pop(), None);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Generic Structs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Generics allow you to write flexible, reusable functions and types that can work with any data type. Instead of specifying concrete types, you use type parameters, which are placeholders for types that will be specified when the function or type is used.\n",
"* Generics use parameters passed in angle brackets to specify the types they work with. For example, `fn example<T>(param: T) {}` uses `T` as a generic type parameter."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
"pub struct Stack<T> {\n",
" items: Vec<T>\n",
"}\n",
"\n",
"impl<T> Stack<T> {\n",
" pub fn new() -> Stack<T> {\n",
" Stack{ items: Vec::new() }\n",
" }\n",
"\n",
" pub fn push(&mut self, item: T) {\n",
" self.items.push(item)\n",
" }\n",
"\n",
" pub fn pop(&mut self) -> Option<T> {\n",
" self.items.pop()\n",
" }\n",
"\n",
" pub fn is_empty(&self) -> bool {\n",
" self.items.is_empty()\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* For static method calls, you can supply the type parameter explicitly using the turbofish `::<>` notation:"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [],
"source": [
"let s = Stack::<char>::new();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* But in practice, Rust can figure it out for you:"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [],
"source": [
"let mut stack_1 = Stack::new();\n",
"let mut stack_2 = Stack::new();\n",
"\n",
"stack_1.push(\"Hello\");\n",
"stack_2.push(3.1415);\n",
"\n",
"stack_1.push(\"World\");\n",
"stack_2.push(2.71);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Deriving Common Traits for Structs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Structs are not copyable or comparable by default\n",
"* You can derive the `Copy` and `Clone` traits for a struct type, but only if all its fields are copyable or clonable\n",
"* You can derive the `PartialEq` and `Eq` traits for a struct type, but only if all its fields are comparable for equality\n",
"* You can derive `Debug` for a struct type, but only if all its fields are printable"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [],
"source": [
"#[derive(Copy, Clone, Debug, PartialEq)]\n",
"struct Point {\n",
" x: f64,\n",
" y: f64\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"pt = Point { x: 42.42, y: 1.0 }\n",
"other_pt = Point { x: 0.0, y: 1.0 }\n"
]
}
],
"source": [
"let mut pt = Point{ x: 0.0, y: 1.0 };\n",
"\n",
"let other_pt = pt;\n",
"assert!(pt == other_pt);\n",
"\n",
"pt.x = 42.42;\n",
"assert!(pt != other_pt);\n",
"\n",
"println!(\"pt = {:?}\", pt);\n",
"println!(\"other_pt = {:?}\", other_pt);"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,938 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Error handling"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Panic\n",
"\n",
"* A program panics when it encounters something so messed up that there must be a bug in the program itself. Something like:\n",
" * Out-of-bounds array access\n",
" * Integer division by zero\n",
" * Calling `.unwrap()` on an `Option` that happens to be `None`\n",
" * Assertion failure\n",
"* A panic is not a crash. It’s not undefined behavior. The behavior is well-defined!\n",
"* Macro `panic!` can trigger a panic directly"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\n",
"thread '<unnamed>' panicked at src\\lib.rs:6:1:\n",
"Critical error!\n",
"stack backtrace:\n",
" 0: std::panicking::begin_panic_handler\n",
" at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library\\std\\src\\panicking.rs:697\n",
" 1: core::panicking::panic_fmt\n",
" at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library\\core\\src\\panicking.rs:75\n",
" 2: ctx::run_user_code_2::{{closure}}\n",
" 3: _rust_try.llvm.7135721178753807917\n",
" 4: std::panic::catch_unwind\n",
" 5: run_user_code_2\n",
" 6: <unknown>\n",
" 7: <unknown>\n",
" 8: <unknown>\n",
" 9: <unknown>\n",
" 10: <unknown>\n",
" 11: <unknown>\n",
" 12: <unknown>\n",
" 13: <unknown>\n",
" 14: BaseThreadInitThunk\n",
" 15: RtlUserThreadStart\n",
"note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
]
}
],
"source": [
"panic!(\"Critical error!\");"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Unwinding\n",
"\n",
"* Panic typically proceeds as follows:\n",
" * An error message is printed to the terminal. If you set the `RUST_BACKTRACE` environment variable, as the messages suggests, Rust will also dump the stack at this point.\n",
" * The stack is unwound. This is a lot like C++ exception handling. Any temporary values, local variables, or arguments that the current function was using are dropped, in the reverse of the order they were created. Dropping a value simply means cleaning up after it: any `String`s or `Vec`s the program was using are freed, any open `File`s are closed, and so on. User-defined `drop` methods are called too.\n",
" * Finally, the thread exits. If the panicking thread was the main thread, then the whole process exits (with a nonzero exit code)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Aborting\n",
"\n",
"* Stack unwinding is the default panic behavior, but there are two circumstances in which Rust does not try to unwind the stack.\n",
" * If a `.drop()` method triggers a second panic while Rust is still trying to clean up after the first, this is considered fatal. Rust stops unwinding and aborts the whole process.\n",
" * Rust’s panic behavior is customizable. If you compile with `-C panic=abort`, the first panic in your program immediately aborts the process. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Result"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* A `Result` represents an operation that can either succeed (returning a result) or fail (returning an error).\n",
"* It is defined as:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"mod explain {\n",
" pub enum Result<T, E> {\n",
" Ok(T),\n",
" Err(E),\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"#[derive(Debug)]\n",
"struct ReadFileError {\n",
" message: String\n",
"}\n",
"\n",
"impl std::fmt::Display for ReadFileError {\n",
" fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n",
" write!(f, \"ReadFileError: {}\", self.message)\n",
" }\n",
"}\n",
"\n",
"impl std::error::Error for ReadFileError {}"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"ename": "Error",
"evalue": "failed to resolve: use of unresolved module or unlinked crate `io`",
"output_type": "error",
"traceback": [
"\u001b[31m[E0433] Error:\u001b[0m failed to resolve: use of unresolved module or unlinked crate `io`",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_5:1:1 \u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mR\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m<\u001b[0m\u001b[38;5;249mS\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m use of unresolved module or unlinked crate `io`",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m help: a builtin type with a similar name exists: `i8`",
" \u001b[38;5;240m │\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;115mNote\u001b[0m: help: consider importing this module: `use std::io;",
" \u001b[38;5;240m │\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m `",
"\u001b[38;5;246m───╯\u001b[0m"
]
}
],
"source": [
"fn read_file(path: &str) -> Result<String, ReadFileError> { \n",
" let file: io::Result<String> = std::fs::read_to_string(path);\n",
" \n",
" match file {\n",
" Ok(content) => Result::Ok(content),\n",
" Err(err) => Result::Err(ReadFileError{message: err.to_string()}),\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"ename": "Error",
"evalue": "cannot find function `read_file` in this scope",
"output_type": "error",
"traceback": [
"\u001b[31m[E0425] Error:\u001b[0m cannot find function `read_file` in this scope",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_6:1:1 \u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54mf\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
"\u001b[38;5;246m───╯\u001b[0m"
]
}
],
"source": [
"let file_content = read_file(\"file.txt\");\n",
"\n",
"match file_content {\n",
" Ok(content) => println!(\"{}\", content),\n",
" Err(err) => println!(\"{}\", err),\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Result methods"
]
},
{
"cell_type": "markdown",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"source": [
"* `result.unwrap()` also returns the success value, if result is a success result. However, if result is an error result, this method panics.\n",
"* `result.expect(message)` is the same as `.unwrap()`, but lets you provide a message that it prints in case of panic.\n",
"* `result.is_ok()` and `result.is_err()` return a `bool` telling if result is a success result or an error result.\n",
"* `result.ok()` returns the success value, if any, as an `Option<T>`. If result is a success result, this returns `Some(success_value)`; otherwise, it returns `None`, discarding the error value.\n",
"* `result.err()` returns the error value, if any, as an `Option<E>`.\n",
"* `result.unwrap_or(fallback)` returns the success value, if result is a success result. Otherwise, it returns `fallback`, discarding the error value."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"ename": "Error",
"evalue": "cannot find function `read_file` in this scope",
"output_type": "error",
"traceback": [
"\u001b[31m[E0425] Error:\u001b[0m cannot find function `read_file` in this scope",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_7:1:1 \u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54mf\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mD\u001b[0m\u001b[38;5;249mE\u001b[0m\u001b[38;5;249mF\u001b[0m\u001b[38;5;249mA\u001b[0m\u001b[38;5;249mU\u001b[0m\u001b[38;5;249mL\u001b[0m\u001b[38;5;249mT\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mF\u001b[0m\u001b[38;5;249mI\u001b[0m\u001b[38;5;249mL\u001b[0m\u001b[38;5;249mE\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mC\u001b[0m\u001b[38;5;249mO\u001b[0m\u001b[38;5;249mN\u001b[0m\u001b[38;5;249mT\u001b[0m\u001b[38;5;249mE\u001b[0m\u001b[38;5;249mN\u001b[0m\u001b[38;5;249mT\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
"\u001b[38;5;246m───╯\u001b[0m"
]
}
],
"source": [
"static DEFAULT_FILE_CONTENT: &str = \"Default content\";\n",
"\n",
"let file_content = read_file(\"unknown_file.txt\").unwrap_or(DEFAULT_FILE_CONTENT.to_string());\n",
"\n",
"file_content"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* `result.unwrap_or_else(fallback_fn)` is the same, but instead of passing a fallback value directly, you pass a function or closure. This is for cases where it would be wasteful to compute a fallback value if you’re not going to use it. The `fallback_fn` is called only if we have an error result.\n",
"* `result.as_ref()` converts a `Result<T, E>` to a `Result<&T, &E>`, borrowing a reference to the success or error value in the existing result.\n",
"* `result.as_mut()` is the same, but borrows a mutable reference. The return type is `Result<&mut T, &mut E>`.\n",
"\n",
"#### Mapping\n",
"\n",
"* Mapping means transforming the success or error value inside a `Result`, while leaving the other value untouched. It simplifies code that would otherwise require matching on the `Result` and handling both cases.\n",
" * `result.map(success_fn)` transforms a `Result<T, E>` to a `Result<U, E>` by applying the function `success_fn` to the success value, if any. The error value is left untouched.\n",
" * `result.map_err(error_fn)` is the same, but applies `error_fn` to the error value, if any, transforming a `Result<T, E>` to a `Result<T, F>`."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"This is a file with some text.\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fn read_file(path: &str) -> Result<String, ReadFileError> { \n",
" std::fs::read_to_string(path).map_err(|err| ReadFileError{message: err.to_string()})\n",
"}\n",
"\n",
"let file_content = read_file(\"file.txt\");\n",
"\n",
"match file_content {\n",
" Ok(content) => println!(\"{}\", content),\n",
" Err(err) => println!(\"{}\", err),\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Result Type Aliases\n",
"\n",
"* Modules often define a `Result` type alias to avoid having to repeat an error type that’s used consistently by almost every function in the module"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Some(\"This is a file with some text.\")"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mod custom {\n",
" pub type Result<T> = std::result::Result<T, ReadFileError>;\n",
"\n",
" #[derive(Debug)]\n",
" pub struct ReadFileError {\n",
" message: String\n",
" }\n",
"\n",
" pub fn read_file(path: &str) -> Result<String> { \n",
" let file = std::fs::read_to_string(path);\n",
" \n",
" match file {\n",
" Ok(content) => Result::Ok(content),\n",
" Err(err) => Result::Err(ReadFileError{message: err.to_string()}),\n",
" }\n",
" }\n",
"}\n",
"\n",
"custom::read_file(\"file.txt\").ok()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Trait std::error::Error - Printing Errors"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* All of standard library errors have a common interface, the `std::error::Error` trait, which means they share the following features:\n",
" * They’re all printable using `println!()`. Printing an error with the `{}` format specifier typically displays only a brief error message. Alternatively, you can print with the `{:?}` format specifier, to get a `Debug` view of the error\n",
" * `err.description()` returns an error message as a `&str`.\n",
" * `err.source()` returns an `Option<&(dyn Error + 'static)>`: the underlying error, if any, that triggered `err`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Propagating Error"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* In most places where we try something that could fail, we don’t want to catch and handle the error immediately\n",
"* Instead, if an error occurs, we usually want to let our caller deal with it. We want errors to propagate up the call stack.\n",
"* Rust has a `?` operator that does this. You can add a `?` to any expression that produces a `Result`, such as the result of a function call:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"use std::io;\n",
"\n",
"fn read_file_content(name: &str) -> io::Result<String> {\n",
" use std::fs::File;\n",
" use std::io::prelude::*;\n",
" \n",
" let mut file = File::open(name)?; \n",
" let mut contents = String::new();\n",
" file.read_to_string(&mut contents)?;\n",
" Ok(contents)\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Error: Os { code: 2, kind: NotFound, message: \"Nie można odnaleźć określonego pliku.\" }\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"let file_content = read_file_content(\"unknown_file.txt\");\n",
"\n",
"match file_content {\n",
" Ok(content) => println!(\"{}\", content),\n",
" Err(err) => println!(\"Error: {:?}\", err),\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* The behavior of `?` depends on whether this function returns a success result or an error result:\n",
" * on success, it unwraps the Result to get the success value inside.\n",
" * on error, it immediately returns from the enclosing function, passing the error result up the call chain. To ensure that this works, `?` can only be used in functions that have a `Result` return type."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Working with Multiple Error Types"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"ename": "Error",
"evalue": "`?` couldn't convert the error to `std::io::Error`",
"output_type": "error",
"traceback": [
"\u001b[31m[E0277] Error:\u001b[0m `?` couldn't convert the error to `std::io::Error`",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_14:1:1 \u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mB\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mR\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mR\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100ml\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100m<\u001b[0m\u001b[38;5;100mV\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100mc\u001b[0m\u001b[38;5;100m<\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100m3\u001b[0m\u001b[38;5;100m2\u001b[0m\u001b[38;5;100m>\u001b[0m\u001b[38;5;100m,\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100mo\u001b[0m\u001b[38;5;100m:\u001b[0m\u001b[38;5;100m:\u001b[0m\u001b[38;5;100mE\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100mo\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m expected `std::io::Error` because of this",
" \u001b[38;5;240m │\u001b[0m ",
" \u001b[38;5;246m7 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54m:\u001b[0m\u001b[38;5;54m:\u001b[0m\u001b[38;5;54m<\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54m3\u001b[0m\u001b[38;5;54m2\u001b[0m\u001b[38;5;54m>\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;68m?\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;68m┬\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m this can't be annotated with `?` because it has type `Result<_, ParseIntError>`",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m the trait `From<ParseIntError>` is not implemented for `std::io::Error`",
"\u001b[38;5;246m───╯\u001b[0m"
]
}
],
"source": [
"use std::io::{self, BufRead};\n",
"\n",
"fn read_numbers(file: &mut dyn BufRead) -> Result<Vec<i32>, io::Error> {\n",
" let mut numbers = Vec::new();\n",
" for line_result in file.lines() {\n",
" let line = line_result?;\n",
" let number = line.parse::<i32>()?;\n",
" numbers.push(number);\n",
" }\n",
" Ok(numbers)\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Case 1 - Trait `From`"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"use std::io::BufRead;\n",
"\n",
"#[derive(Debug)]\n",
"enum ReadNumbersError {\n",
" Io(io::Error),\n",
" ParseInt(std::num::ParseIntError),\n",
"}\n",
"\n",
"impl From<io::Error> for ReadNumbersError {\n",
" fn from(err: io::Error) -> Self {\n",
" ReadNumbersError::Io(err)\n",
" }\n",
"}\n",
"\n",
"impl From<std::num::ParseIntError> for ReadNumbersError {\n",
" fn from(err: std::num::ParseIntError) -> Self {\n",
" ReadNumbersError::ParseInt(err)\n",
" }\n",
"}\n",
"\n",
"fn read_numbers(file: &mut dyn BufRead) -> Result<Vec<i32>, ReadNumbersError> {\n",
" let mut numbers = Vec::new();\n",
" for line_result in file.lines() {\n",
" let line = line_result?;\n",
" let number = line.parse::<i32>()?;\n",
" numbers.push(number);\n",
" }\n",
" Ok(numbers)\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[1, 2, 3, 42, 665, 6, 7, 8]\n"
]
}
],
"source": [
"use std::io::{self, BufReader};\n",
"\n",
"fn main() {\n",
" let file = std::fs::File::open(\"numbers.txt\").unwrap();\n",
"\n",
" let mut buffer_reader = BufReader::new(file);\n",
"\n",
" let numbers_result = read_numbers(&mut buffer_reader);\n",
"\n",
" match numbers_result {\n",
" Ok(numbers) => println!(\"{:?}\", numbers),\n",
" Err(e) => println!(\"Error reading numbers: {:?}\", e),\n",
" }\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Case 2 - `Box<dyn std::error::Error>`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Code does not compile - there is no conversion from `ParseIntError` to `io::Error`\n",
"* The easiest way to handle multiple error types is to define these type aliases:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [],
"source": [
"type GenericError = Box<dyn std::error::Error>;\n",
"type GenericResult<T> = Result<T, GenericError>;"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* and change return type from function to `GenericResult<Vec<i32>>`"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"use std::io::{self, BufRead};\n",
"\n",
"fn parse_numbers(file: &mut dyn BufRead) -> GenericResult<Vec<i32>> {\n",
" let mut numbers = Vec::new();\n",
" for line_result in file.lines() {\n",
" let line = line_result?;\n",
" let number = line.parse::<i32>()?;\n",
" numbers.push(number);\n",
" }\n",
" Ok(numbers)\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Error reading numbers: ParseIntError { kind: InvalidDigit }\n"
]
}
],
"source": [
"use std::io::{self, BufReader};\n",
"\n",
"fn main() {\n",
" let file = std::fs::File::open(\"invalid_numbers.txt\").unwrap();\n",
" let mut buffer_reader = BufReader::new(file);\n",
" \n",
" let numbers_result = parse_numbers(&mut buffer_reader);\n",
"\n",
" match numbers_result {\n",
" Ok(numbers) => println!(\"{:?}\", numbers),\n",
" Err(e) => println!(\"Error reading numbers: {:?}\", e),\n",
" }\n",
"}\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Declaring a Custom Error Types"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"#[derive(Debug, Clone)]\n",
"pub struct JsonError {\n",
" pub message: String,\n",
" pub line: usize,\n",
" pub column: usize,\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"use std;\n",
"use std::fmt;\n",
"\n",
"// Errors should be printable.\n",
"impl fmt::Display for JsonError {\n",
" fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {\n",
" write!(f, \"{} ({}:{})\", self.message, self.line, self.column)\n",
" }\n",
"}\n",
"\n",
"// Errors should implement the std::error::Error trait.\n",
"impl std::error::Error for JsonError {\n",
" fn description(&self) -> &str {\n",
" &self.message\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
":dep serde_json = \"1.0.64\"\n",
":dep serde = { version=\"1.0.127\", features=[\"derive\"] }\n",
"\n",
"use serde::{Deserialize, Serialize};\n",
"\n",
"#[derive(Serialize, Deserialize, Debug)]\n",
"struct Person {\n",
" name: String,\n",
" age: i32,\n",
"}\n",
"\n",
"fn load_from_json() -> Result<Person, JsonError> {\n",
" let json = r#\"\n",
" {\n",
" \"name\": \"John\",\n",
" \"age\": 30\n",
" }\n",
" \"#;\n",
"\n",
" let person: Person = match serde_json::from_str(json) {\n",
" Ok(data) => data,\n",
" Err(err) => {\n",
" let line = err.line();\n",
" let column = err.column();\n",
" let message = err.to_string();\n",
" return Err(JsonError { message, line, column });\n",
" }\n",
" };\n",
"\n",
" Ok(person)\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"None"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"let person = load_from_json().err();\n",
"person"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Crates for Error Handling"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## thiserror\n",
"\n",
"* The `thiserror` crate provides a convenient way to define custom error types in Rust by using procedural macros. It simplifies the process of implementing the `std::error::Error` trait and provides useful features for error handling.\n",
"* With `thiserror`, you can define your error types as enums or structs and annotate them with the `#[derive(Error)]` attribute. This automatically generates the necessary implementations for the `Error` trait, including methods like `source()` and `description()`.\n",
"* The crate also allows you to specify error messages using the `#[error(\"...\")]` attribute, which supports formatting and interpolation of fields within the error type.\n",
"* Additionally, `thiserror` supports automatic conversion from other error types using the `#[from]` attribute, making it easy to wrap and propagate errors from different sources."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Error parsing numbers: Failed to parse number: 66d5\n"
]
}
],
"source": [
":dep thiserror = \"2.0\"\n",
"\n",
"mod thiserror_example {\n",
" use thiserror::Error;\n",
"\n",
" #[derive(Error, Debug)]\n",
" pub enum ParseNumberError {\n",
" #[error(\"File not found\")]\n",
" NotFound(#[from] std::io::Error), // automatic conversion from std::io::Error\n",
" #[error(\"Failed to parse number: {0}\")]\n",
" ParseError(String),\n",
" }\n",
"\n",
" pub fn parse_numbers(path: &str) -> Result<Vec<i32>, ParseNumberError> {\n",
" use std::fs::File;\n",
" use std::io::{self, BufRead, BufReader};\n",
"\n",
" let file = File::open(path)?;\n",
" let reader = BufReader::new(file);\n",
" let mut numbers = Vec::new();\n",
"\n",
" for line_result in reader.lines() {\n",
" let line = line_result?;\n",
" match line.parse::<i32>() {\n",
" Ok(num) => numbers.push(num),\n",
" Err(_) => return Err(ParseNumberError::ParseError(line)),\n",
" }\n",
" }\n",
"\n",
" Ok(numbers)\n",
" }\n",
"}\n",
"\n",
"fn main() {\n",
" match thiserror_example::parse_numbers(\"invalid_numbers.txt\") {\n",
" Ok(numbers) => println!(\"Parsed numbers: {:?}\", numbers),\n",
" Err(e) => println!(\"Error parsing numbers: {}\", e),\n",
" }\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## anyhow\n",
"\n",
"* The `anyhow` crate provides a simple and flexible way to handle errors in Rust applications. It allows you to create and propagate errors without having to define custom error types for every possible error scenario.\n",
"* With `anyhow`, you can use the `anyhow::Error` type to represent errors, which can encapsulate any error type that implements the `std::error::Error` trait. This makes it easy to work with different error types without having to define a separate error enum or struct for each case.\n",
"* The crate also provides convenient macros like `anyhow!` for creating errors with formatted messages, and the `Context` trait for adding additional context to errors as they propagate through your code.\n",
"* Library convinent when prototyping or building applications where you want to focus on error handling without the overhead of defining numerous custom error types."
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[1, 2, 3, 42, 665, 6, 7, 8]\n"
]
}
],
"source": [
":dep anyhow = \"1.0\"\n",
"\n",
"mod anyhow_example {\n",
" use anyhow::Context;\n",
" use std::io::{BufRead, BufReader};\n",
"\n",
" pub fn parse_numbers(file: &mut dyn BufRead) -> anyhow::Result<Vec<i32>> {\n",
" let mut numbers = Vec::new();\n",
" for (index, line_result) in file.lines().enumerate() {\n",
" let line = line_result.context(format!(\"Failed to read line {}\", index + 1))?;\n",
" let number = line.parse::<i32>()\n",
" .context(format!(\"Failed to parse '{}' as i32 on line {}\", line, index + 1))?;\n",
" numbers.push(number);\n",
" }\n",
" Ok(numbers)\n",
" }\n",
"\n",
" pub fn read_numbers(path: &str) -> anyhow::Result<Vec<i32>> {\n",
" let file = std::fs::File::open(path)\n",
" .with_context(|| format!(\"Failed to open file '{}'\", path))?;\n",
" \n",
" let mut buffer_reader = BufReader::new(file);\n",
" let numbers = parse_numbers(&mut buffer_reader)\n",
" .with_context(|| format!(\"Failed to read numbers from file '{}'\", path))?;\n",
" \n",
" Ok(numbers)\n",
" }\n",
"}\n",
"\n",
"fn main() {\n",
" let result = anyhow_example::read_numbers(\"numbers.txt\"); \n",
" match result {\n",
" Ok(numbers) => println!(\"{:?}\", numbers),\n",
" Err(err) => println!(\"Error: {:?}\", err),\n",
" }\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [],
"source": [
"use anyhow::{anyhow, Result};\n",
"\n",
"fn get_user_age(name: &str) -> Result<u32> {\n",
" match name {\n",
" \"Alice\" => Ok(30),\n",
" \"Bob\" => Ok(25),\n",
" _ => Err(anyhow!(\"No age data available for user '{}'\", name)),\n",
" }\n",
"}\n",
"\n",
"fn main() -> Result<()> {\n",
" let age = get_user_age(\"Charlie\")?;\n",
" println!(\"User age: {}\", age);\n",
" Ok(())\n",
"}\n",
"\n",
"main();"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,536 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Smart Pointers"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## `Box<T>`\n",
"\n",
"* A smart pointer that allocates data on the heap.\n",
"* Provides ownership for the heap data.\n",
"* Dereferences to the data it points to.\n",
"* Useful for recursive data types and large data on the heap."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Storing Data on Heap"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5\n"
]
}
],
"source": [
"fn main() {\n",
" let on_heap = Box::new(5);\n",
" println!(\"{}\", on_heap);\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Recursive Data Structures"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"enum List {\n",
" Cons(i32, Box<List>), // Box<List> allows for recursive data structures\n",
" Nil,\n",
"}\n",
"\n",
"use List::{Cons, Nil};\n",
"\n",
"fn main() {\n",
" let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Dereferencing"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn main() {\n",
" let x = 5;\n",
" let y = &x;\n",
" let z = Box::new(x);\n",
"\n",
" assert!(5 == x);\n",
" assert!(5 == *y);\n",
" assert!(5 == *z);\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### How it works"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Creating MyBox with some data!\n",
"Dropping MyBox with some data!\n"
]
}
],
"source": [
"struct MyBox<T>(T);\n",
"\n",
"impl<T> MyBox<T> {\n",
" fn new(x: T) -> MyBox<T> {\n",
" println!(\"Creating MyBox with some data!\");\n",
" MyBox(x)\n",
" }\n",
"}\n",
" \n",
"use std::ops::Deref;\n",
"\n",
"impl<T> Deref for MyBox<T> {\n",
" type Target = T;\n",
"\n",
" fn deref(&self) -> &Self::Target {\n",
" &self.0\n",
" }\n",
"}\n",
"\n",
"impl<T> Drop for MyBox<T> {\n",
" fn drop(&mut self) {\n",
" println!(\"Dropping MyBox with some data!\");\n",
" }\n",
"}\n",
"\n",
"fn main() {\n",
" let x = 5;\n",
" let y = MyBox::new(x);\n",
"\n",
" assert!(5 == x);\n",
" assert!(5 == *y);\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Deref coercion\n",
"\n",
"* Deref coercion converts a reference to a type that implements the `Deref` trait into a reference to another type. For example, deref coercion can convert `&String` to `&str` because `String` implements the `Deref` trait such that it returns `&str`"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hello, John!\n",
"Hello, Jane!\n",
"Creating MyBox with some data!\n",
"Hello, Rust!\n",
"Dropping MyBox with some data!\n"
]
}
],
"source": [
"fn hello(name: &str) {\n",
" println!(\"Hello, {}!\", name);\n",
"}\n",
"\n",
"fn main() {\n",
" hello(\"John\");\n",
" \n",
" let name = String::from(\"Jane\");\n",
" hello(&name);\n",
"\n",
" let m = MyBox::new(String::from(\"Rust\"));\n",
" hello(&m);\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## `Rc` (Reference Counted Smart Pointer)\n",
"\n",
"* `Rc<T>` enables multiple ownership of the same data; `Rc<T>` keeps track of the number of references to a value which determines whether or not a value is still in use.\n",
"* `Rc<T>` is only for use in single-threaded scenarios. For multi-threaded code, `Arc<T>` should be used.\n",
"* `Rc<T>` points to immutable data. If you need mutability, put a `RefCell<T>` inside the `Rc<T>`."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Using Value(\"foo\"). RC: 3\n",
"Using Value(\"bar\"). RC: 2\n",
"v_inner - Value(\"bar\") - it was only one strong reference\n",
"Dropping Value(\"bar\")\n",
"Value(\"foo\")\n",
"---------------------------------\n",
"Dropping Value(\"foo\")\n",
"---------------------------------\n"
]
}
],
"source": [
"use std::collections::HashMap;\n",
"use std::rc::Rc;\n",
"\n",
"#[derive(Debug)]\n",
"struct Value(String);\n",
"\n",
"impl Value {\n",
" fn value(&self) -> &String {\n",
" &self.0\n",
" }\n",
"}\n",
"\n",
"impl Drop for Value {\n",
" fn drop(&mut self) {\n",
" println!(\"Dropping {:?}\", self);\n",
" }\n",
"}\n",
"\n",
"fn use_value(data: Rc<Value>) {\n",
" println!(\"Using {:?}. RC: {}\", data, Rc::strong_count(&data));\n",
"}\n",
"\n",
"fn main() {\n",
" let mut map = HashMap::<&str, Rc<Value>>::new();\n",
" {\n",
" let v_foo = Rc::new(Value(\"foo\".to_string()));\n",
" map.insert(\"foo\", v_foo.clone());\n",
" use_value(v_foo.clone());\n",
" {\n",
" let v_bar = Rc::new(Value(\"bar\".to_string()));\n",
" use_value(v_bar.clone());\n",
" \n",
" let v_inner = Rc::into_inner(v_bar);\n",
"\n",
" match v_inner {\n",
" Some(value) => {\n",
" println!(\"v_inner - {:?} - it was only one strong reference\", value);\n",
" }\n",
" None => {\n",
" println!(\"v_inner is None - more than one reference to it\");\n",
" }\n",
" }\n",
" } \n",
" }\n",
"\n",
" println!(\"{:?}\", map.get(\"foo\").unwrap());\n",
"\n",
" println!(\"---------------------------------\");\n",
"\n",
" map.clear();\n",
"\n",
" println!(\"---------------------------------\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## `Weak` - Breaking Reference Cycles\n",
"\n",
"* `Weak<T>` is a version of `Rc<T>` that holds a non-owning reference. The object that `Weak<T>` points to is only valid if there is at least one `Rc<T>` pointing to it.\n",
"* `Weak<T>` is useful in breaking reference cycles. A reference cycle is a situation where two objects reference each other, preventing either from being cleaned up."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Memory Leak - Reference Cycles"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"John: John (30) is not married\n",
"Jane: Jane (25) is not married\n",
"Dropping Jane (25)\n",
"Dropping John (30)\n"
]
}
],
"source": [
"use std::cell::RefCell;\n",
"use std::fmt::{self, Display, Formatter, Debug};\n",
"\n",
"struct Human {\n",
" name: String,\n",
" age: u32,\n",
"\n",
" partner: RefCell<Option<Rc<Human>>>,\n",
"}\n",
"\n",
"impl Debug for Human {\n",
" fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n",
" write!(f, \"{} ({})\", self.name, self.age)\n",
" }\n",
"}\n",
"\n",
"impl Display for Human {\n",
" fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n",
" write!(f, \"{} ({})\", self.name, self.age);\n",
"\n",
" if let Some(partner) = &*self.partner.borrow() {\n",
" write!(f, \" is married to {}\", partner.name)\n",
" } else {\n",
" write!(f, \" is not married\")\n",
" }\n",
" }\n",
"}\n",
"\n",
"impl Drop for Human {\n",
" fn drop(&mut self) {\n",
" println!(\"Dropping {:?}\", self);\n",
" }\n",
"}\n",
"\n",
"impl Human {\n",
" fn new(name: &str, age: u32) -> Rc<Human> {\n",
" Rc::new(Human {\n",
" name: name.to_string(),\n",
" age,\n",
" partner: RefCell::new(None),\n",
" })\n",
" }\n",
"}\n",
"\n",
"fn marry(h1: Rc<Human>, h2: Rc<Human>) {\n",
" *h1.partner.borrow_mut() = Some(h2.clone());\n",
" *h2.partner.borrow_mut() = Some(h1.clone());\n",
"}\n",
"\n",
"fn main() {\n",
" let mut john = Human::new(\"John\", 30);\n",
" let mut jane = Human::new(\"Jane\", 25);\n",
"\n",
" //marry(john.clone(), jane.clone()); // this creates a reference cycle -> memory leak\n",
"\n",
" println!(\"John: {}\", john);\n",
" println!(\"Jane: {}\", jane);\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Breaking Reference Cycles with `Weak`"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"John: John (30) is married to Jane - Rc::strong_count(1)\n",
"Jane: Jane (25) is married to John - Rc::strong_count(1)\n",
"Dropping Jane (25)\n",
"John: John (30) is widow/widower\n",
"Dropping John (30)\n"
]
}
],
"source": [
"use std::rc::{Rc, Weak}\n",
"use std::cell::RefCell;\n",
"use std::fmt::{self, Display, Formatter};\n",
"\n",
"struct Human {\n",
" name: String,\n",
" age: u32,\n",
"\n",
" partner: RefCell<Option<Weak<Human>>>,\n",
"}\n",
"\n",
"impl Debug for Human {\n",
" fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n",
" write!(f, \"{} ({})\", self.name, self.age)\n",
" }\n",
"}\n",
"\n",
"impl Display for Human {\n",
" fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n",
" write!(f, \"{} ({})\", self.name, self.age);\n",
"\n",
" if let Some(partner) = &*self.partner.borrow() {\n",
" if let Some(partner) = partner.upgrade() {\n",
" write!(f, \" is married to {}\", partner.name)\n",
" } else {\n",
" write!(f, \" is widow/widower\")\n",
" }\n",
" } else {\n",
" write!(f, \" is not married\")\n",
" }\n",
" }\n",
"}\n",
"\n",
"impl Drop for Human {\n",
" fn drop(&mut self) {\n",
" println!(\"Dropping {:?}\", self);\n",
" }\n",
"}\n",
"\n",
"impl Human {\n",
" fn new(name: &str, age: u32) -> Rc<Human> {\n",
" Rc::new(Human {\n",
" name: name.to_string(),\n",
" age,\n",
" partner: RefCell::new(None),\n",
" })\n",
" }\n",
"}\n",
"\n",
"fn marry(h1: Rc<Human>, h2: Rc<Human>) {\n",
" *h1.partner.borrow_mut() = Some(Rc::downgrade(&h2));\n",
" *h2.partner.borrow_mut() = Some(Rc::downgrade(&h1));\n",
"}\n",
"\n",
"fn main() {\n",
" let mut john: Rc<Human> = Human::new(\"John\", 30);\n",
" let mut jane: Rc<Human> = Human::new(\"Jane\", 25);\n",
"\n",
" marry(john.clone(), jane.clone());\n",
"\n",
" println!(\"John: {} - Rc::strong_count({})\", john, Rc::strong_count(&john));\n",
" println!(\"Jane: {} - Rc::strong_count({})\", jane, Rc::strong_count(&jane));\n",
"\n",
" std::mem::drop(jane);\n",
" println!(\"John: {}\", john);\n",
"}\n",
"\n",
"main();"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "Rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View file

@ -0,0 +1,453 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Interior Mutability"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"use std::collections::HashMap;\n",
"\n",
"struct DnsService {\n",
" lookup_table: HashMap<String, String>\n",
"}\n",
"\n",
"impl DnsService {\n",
" fn lookup(&self, hostname: &str) -> Option<&str> {\n",
" self.lookup_table.get(hostname).map(|s| s.as_str())\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Some(\"1.22.33.1\")\n"
]
}
],
"source": [
"let dns_service = DnsService {\n",
" lookup_table: [(\"www.example.com\".to_string(), \"143.33.44.4\".to_string()),\n",
" (\"www.rust-lang.org\".to_string(), \"1.22.33.1\".to_string()),\n",
" (\"www.mozilla.org\".to_string(), \"2.43.44.3\".to_string())\n",
" ].iter().cloned().collect()\n",
"};\n",
"\n",
"println!(\"{:?}\", dns_service.lookup(\"www.rust-lang.org\"));"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"ename": "Error",
"evalue": "cannot assign to `self.counter`, which is behind a `&` reference",
"output_type": "error",
"traceback": [
"\u001b[31m[E0594] Error:\u001b[0m cannot assign to `self.counter`, which is behind a `&` reference",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_4:1:1 \u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m 9 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mO\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m<\u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m help: consider changing this to be a mutable reference: `mut `",
" \u001b[38;5;246m10 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54mf\u001b[0m\u001b[38;5;54m.\u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m+\u001b[0m\u001b[38;5;54m=\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m1\u001b[0m\u001b[38;5;249m;\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mE\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m`\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m`\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249md\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `self` is a `&` reference, so the data it refers to cannot be written",
"\u001b[38;5;246m────╯\u001b[0m"
]
}
],
"source": [
"use std::collections::HashMap;\n",
"\n",
"struct DnsService {\n",
" lookup_table: HashMap<String, String>,\n",
" counter: i32\n",
"}\n",
"\n",
"impl DnsService {\n",
" fn lookup(&self, hostname: &str) -> Option<&str> {\n",
" self.counter += 1; // Error: cannot assign to `self.counter` because it is borrowed\n",
" self.lookup_table.get(hostname).map(|s| s.as_str())\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## `Cell` - for `Copy` types"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"use std::collections::HashMap;\n",
"use std::cell::Cell;\n",
"\n",
"struct DnsService {\n",
" lookup_table: HashMap<String, String>,\n",
" counter: Cell<i32>\n",
"}\n",
"\n",
"impl DnsService {\n",
" fn lookup(&self, hostname: &str) -> Option<&str> {\n",
" let value = self.counter.get();\n",
" self.counter.set(value + 1);\n",
" self.lookup_table.get(hostname).map(|s| s.as_str())\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"The type of the variable dns_service was redefined, so was lost.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Some(\"1.22.33.1\")\n",
"Some(\"143.33.44.4\")\n",
"None\n",
"Dns used 3 times\n"
]
}
],
"source": [
"let dns_service = DnsService {\n",
" lookup_table: [(\"www.example.com\".to_string(), \"143.33.44.4\".to_string()),\n",
" (\"www.rust-lang.org\".to_string(), \"1.22.33.1\".to_string()),\n",
" (\"www.mozilla.org\".to_string(), \"2.43.44.3\".to_string())\n",
" ].iter().cloned().collect(), \n",
" counter: Cell::new(0)\n",
"};\n",
"\n",
"println!(\"{:?}\", dns_service.lookup(\"www.rust-lang.org\"));\n",
"println!(\"{:?}\", dns_service.lookup(\"www.example.com\"));\n",
"println!(\"{:?}\", dns_service.lookup(\"www.infotraining.pl\"));\n",
"\n",
"println!(\"Dns used {} times\", dns_service.counter.get());"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## RefCell - for non-`Copy` types"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"use std::collections::HashMap;\n",
"use std::cell::RefCell;\n",
"\n",
"type LookupLog = Vec<String>;\n",
"\n",
"struct DnsService {\n",
" lookup_table: HashMap<String, String>,\n",
" lookup_log: RefCell<LookupLog>,\n",
"}\n",
"\n",
"impl DnsService {\n",
" fn lookup(&self, hostname: &str) -> Option<&str> {\n",
" self.lookup_log.borrow_mut().push(hostname.to_string());\n",
" self.lookup_table.get(hostname).map(|s| s.as_str())\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Some(\"1.22.33.1\")\n",
"Some(\"143.33.44.4\")\n",
"None\n",
"Dns looked up for [\"www.rust-lang.org\", \"www.example.com\", \"www.infotraining.pl\"]\n"
]
}
],
"source": [
"let dns_service = DnsService {\n",
" lookup_table: [(\"www.example.com\".to_string(), \"143.33.44.4\".to_string()),\n",
" (\"www.rust-lang.org\".to_string(), \"1.22.33.1\".to_string()),\n",
" (\"www.mozilla.org\".to_string(), \"2.43.44.3\".to_string())\n",
" ].iter().cloned().collect(), \n",
" lookup_log: RefCell::new(Vec::new())\n",
"};\n",
"\n",
"println!(\"{:?}\", dns_service.lookup(\"www.rust-lang.org\"));\n",
"println!(\"{:?}\", dns_service.lookup(\"www.example.com\"));\n",
"println!(\"{:?}\", dns_service.lookup(\"www.infotraining.pl\"));\n",
"\n",
"println!(\"Dns looked up for {:?}\", dns_service.lookup_log.borrow());"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## RwLock - for thread-safe shared access"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"use std::collections::HashMap;\n",
"use std::cell::RefCell;\n",
"\n",
"type LookupLog = Vec<String>;\n",
"\n",
"struct DnsService {\n",
" lookup_table: HashMap<String, String>,\n",
" lookup_log: RefCell<LookupLog>,\n",
"}\n",
"\n",
"impl DnsService {\n",
" fn from_slice(data: &[(&str, &str)]) -> DnsService {\n",
" DnsService {\n",
" lookup_table: data.iter().cloned().map(|(k, v)| (k.to_string(), v.to_string())).collect(),\n",
" lookup_log: RefCell::new(Vec::new())\n",
" }\n",
" }\n",
"\n",
" fn lookup(&self, hostname: &str) -> Option<&str> {\n",
" self.lookup_log.borrow_mut().push(hostname.to_string());\n",
" self.lookup_table.get(hostname).map(|s| s.as_str())\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"ename": "Error",
"evalue": "`RefCell<Vec<String>>` cannot be shared between threads safely",
"output_type": "error",
"traceback": [
"\u001b[31m[E0277] Error:\u001b[0m `RefCell<Vec<String>>` cannot be shared between threads safely",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_11:1:1 \u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;54m╭\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m▶\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100md\u001b[0m\u001b[38;5;100m:\u001b[0m\u001b[38;5;100m:\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100mh\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100ma\u001b[0m\u001b[38;5;100md\u001b[0m\u001b[38;5;100m:\u001b[0m\u001b[38;5;100m:\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;100mp\u001b[0m\u001b[38;5;100ma\u001b[0m\u001b[38;5;100mw\u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;68m|\u001b[0m\u001b[38;5;68m|\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m{\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m│\u001b[0m \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m│\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m required by a bound introduced by this call",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m│\u001b[0m \u001b[38;5;68m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m│\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m note: required because it's used within this closure",
" \u001b[38;5;240m ┆\u001b[0m \u001b[38;5;54m┆\u001b[0m ",
" \u001b[38;5;246m8 │\u001b[0m \u001b[38;5;54m├\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m▶\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m}\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `RefCell<Vec<String>>` cannot be shared between threads safely",
" \u001b[38;5;240m │\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;115mNote\u001b[0m: note: required because it appears within the type `DnsService`",
"\u001b[38;5;246m───╯\u001b[0m"
]
}
],
"source": [
"fn main() {\n",
" let dns_service = DnsService::from_slice(&[(\"www.example.com\", \"122.33.22.33\"), (\"www.rust-lang.org\", \"1.2.3.4\"), (\"www.mozilla.org\", \"9.4.3.4\")]);\n",
"\n",
" println!(\"{:?}\", dns_service.lookup(\"www.rust-lang.org\"));\n",
"\n",
" let thd_1 = std::thread::spawn(|| {\n",
" println!(\"{:?}\", dns_service.lookup(\"www.example.com\"));\n",
" });\n",
"\n",
" thd_1.join().unwrap();\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Arc + RwLock - for shared access across threads"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"use std::collections::HashMap;\n",
"use std::sync::RwLock;\n",
"use std::borrow::BorrowMut;\n",
"\n",
"type LookupLog = Vec<String>;\n",
"\n",
"struct DnsService {\n",
" lookup_table: HashMap<String, String>,\n",
" lookup_log: RwLock<LookupLog>,\n",
"}\n",
"\n",
"impl DnsService {\n",
" fn from_slice(data: &[(&str, &str)]) -> DnsService {\n",
" DnsService {\n",
" lookup_table: data.iter().cloned().map(|(k, v)| (k.to_string(), v.to_string())).collect(),\n",
" lookup_log: RwLock::new(Vec::new())\n",
" }\n",
" }\n",
"\n",
" fn lookup(&self, hostname: &str) -> Option<&str> {\n",
" let mut log = self.lookup_log.write().unwrap();\n",
" log.push(hostname.to_string());\n",
" self.lookup_table.get(hostname).map(|s| s.as_str())\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Some(\"1.2.3.4\")\n",
"Some(\"122.33.22.33\")\n",
"Some(\"9.4.3.4\")\n",
"Dns looked up for [\"www.rust-lang.org\", \"www.example.com\", \"www.mozilla.org\"]\n"
]
}
],
"source": [
"use std::sync::Arc;\n",
"\n",
"fn main() {\n",
" let dns_service = Arc::new(\n",
" DnsService::from_slice(&[(\"www.example.com\", \"122.33.22.33\"), (\"www.rust-lang.org\", \"1.2.3.4\"), (\"www.mozilla.org\", \"9.4.3.4\")])\n",
" );\n",
"\n",
" println!(\"{:?}\", dns_service.lookup(\"www.rust-lang.org\"));\n",
"\n",
" let mut dns = dns_service.clone();\n",
" let thd_1 = std::thread::spawn(move || {\n",
" println!(\"{:?}\", dns.lookup(\"www.example.com\"));\n",
" });\n",
"\n",
" let mut dns = dns_service.clone();\n",
" let thd_2 = std::thread::spawn(move || {\n",
" println!(\"{:?}\", dns.lookup(\"www.mozilla.org\"));\n",
" });\n",
"\n",
" thd_1.join().unwrap();\n",
" thd_2.join().unwrap();\n",
"\n",
" println!(\"Dns looked up for {:?}\", dns_service.lookup_log.read().unwrap());\n",
"}\n",
"\n",
"main();"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "Rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,718 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Functions & Closures"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"People ordered by age: [Person { name: \"Marry\", age: 11, height: 1.5 }, Person { name: \"Adam\", age: 16, height: 1.6 }, Person { name: \"Alice\", age: 20, height: 1.7 }, Person { name: \"Bob\", age: 25, height: 1.8 }, Person { name: \"Charlie\", age: 30, height: 1.9 }, Person { name: \"David\", age: 35, height: 1.75 }, Person { name: \"Eve\", age: 40, height: 1.75 }]\n",
"People ordered by height: [Person { name: \"Marry\", age: 11, height: 1.5 }, Person { name: \"Adam\", age: 16, height: 1.6 }, Person { name: \"Alice\", age: 20, height: 1.7 }, Person { name: \"David\", age: 35, height: 1.75 }, Person { name: \"Eve\", age: 40, height: 1.75 }, Person { name: \"Bob\", age: 25, height: 1.8 }, Person { name: \"Charlie\", age: 30, height: 1.9 }]\n"
]
}
],
"source": [
"#[derive(Debug, PartialEq, Clone)]\n",
"struct Person {\n",
" name: String,\n",
" age: u8,\n",
" height: f32\n",
"}\n",
"\n",
"fn create_people() -> Vec<Person> {\n",
" vec![\n",
" Person {\n",
" name: \"Alice\".to_string(),\n",
" age: 20,\n",
" height: 1.7\n",
" },\n",
" Person {\n",
" name: \"Bob\".to_string(),\n",
" age: 25,\n",
" height: 1.8\n",
" },\n",
" Person {\n",
" name: \"Charlie\".to_string(),\n",
" age: 30,\n",
" height: 1.9\n",
" },\n",
" Person {\n",
" name: \"David\".to_string(),\n",
" age: 35,\n",
" height: 1.75\n",
" },\n",
" Person {\n",
" name: \"Eve\".to_string(),\n",
" age: 40,\n",
" height: 1.75\n",
" },\n",
" Person {\n",
" name: \"Adam\".to_string(),\n",
" age: 16,\n",
" height: 1.6\n",
" },\n",
" Person {\n",
" name: \"Marry\".to_string(),\n",
" age: 11,\n",
" height: 1.5\n",
" }\n",
" ]\n",
"}\n",
"\n",
"let people = create_people();\n",
"\n",
"let people_sorted_by_age = {\n",
" let mut people = people.clone();\n",
" people.sort_by_key(|person| person.age);\n",
" people\n",
"};\n",
"\n",
"let people_sorted_by_height = {\n",
" let mut people = people.clone();\n",
" people.sort_by(|person, other| f32::total_cmp(&person.height, &other.height));\n",
" people\n",
"};\n",
"\n",
"println!(\"People ordered by age: {:?}\", people_sorted_by_age);\n",
"println!(\"People ordered by height: {:?}\", people_sorted_by_height);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Closures Borrow by Default"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"People with translated names: [Person { name: \"Alicja\", age: 20, height: 1.7 }, Person { name: \"Robert\", age: 25, height: 1.8 }, Person { name: \"Karol\", age: 30, height: 1.9 }, Person { name: \"Dawid\", age: 35, height: 1.75 }, Person { name: \"Ewa\", age: 40, height: 1.75 }, Person { name: \"Adam\", age: 16, height: 1.6 }, Person { name: \"Maria\", age: 11, height: 1.5 }]\n"
]
}
],
"source": [
"use std::collections::HashMap;\n",
"\n",
"fn create_name_translator() -> HashMap<String, String> {\n",
" [\n",
" (\"Alice\".to_string(), \"Alicja\".to_string()),\n",
" (\"Bob\".to_string(), \"Robert\".to_string()),\n",
" (\"Charlie\".to_string(), \"Karol\".to_string()),\n",
" (\"David\".to_string(), \"Dawid\".to_string()),\n",
" (\"Eve\".to_string(), \"Ewa\".to_string()),\n",
" (\"Adam\".to_string(), \"Adam\".to_string()),\n",
" (\"Marry\".to_string(), \"Maria\".to_string())\n",
" ].iter().cloned().collect()\n",
"}\n",
"\n",
"fn main() {\n",
" let people = create_people();\n",
"\n",
" let name_translator: HashMap<_, _> = create_name_translator();\n",
"\n",
" let person_name_translator = |person: &Person| {\n",
" let translated_name = name_translator.get(&person.name).unwrap_or(&person.name); // name_translator is borrowed\n",
" Person {\n",
" name: translated_name.to_string(),\n",
" age: person.age,\n",
" height: person.height\n",
" }\n",
" };\n",
"\n",
" let people_translated: Vec<Person> = people.iter().map(person_name_translator).collect();\n",
"\n",
" println!(\"People with translated names: {:?}\", people_translated);\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Closures That Move"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"People with translated names: [Person { name: \"Alicja\", age: 20, height: 1.7 }, Person { name: \"Robert\", age: 25, height: 1.8 }, Person { name: \"Karol\", age: 30, height: 1.9 }, Person { name: \"Dawid\", age: 35, height: 1.75 }, Person { name: \"Ewa\", age: 40, height: 1.75 }, Person { name: \"Adam\", age: 16, height: 1.6 }, Person { name: \"Maria\", age: 11, height: 1.5 }]\n"
]
}
],
"source": [
"fn main() {\n",
" let people: Vec<Person> = create_people();\n",
" let name_translator: HashMap<String, String> = create_name_translator();\n",
"\n",
" let person_name_translator = move |person: &Person| {\n",
" let translated_name = name_translator.get(&person.name).unwrap_or(&person.name); // name_translator is moved\n",
" Person {\n",
" name: translated_name.to_string(),\n",
" age: person.age,\n",
" height: person.height\n",
" }\n",
" };\n",
"\n",
" let thd = std::thread::spawn(move || { \n",
" let people_translated: Vec<Person> = people.iter().map(person_name_translator).collect(); // people & person_name_translator are moved\n",
" \n",
" println!(\"People with translated names: {:?}\", people_translated);\n",
" });\n",
"\n",
" thd.join().unwrap();\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Function & Closure Types"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Function Type"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"fn is_adult(person: &Person) -> bool {\n",
" person.age >= 18\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The function `is_adult` has a type: `fn(&Person) -> bool`"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Adults: [Person { name: \"Alice\", age: 20, height: 1.7 }, Person { name: \"Bob\", age: 25, height: 1.8 }, Person { name: \"Charlie\", age: 30, height: 1.9 }, Person { name: \"David\", age: 35, height: 1.75 }, Person { name: \"Eve\", age: 40, height: 1.75 }]\n"
]
}
],
"source": [
"let f_predicate: fn(&Person) -> bool = is_adult;\n",
"\n",
"fn filter_by_predicate(people: &Vec<Person>, predicate: fn(&Person) -> bool) -> Vec<Person> {\n",
" let mut qualified: Vec<Person> = Vec::new();\n",
" for person in people {\n",
" if predicate(person) {\n",
" qualified.push(person.clone());\n",
" }\n",
" }\n",
" qualified\n",
"}\n",
"\n",
"let adults = filter_by_predicate(&people, is_adult);\n",
"\n",
"println!(\"Adults: {:?}\", adults);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"When function expects a function as an argument, it accepts a closure that captures nothing:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Tall people: [Person { name: \"Bob\", age: 25, height: 1.8 }, Person { name: \"Charlie\", age: 30, height: 1.9 }]\n"
]
}
],
"source": [
"let tall_people = filter_by_predicate(&people, |person| person.height > 1.75);\n",
"\n",
"println!(\"Tall people: {:?}\", tall_people);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A closure that captures variables from the enclosing scope cannot be passed to a function that accepts a function type:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"ename": "Error",
"evalue": "mismatched types",
"output_type": "error",
"traceback": [
"\u001b[31m[E0308] Error:\u001b[0m mismatched types",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_10:1:1 \u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mf\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100ml\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100m_\u001b[0m\u001b[38;5;100mb\u001b[0m\u001b[38;5;100my\u001b[0m\u001b[38;5;100m_\u001b[0m\u001b[38;5;100mp\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100md\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100mc\u001b[0m\u001b[38;5;100ma\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m|\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54m|\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54m.\u001b[0m\u001b[38;5;54mh\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mg\u001b[0m\u001b[38;5;54mh\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m>\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;68mh\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68mg\u001b[0m\u001b[38;5;68mh\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;68m_\u001b[0m\u001b[38;5;68ml\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68mm\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m arguments to this function are incorrect",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m│\u001b[0m \u001b[38;5;68m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected fn pointer, found closure",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m `height_limit` captured here",
"\u001b[38;5;246m───╯\u001b[0m"
]
}
],
"source": [
"let height_limit = 1.75;\n",
"let tall_people = filter_by_predicate(&people, |person| person.height > height_limit);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### `Fn` Trait"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Functions and closures implement the `Fn` trait, which is the trait of things that can be called like functions."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"fn filter_by_predicate<F>(people: &Vec<Person>, predicate: F) -> Vec<Person>\n",
" where F: Fn(&Person) -> bool \n",
"{\n",
" let mut qualified: Vec<Person> = Vec::new();\n",
" for person in people {\n",
" if predicate(person) {\n",
" qualified.push(person.clone());\n",
" }\n",
" }\n",
" qualified\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Adults: [Person { name: \"Alice\", age: 20, height: 1.7 }, Person { name: \"Bob\", age: 25, height: 1.8 }, Person { name: \"Charlie\", age: 30, height: 1.9 }, Person { name: \"David\", age: 35, height: 1.75 }, Person { name: \"Eve\", age: 40, height: 1.75 }]\n",
"Tall people: [Person { name: \"Bob\", age: 25, height: 1.8 }, Person { name: \"Charlie\", age: 30, height: 1.9 }]\n"
]
}
],
"source": [
"let adults = filter_by_predicate(&people, is_adult); // using function pointer\n",
"println!(\"Adults: {:?}\", adults);\n",
"\n",
"let height_limit = 1.75;\n",
"let tall_people = filter_by_predicate(&people, |person| person.height > height_limit); // using closure that captures (borrows) height_limit\n",
"println!(\"Tall people: {:?}\", tall_people);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Now the function `filter_by_predicate` is generic. It accepts any function or closure `F` that implements the special trait `Fn(&Person) -> bool`.\n",
"* The trait `Fn(&Person) -> bool` automatically implemented by all functions and closures that can be called with a `&Person` argument and return a `bool`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### `FnMut` Trait\n",
"\n",
"* The `FnMut` trait is a subtrait of `Fn`. It allows the closure to mutate the captured variables."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Generated number: 11\n",
"Generated number: 12\n",
"Generated number: 13\n"
]
}
],
"source": [
"fn create_generator(seed: i32) -> impl FnMut() -> i32 {\n",
" let mut state = seed;\n",
" move || {\n",
" state += 1; // mutating captured state\n",
" state\n",
" }\n",
"}\n",
"\n",
"fn main() {\n",
" let mut generator = create_generator(10);\n",
" println!(\"Generated number: {}\", generator());\n",
" println!(\"Generated number: {}\", generator());\n",
" println!(\"Generated number: {}\", generator());\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"fn main() {\n",
" let mut state = 10;\n",
"\n",
" let mut f = || {\n",
" state += 1; // mutating captured state\n",
" state\n",
" };\n",
"\n",
" let mut boxed_f: Box<dyn FnMut()->i32> = Box::new(f);\n",
"\n",
" boxed_f();\n",
" boxed_f();\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### `FnOnce` Trait\n",
"\n",
"* Some functions and closures can be called only once. They are not allowed to be called multiple times.\n",
"* The trait `FnOnce` is the trait of things that can be called once. It is implemented by functions and closures that can be called only once.\n",
" * The `FnOnce` trait is a subtrait of the `FnMut` trait, which is a subtrait of the `Fn` trait."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"ename": "Error",
"evalue": "use of moved value: `f`",
"output_type": "error",
"traceback": [
"\u001b[31m[E0382] Error:\u001b[0m use of moved value: `f`",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_15:1:1 \u001b[38;5;246m]\u001b[0m",
" \u001b[38;5;246m│\u001b[0m",
" \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;68mm\u001b[0m\u001b[38;5;68my\u001b[0m\u001b[38;5;68m_\u001b[0m\u001b[38;5;68ms\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;68mr\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;68mg\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249me\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m note: closure cannot be invoked more than once because it moves the variable `my_string` out of its environment",
" \u001b[38;5;240m │\u001b[0m ",
" \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;37mf\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;37m┬\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m note: this value implements `FnOnce`, which causes it to be moved when called",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m│\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `f` moved due to this call",
" \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mf\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m┬\u001b[0m ",
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m value used here after move",
"\u001b[38;5;246m───╯\u001b[0m"
]
}
],
"source": [
"fn main() {\n",
" let my_string = \"Hello, World!\".to_string();\n",
" let f = || drop(my_string); // this closure should be called only once\n",
"\n",
" f();\n",
" f();\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Data: [1, 2, 3, 4, 5, 665]\n"
]
}
],
"source": [
"fn main() {\n",
" let mut data = vec![1, 2, 3, 4, 5];\n",
"\n",
" let mut f_once = || {\n",
" data.push(665); // mutating captured data\n",
" data // moving the data out of the closure\n",
" };\n",
"\n",
" let mut f_once_boxed: Box<dyn FnOnce() -> Vec<i32>> = Box::new(f_once);\n",
"\n",
" let data = f_once_boxed();\n",
" println!(\"Data: {:?}\", data);\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* `Fn` is the family of closures and functions that you can call multiple times without restriction. This highest category also includes all fn functions.\n",
"\n",
"* `FnMut` is the family of closures that can be called multiple times if the closure itself is declared mut.\n",
"\n",
"* `FnOnce` is the family of closures that can be called once, if the caller owns the closure.\n",
"\n",
"* Every `Fn` meets the requirements for `FnMut`, and every `FnMut` meets the requirements for `FnOnce`"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [],
"source": [
"// mod explain {\n",
"// // Pseudocode for `Fn`, `FnMut`, and `FnOnce` traits.\n",
"// trait Fn() -> R {\n",
"// fn call(&self) -> R;\n",
"// }\n",
"\n",
"// trait FnMut() -> R {\n",
"// fn call_mut(&mut self) -> R;\n",
"// }\n",
"\n",
"// trait FnOnce() -> R {\n",
"// fn call_once(self) -> R;\n",
"// }\n",
"// }"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Copy and Clone for Closures\n",
"\n",
"* Just as Rust automatically figures out which closures can be called only once, it can figure out which closures can implement `Copy` and `Clone`, and which cannot."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"fn main() {\n",
" let y = 4;\n",
" let add_y = move |x| x + y;\n",
" let copy_of_add_y = add_y; // closure is copied\n",
" assert_eq!(add_y(copy_of_add_y(3)), 11);\n",
"\n",
" let word: String = \"Hello\".to_string();\n",
" let append_word = move |mut s: String| {\n",
" s.push_str(&word); \n",
" s\n",
" };\n",
" let copy_of_append_word = append_word.clone(); // closure is cloned\n",
" assert_eq!(append_word(copy_of_append_word(\" World\".to_string())), \" WorldHelloHello\");\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Callbacks"
]
},
{
"cell_type": "markdown",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"source": [
"* Callbacks are functions that are passed as arguments to other functions.\n",
"* Callbacks are used to implement event handlers, asynchronous programming, and other patterns."
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"type Callback = Box<dyn Fn(f32)>;\n",
"\n",
"struct TemperaturMonitor {\n",
" current_temp: f32,\n",
" on_temperature_changed: Option<Callback>,\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [],
"source": [
"impl TemperaturMonitor {\n",
" fn new() -> Self {\n",
" Self {\n",
" current_temp: 0.0,\n",
" on_temperature_changed: None,\n",
" }\n",
" }\n",
"\n",
" fn set_on_temperature_changed<F: Fn(f32) + 'static>(&mut self, callback: F) {\n",
" self.on_temperature_changed = Some(Box::new(callback));\n",
" }\n",
"\n",
" fn set_current_temp(&mut self, temp: f32) {\n",
" self.current_temp = temp;\n",
" if let Some(ref on_temperature_changed) = self.on_temperature_changed {\n",
" on_temperature_changed(self.current_temp);\n",
" }\n",
" } \n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Rust makes us add this `'static bound`. Without it, the call to `Box::new(callback)` would be an error, because it’s not safe to store a closure if it contains borrowed references to variables that are about to go out of scope.)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Temperature changed to: 22.5\n",
"Temperature changed to: 23.5\n",
"Current temperature is: 24.7°C\n",
"Current temperature is: 27.1°C\n"
]
}
],
"source": [
"fn main() {\n",
" let mut monitor = TemperaturMonitor::new();\n",
" monitor.set_on_temperature_changed(|temp| println!(\"Temperature changed to: {}\", temp));\n",
" monitor.set_current_temp(22.5);\n",
" monitor.set_current_temp(23.5);\n",
"\n",
" monitor.set_on_temperature_changed(|temp| println!(\"Current temperature is: {}°C\", temp));\n",
" monitor.set_current_temp(24.7);\n",
" monitor.set_current_temp(27.1);\n",
"}\n",
"\n",
"main();"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 2
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,650 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "4e3ae322",
"metadata": {},
"source": [
"# Multithreading in Rust"
]
},
{
"cell_type": "markdown",
"id": "947ff014",
"metadata": {},
"source": [
"## Managing Threads\n",
"\n",
"### Creating and joining threads\n",
"\n",
"* Creating a thread using `std::thread::spawn`\n",
"* Joining threads to wait for their completion using `join()`"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "e8d84fec",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Counting 1 in background ThreadId(2)\n",
"Counting 1 in spawned ThreadId(3)\n",
"Counting 2 in background ThreadId(2)\n",
"Counting 2 in spawned ThreadId(3)\n",
"Counting 3 in background ThreadId(2)\n",
"Counting 3 in spawned ThreadId(3)\n",
"Counting 4 in background ThreadId(2)\n",
"Counting 4 in spawned ThreadId(3)\n",
"Counting 5 in spawned ThreadId(3)\n",
"Counting 5 in background ThreadId(2)\n",
"Counting 6 in spawned ThreadId(3)\n",
"Counting 6 in background ThreadId(2)\n",
"Counting 7 in background ThreadId(2)\n",
"Counting 7 in spawned ThreadId(3)\n",
"Counting 8 in background ThreadId(2)\n",
"Counting 8 in spawned ThreadId(3)\n",
"Counting 9 in spawned ThreadId(3)\n",
"Counting 9 in background ThreadId(2)\n",
"Counting 10 in spawned ThreadId(3)\n",
"Counting 10 in background ThreadId(2)\n"
]
}
],
"source": [
"use std::thread;\n",
"\n",
"fn background_counting() {\n",
" for i in 1..=10 {\n",
" println!(\"Counting {} in background {:?}\", i, thread::current().id());\n",
" thread::sleep(std::time::Duration::from_millis(50));\n",
" }\n",
"}\n",
"\n",
"let thd_1 = thread::spawn(background_counting);\n",
"\n",
"let thd_2 = thread::spawn(|| {\n",
" for i in 1..=10 {\n",
" println!(\"Counting {} in spawned {:?}\", i, thread::current().id());\n",
" thread::sleep(std::time::Duration::from_millis(50));\n",
" }\n",
"});\n",
"\n",
"thd_1.join().unwrap();\n",
"thd_2.join().unwrap();"
]
},
{
"cell_type": "markdown",
"id": "d64ca60d",
"metadata": {},
"source": [
"## Sharing Data Between Threads\n",
"\n",
"\n",
"### Transfer Ownership\n",
"\n",
"* Safely transfer ownership of data to threads\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "80c5a805",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Processing data_vec in thread ThreadId(4)\n",
"Sum of data_vec: 500500\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"let data_vec = (1..=1000).collect::<Vec<i32>>();\n",
"\n",
"let thd_process = thread::spawn(move || {\n",
" println!(\"Processing data_vec in thread {:?}\", thread::current().id());\n",
" thread::sleep(std::time::Duration::from_millis(500));\n",
" let sum: i32 = data_vec.iter().sum();\n",
" // panic!(\"Intentional panic after processing data_vec with sum {}\", sum);\n",
" sum\n",
"});\n",
"\n",
"match thd_process.join() {\n",
" Ok(sum) => println!(\"Sum of data_vec: {}\", sum),\n",
" Err(e) => println!(\"Thread panicked: {:?}\", e),\n",
"}"
]
},
{
"cell_type": "markdown",
"id": "72eaed46",
"metadata": {},
"source": [
"### Shared Ownership - Immutable Data\n",
"\n",
"* Using `Arc<T>` for shared ownership across threads"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "01bd107d",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Min in thread ThreadId(6): 1\n",
"Max in thread ThreadId(6): 100\n",
"Sum in thread ThreadId(5): 5025\n",
"Final Results - Total Sum: 5025, Min: 1, Max: 100\n"
]
}
],
"source": [
":dep rand = \"0.9\"\n",
"\n",
"use rand::random_range;\n",
"use std::iter::from_fn;\n",
"use std::sync::Arc;\n",
"\n",
"let data: Vec<i32> = from_fn(|| Some(random_range(1..=100))).take(100).collect();\n",
"let shared_data = Arc::new(data);\n",
"\n",
"let thd_sum = {\n",
" let data_clone = Arc::clone(&shared_data);\n",
" thread::spawn(move || {\n",
" let sum: i32 = data_clone.iter().sum();\n",
" println!(\"Sum in thread {:?}: {}\", thread::current().id(), sum);\n",
" sum\n",
" })\n",
"}; \n",
"\n",
"let thd_max = {\n",
" let data_clone = Arc::clone(&shared_data);\n",
" thread::spawn(move || {\n",
" let min = data_clone.iter().min().cloned().unwrap();\n",
" println!(\"Min in thread {:?}: {}\", thread::current().id(), min);\n",
" let max = data_clone.iter().max().cloned().unwrap();\n",
" println!(\"Max in thread {:?}: {}\", thread::current().id(), max);\n",
" (min, max)\n",
" })\n",
"};\n",
"\n",
"let total_sum = thd_sum.join().unwrap();\n",
"let (min_value, max_value) = thd_max.join().unwrap();\n",
"\n",
"println!(\"Final Results - Total Sum: {}, Min: {}, Max: {}\", total_sum, min_value, max_value);"
]
},
{
"cell_type": "markdown",
"id": "85f2b2a1",
"metadata": {},
"source": [
"### Shared Mutable State Between Threads"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "3c499020",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"use std::sync::{Arc, Mutex};\n",
"\n",
"pub struct BankAccount {\n",
" // balance: f32\n",
" balance: Mutex<f32>,\n",
"}\n",
"\n",
"impl BankAccount {\n",
" pub fn new(initial_balance: f32) -> Self {\n",
" BankAccount { balance: Mutex::new(initial_balance) }\n",
" }\n",
" \n",
" pub fn deposit(&self, amount: f32) {\n",
" *self.balance.lock().unwrap() += amount;\n",
" }\n",
" \n",
" pub fn withdraw(&self, amount: f32) -> Result<(), String> {\n",
" let mut balance = self.balance.lock().unwrap();\n",
" if amount > *balance {\n",
" Err(\"Insufficient funds\".to_string())\n",
" } else {\n",
" *balance -= amount;\n",
" Ok(())\n",
" }\n",
" }\n",
"\n",
" fn transfer(&self, to: &BankAccount, amount: f32) -> Result<(), String> {\n",
" let mut from_balance = self.balance.lock().unwrap();\n",
" if amount > *from_balance {\n",
" return Err(\"Insufficient funds\".to_string());\n",
" }\n",
" let mut to_balance = to.balance.lock().unwrap();\n",
"\n",
" *from_balance -= amount;\n",
" *to_balance += amount;\n",
" \n",
" Ok(())\n",
" }\n",
" \n",
" pub fn balance(&self) -> f32 {\n",
" *self.balance.lock().unwrap()\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "aa2240cd",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [],
"source": [
"fn pay_in(account: Arc<BankAccount>, amount: f32, count: usize) {\n",
" for _ in 0..count {\n",
" if account.balance() < 200.0 {\n",
" println!(\"Balance low: ${}, depositing ${}\", account.balance(), amount);\n",
" account.deposit(amount);\n",
" } \n",
"\n",
" std::thread::sleep(std::time::Duration::from_millis(10));\n",
" }\n",
"}\n",
"\n",
"fn take_out(account: Arc<BankAccount>, amount: f32, count: usize) {\n",
" for _ in 0..count {\n",
" match account.withdraw(amount) {\n",
" Ok(_) => println!(\"Withdrew ${}, new balance: ${}\", amount, account.balance()),\n",
" Err(e) => println!(\"Failed to withdraw ${}: {}\", amount, e),\n",
" }\n",
"\n",
" std::thread::sleep(std::time::Duration::from_millis(20));\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "a22be054",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Withdrew $30, new balance: $70\n",
"Balance low: $70, depositing $50\n",
"Balance low: $120, depositing $50\n",
"Withdrew $30, new balance: $140\n",
"Balance low: $140, depositing $50\n",
"Balance low: $190, depositing $50\n",
"Withdrew $30, new balance: $210\n",
"Withdrew $30, new balance: $180\n",
"Balance low: $180, depositing $50\n",
"Withdrew $30, new balance: $200\n",
"Withdrew $30, new balance: $170\n",
"Withdrew $30, new balance: $140\n",
"Withdrew $30, new balance: $110\n",
"Withdrew $30, new balance: $80\n",
"Withdrew $30, new balance: $50\n"
]
}
],
"source": [
"fn main() {\n",
" let mut account = Arc::new(BankAccount::new(100.0));\n",
"\n",
" let mut account_for_pay_in = Arc::clone(&account);\n",
" let pay_in_thread = std::thread::spawn(move || pay_in(account_for_pay_in, 50.0, 10));\n",
"\n",
" let mut account_for_take_out = Arc::clone(&account);\n",
" let take_out_thread = std::thread::spawn(move || take_out(account_for_take_out, 30.0, 10));\n",
"\n",
" pay_in_thread.join().unwrap();\n",
" take_out_thread.join().unwrap();\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"id": "7f7968af",
"metadata": {},
"source": [
"## Send and Sync"
]
},
{
"cell_type": "markdown",
"id": "e02fb112",
"metadata": {},
"source": [
"* The `Send` and `Sync` traits affect the ability to transfer and share data between threads\n",
"* Types that implement `Send` can be transferred to another thread\n",
" * Most primitive types in Rust implement `Send`\n",
" * Owned types like `String` and `Vec<T>` also implement `Send`\n",
" * Types that do not implement `Send` include raw pointers and types that manage non-thread-safe resources: `Rc<T>`, `RefCell<T>`\n",
"* Types that implement `Sync` can be referenced from multiple threads safely\n",
" * Immutable references (`&T`) are `Sync` if `T` is `Sync`\n",
" * Mutable references (`&mut T`) are not `Sync`\n",
" * Types that do not implement `Sync` include `Cell<T>` and `RefCell<T>`\n",
" * Types like `Mutex<T>` and `RwLock<T>` provide safe shared mutable access across threads"
]
},
{
"cell_type": "markdown",
"id": "7c6393dc",
"metadata": {},
"source": [
"## Deadlocks"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "5ae7b3aa",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Transferred $50 from BankAccount#1 to BankAccount#2. New balances: from $450, to $350\n",
"Transferred $30 from BankAccount#2 to BankAccount#1. New balances: from $320, to $480\n",
"Transferred $30 from BankAccount#2 to BankAccount#1. New balances: from $290, to $510\n",
"Transferred $50 from BankAccount#1 to BankAccount#2. New balances: from $460, to $340\n",
"Transferred $30 from BankAccount#2 to BankAccount#1. New balances: from $310, to $490\n",
"Transferred $50 from BankAccount#1 to BankAccount#2. New balances: from $440, to $360\n",
"Transferred $30 from BankAccount#2 to BankAccount#1. New balances: from $330, to $470\n",
"Transferred $50 from BankAccount#1 to BankAccount#2. New balances: from $420, to $380\n",
"Transferred $30 from BankAccount#2 to BankAccount#1. New balances: from $350, to $450\n",
"Transferred $50 from BankAccount#1 to BankAccount#2. New balances: from $400, to $400\n",
"Transferred $30 from BankAccount#2 to BankAccount#1. New balances: from $370, to $430\n",
"Transferred $50 from BankAccount#1 to BankAccount#2. New balances: from $380, to $420\n",
"Transferred $30 from BankAccount#2 to BankAccount#1. New balances: from $390, to $410\n",
"Transferred $50 from BankAccount#1 to BankAccount#2. New balances: from $360, to $440\n",
"Transferred $30 from BankAccount#2 to BankAccount#1. New balances: from $410, to $390\n",
"Transferred $50 from BankAccount#1 to BankAccount#2. New balances: from $340, to $460\n",
"Transferred $30 from BankAccount#2 to BankAccount#1. New balances: from $430, to $370\n",
"Transferred $50 from BankAccount#1 to BankAccount#2. New balances: from $320, to $480\n",
"Transferred $30 from BankAccount#2 to BankAccount#1. New balances: from $450, to $350\n",
"Transferred $50 from BankAccount#1 to BankAccount#2. New balances: from $300, to $500\n",
"Final Balance of Account A: $300\n",
"Final Balance of Account B: $500\n"
]
}
],
"source": [
"use std::sync::{Arc, Mutex};\n",
"\n",
"mod Bank {\n",
" use std::sync::{Arc, Mutex};\n",
"\n",
" pub struct BankAccount {\n",
" id: u32,\n",
" balance: Mutex<f32>,\n",
" }\n",
"\n",
" impl BankAccount {\n",
" pub fn new(id: u32, initial_balance: f32) -> Self {\n",
" BankAccount { id, balance: std::sync::Mutex::new(initial_balance) }\n",
" }\n",
"\n",
" pub fn transfer(&self, to: &BankAccount, amount: f32) -> Result<(), String> {\n",
"\n",
" let (mut from_balance, mut to_balance) = if self.id < to.id {\n",
" let from_balance = self.balance.lock().unwrap();\n",
" let to_balance = to.balance.lock().unwrap();\n",
" (from_balance, to_balance)\n",
" } else {\n",
" let to_balance = to.balance.lock().unwrap();\n",
" let from_balance = self.balance.lock().unwrap();\n",
" (from_balance, to_balance)\n",
" };\n",
"\n",
" //let mut from_balance = self.balance.lock().unwrap();\n",
" //let mut to_balance = to.balance.lock().unwrap();\n",
"\n",
" *from_balance -= amount;\n",
" *to_balance += amount;\n",
" \n",
" Ok(())\n",
" }\n",
" \n",
" pub fn balance(&self) -> f32 {\n",
" *self.balance.lock().unwrap()\n",
" }\n",
"\n",
" pub fn id(&self) -> u32 {\n",
" self.id\n",
" }\n",
" }\n",
"\n",
" pub fn transfer_funds(from: Arc<BankAccount>, to: Arc<BankAccount>, amount: f32, count: usize) {\n",
" for _ in 0..count {\n",
" match from.transfer(&to, amount) {\n",
" Ok(_) => println!(\"Transferred ${} from BankAccount#{} to BankAccount#{}. New balances: from ${}, to ${}\", \n",
" amount, from.id(), to.id(), from.balance(), to.balance()),\n",
" Err(e) => println!(\"Failed to transfer ${} from BankAccount#{} to BankAccount#{}: {}\", \n",
" amount, from.id(), to.id(), e),\n",
" }\n",
"\n",
" std::thread::sleep(std::time::Duration::from_millis(15));\n",
" }\n",
" }\n",
"\n",
"}\n",
"\n",
"fn main() {\n",
" let account_a = Arc::new(Bank::BankAccount::new(1, 500.0));\n",
" let account_b = Arc::new(Bank::BankAccount::new(2, 300.0));\n",
"\n",
" let account_a_for_transfer_1 = Arc::clone(&account_a);\n",
" let account_b_for_transfer_1 = Arc::clone(&account_b);\n",
"\n",
" let thd_transfer_from_a_to_b = std::thread::spawn(move || {\n",
" Bank::transfer_funds(account_a_for_transfer_1, account_b_for_transfer_1, 50.0, 10);\n",
" });\n",
"\n",
" let account_a_for_transfer_2 = Arc::clone(&account_a);\n",
" let account_b_for_transfe_2 = Arc::clone(&account_b);\n",
" let thd_transfer_from_b_to_a = std::thread::spawn(move || {\n",
" Bank::transfer_funds(account_b_for_transfe_2, account_a_for_transfer_2, 30.0, 10);\n",
" });\n",
"\n",
" thd_transfer_from_a_to_b.join().unwrap();\n",
"\n",
" println!(\"Final Balance of Account A: ${}\", account_a.balance());\n",
" println!(\"Final Balance of Account B: ${}\", account_b.balance());\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"id": "52220484",
"metadata": {},
"source": [
"## Thread Communication With Channels"
]
},
{
"cell_type": "markdown",
"id": "b3653ab8",
"metadata": {},
"source": [
"* Using channels (`std::sync::mpsc`) for thread communication simplifies data transfer between threads\n",
"* Channels provide a way to send data from one thread to another safely\n",
" * Create a channel with `mpsc::channel()` - returns a sender and a receiver\n",
" * Send data between threads using the `send()` method on the sender\n",
" * Receive data in the main thread using the `recv()` method or iterating over the receiver"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "de2665bc",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Received: Hello from the sender thread\n"
]
}
],
"source": [
"use std::thread;\n",
"use std::sync::mpsc;\n",
"\n",
"fn main() {\n",
" let (sender, receiver) = mpsc::channel();\n",
"\n",
" let sender_clone = sender.clone();\n",
" let thd_sender = thread::spawn(move || {\n",
" let message = \"Hello from the sender thread\".to_string();\n",
" sender_clone.send(message).unwrap();\n",
" });\n",
"\n",
" let received_data = receiver.recv().unwrap();\n",
" println!(\"Received: {}\", received_data);\n",
"\n",
" thd_sender.join().unwrap();\n",
"}\n",
"\n",
"main();"
]
},
{
"cell_type": "markdown",
"id": "74bd9f3b",
"metadata": {},
"source": [
"### Message Passing with Structs"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "73c689b8",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Received Message - ID: 42, Content: Important data\n"
]
}
],
"source": [
"use std::thread;\n",
"use std::sync::mpsc;\n",
"\n",
"struct CustomMessage {\n",
" id: u32,\n",
" content: String,\n",
"}\n",
"\n",
"fn main() {\n",
" let (sender, receiver) = mpsc::channel();\n",
"\n",
" let sender_clone = sender.clone();\n",
" let handle = thread::spawn(move || {\n",
" let message = CustomMessage {\n",
" id: 42,\n",
" content: \"Important data\".to_string(),\n",
" };\n",
" sender_clone.send(message).unwrap();\n",
" });\n",
"\n",
" let received_message = receiver.recv().unwrap();\n",
" println!(\"Received Message - ID: {}, Content: {}\", received_message.id, received_message.content);\n",
"\n",
" handle.join().unwrap();\n",
"}\n",
"\n",
"main();"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Rust",
"language": "rust",
"name": "rust"
},
"language_info": {
"codemirror_mode": "rust",
"file_extension": ".rs",
"mimetype": "text/rust",
"name": "Rust",
"pygment_lexer": "rust",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View file

@ -0,0 +1 @@
This is a file with some text.

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View file

@ -0,0 +1,8 @@
1
2
3
42
66d5
6
7
8

View file

@ -0,0 +1,8 @@
1
2
3
42
665
6
7
8