1784 lines
48 KiB
Text
1784 lines
48 KiB
Text
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Enums"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Enums are a powerful feature in Rust that allow you to define a type by enumerating its possible variants.\n",
|
||
"\n",
|
||
"* Enums can have data associated with each variant, making them more flexible than simple enums in other languages.\n",
|
||
"\n",
|
||
"* Pattern matching with enums allows you to concisely handle different cases, making your code more expressive and safe."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## C-Style Enums"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "rust"
|
||
}
|
||
},
|
||
"source": [
|
||
"* The simplest enums are just a list of variants without any associated data.\n",
|
||
"* They are also called \"fieldless\" or \"unit\" variants.\n",
|
||
"* They work similar to enums in C/C++"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"direction = North\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"#[derive(Debug)]\n",
|
||
"enum Compass {\n",
|
||
" North,\n",
|
||
" East,\n",
|
||
" South,\n",
|
||
" West\n",
|
||
"}\n",
|
||
"\n",
|
||
"let direction = Compass::North;\n",
|
||
"\n",
|
||
"println!(\"direction = {:?}\", direction);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* In memory, values of C-style enums are stored as integers. "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"use std::mem::size_of;\n",
|
||
"\n",
|
||
"assert!(size_of::<Compass>() == 1);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Importing constructors"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"use self::Compass::*; // self - when enum type is defined in current module; otherwise name of a module\n",
|
||
"\n",
|
||
"let direction = North;"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Using Integral Values"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#[derive(Debug)]\n",
|
||
"enum HttpStatus {\n",
|
||
" Ok = 200,\n",
|
||
" NotModified = 304,\n",
|
||
" NotFound = 404\n",
|
||
"}\n",
|
||
"\n",
|
||
"assert!(size_of::<HttpStatus>() == 2);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Casting to Integer"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* \"Fieldless\" or \"unit\" variants can be converted to integral value using the `as` keyword."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"let ok_code = HttpStatus::Ok as i32;\n",
|
||
"assert!(ok_code == 200);\n",
|
||
"\n",
|
||
"assert!(HttpStatus::NotFound as i32 == 404);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Casting from Integer"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Converting from integral value requires pattern matching."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"fn http_status_from_u32(status: u32) -> Option<HttpStatus> {\n",
|
||
" match status {\n",
|
||
" 200 => Some(HttpStatus::Ok),\n",
|
||
" 304 => Some(HttpStatus::NotModified),\n",
|
||
" 404 => Some(HttpStatus::NotFound),\n",
|
||
" _ => None\n",
|
||
" }\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Some(NotFound)"
|
||
]
|
||
},
|
||
"execution_count": 8,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"http_status_from_u32(404)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"None"
|
||
]
|
||
},
|
||
"execution_count": 9,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"http_status_from_u32(1024)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Deriving From Common Traits\n",
|
||
"\n",
|
||
"* As with structs, the compiler will implement features like the `==` operator for you, but you have to ask."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#[derive(Copy, Clone, Debug, PartialEq)]\n",
|
||
"enum TimeUnit {\n",
|
||
" Seconds, Minutes, Hours, Days, Months, Years\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"assert!(TimeUnit::Seconds == TimeUnit::Seconds);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Implementing Methods for Enums"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* We can add methods to enums using `impl` blocks"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 12,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"impl TimeUnit {\n",
|
||
" /// Return the plural noun for this time unit.\n",
|
||
" fn plural(self) -> &'static str {\n",
|
||
" match self {\n",
|
||
" TimeUnit::Seconds => \"seconds\",\n",
|
||
" TimeUnit::Minutes => \"minutes\",\n",
|
||
" TimeUnit::Hours => \"hours\",\n",
|
||
" TimeUnit::Days => \"days\",\n",
|
||
" TimeUnit::Months => \"months\",\n",
|
||
" TimeUnit::Years => \"years\"\n",
|
||
" }\n",
|
||
" }\n",
|
||
"\n",
|
||
" /// Return the singular noun for this time unit.\n",
|
||
" fn singular(self) -> &'static str {\n",
|
||
" self.plural().trim_right_matches('s')\n",
|
||
" }\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 13,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"days\""
|
||
]
|
||
},
|
||
"execution_count": 13,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"let time_unit = TimeUnit::Days;\n",
|
||
"\n",
|
||
"time_unit.plural()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Enums With Data"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* The power of Rust enums lies in their ability to store additional data\n",
|
||
"* This allows to create complex data types that can hold different kinds of information"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#[derive(Clone, Debug, PartialEq)]\n",
|
||
"enum Message {\n",
|
||
" Quit, // no data associated\n",
|
||
" Move{ x: i32, y: i32 }, // named fields - like a struct\n",
|
||
" Write(String), // single String\n",
|
||
" ChangeColor(i32, i32, i32) // tuple struct of three values\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 15,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"msg = Quit\n",
|
||
"msg = Move { x: 100, y: 200 }\n",
|
||
"msg = Write(\"TEXT\")\n",
|
||
"msg = ChangeColor(255, 0, 255)\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"let mut msg = Message::Quit;\n",
|
||
"println!(\"msg = {:?}\", msg);\n",
|
||
"\n",
|
||
"msg = Message::Move{ x: 100, y: 200};\n",
|
||
"println!(\"msg = {:?}\", msg);\n",
|
||
"\n",
|
||
"msg = Message::Write(String::from(\"TEXT\"));\n",
|
||
"println!(\"msg = {:?}\", msg);\n",
|
||
"\n",
|
||
"msg = Message::ChangeColor(255, 0, 255);\n",
|
||
"println!(\"msg = {:?}\", msg);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 16,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"impl Message {\n",
|
||
" fn call(&self) {\n",
|
||
" match *self {\n",
|
||
" Message::Quit => println!(\"Quit\"),\n",
|
||
" Message::Move{ x, y } => println!(\"Move to x={}, y={}\", x, y),\n",
|
||
" Message::Write(ref text) => println!(\"Write '{}'\", text),\n",
|
||
" Message::ChangeColor(r, g, b) => println!(\"Change color to r={}, g={}, b={}\", r, g, b)\n",
|
||
" }\n",
|
||
" }\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 17,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Change color to r=255, g=0, b=255\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"msg.call();"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Generic Enums"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Enums can be parametrized with type parameters to create generic enums."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### `Option<T>`"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 18,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"mod explain {\n",
|
||
" enum Option<T> {\n",
|
||
" None,\n",
|
||
" Some(T)\n",
|
||
" }\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### `Result<T, E>`"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 19,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"mod explain{\n",
|
||
" enum Result<T, E> { \n",
|
||
" Ok(T), \n",
|
||
" Err(E) \n",
|
||
" }\n",
|
||
"} "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Real-World Example - BinaryTree"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 20,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"// An ordered collection of `T`s.\n",
|
||
"enum BinaryTree<T> {\n",
|
||
" Empty,\n",
|
||
" NonEmpty(Box<TreeNode<T>>)\n",
|
||
"}\n",
|
||
"\n",
|
||
"// A part of a BinaryTree.\n",
|
||
"struct TreeNode<T> {\n",
|
||
" element: T,\n",
|
||
" left: BinaryTree<T>,\n",
|
||
" right: BinaryTree<T>\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 21,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"use self::BinaryTree::*;\n",
|
||
"\n",
|
||
"let jupyter_tree = NonEmpty(Box::new(TreeNode {\n",
|
||
" element: \"Jupyter\",\n",
|
||
" left: Empty,\n",
|
||
" right: Empty\n",
|
||
"}));\n",
|
||
"\n",
|
||
"let mercury_tree = NonEmpty(Box::new(TreeNode {\n",
|
||
" element: \"Mercury\",\n",
|
||
" left: Empty,\n",
|
||
" right: Empty\n",
|
||
"}));\n",
|
||
"\n",
|
||
"let venus_tree = NonEmpty(Box::new(TreeNode {\n",
|
||
" element: \"Venus\",\n",
|
||
" left: Empty,\n",
|
||
" right: Empty\n",
|
||
"}));\n",
|
||
"\n",
|
||
"let mars_tree = NonEmpty(Box::new(TreeNode {\n",
|
||
" element: \"Mars\",\n",
|
||
" left: jupyter_tree,\n",
|
||
" right: mercury_tree\n",
|
||
"}));\n",
|
||
"\n",
|
||
"let uranus_tree = NonEmpty(Box::new(TreeNode {\n",
|
||
" element: \"Uranus\",\n",
|
||
" left: Empty,\n",
|
||
" right: venus_tree\n",
|
||
"}));\n",
|
||
"\n",
|
||
"// the root\n",
|
||
"let saturn_tree = NonEmpty(Box::new(TreeNode {\n",
|
||
" element: \"Saturn\",\n",
|
||
" left: mars_tree,\n",
|
||
" right: uranus_tree\n",
|
||
"}));"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Pattern Matching\n",
|
||
"\n",
|
||
"* Pattern matching allows to compare a value against a series of patterns and execute code based on which pattern matches.\n",
|
||
"* Patterns can include literals, variable names, wildcards, and more complex structures.\n",
|
||
"* Patterns are commonly used with the `match` expression in Rust.\n",
|
||
"* Match arms consist of a pattern and the code to execute if the pattern matches.\n",
|
||
"* `match` expression is **infallible** and must cover all possible cases."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 22,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"enum RoughTime {\n",
|
||
" InThePast(TimeUnit, u32),\n",
|
||
" JustNow,\n",
|
||
" InTheFuture(TimeUnit, u32)\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 23,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"fn rough_time_to_english(rt: RoughTime) -> String {\n",
|
||
" match rt {\n",
|
||
" RoughTime::InThePast(units, 1) => format!(\"{} ago\", units.singular()),\n",
|
||
" RoughTime::InThePast(units, count) => format!(\"{} {} ago\", count, units.plural()),\n",
|
||
" RoughTime::JustNow => format!(\"just now\"),\n",
|
||
" RoughTime::InTheFuture(units, 1) => format!(\"{} from now\", units.singular()), \n",
|
||
" RoughTime::InTheFuture(units, count) => format!(\"{} {} from now\", count, units.plural()) \n",
|
||
" }\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 24,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"second ago\""
|
||
]
|
||
},
|
||
"execution_count": 24,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"rough_time_to_english(RoughTime::InThePast(TimeUnit::Seconds, 1))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 25,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"42 seconds ago\""
|
||
]
|
||
},
|
||
"execution_count": 25,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"rough_time_to_english(RoughTime::InThePast(TimeUnit::Seconds, 42))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 26,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"just now\""
|
||
]
|
||
},
|
||
"execution_count": 26,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"rough_time_to_english(RoughTime::JustNow)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 27,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"42 seconds from now\""
|
||
]
|
||
},
|
||
"execution_count": 27,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"rough_time_to_english(RoughTime::InTheFuture(TimeUnit::Seconds, 42))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"| Pattern type | Example | Notes |\n",
|
||
"| ----------------------- | ---------------------- | -------------------------------------------------------------------------- |\n",
|
||
"| Literal | `100` | Matches an exact value; the name of a const is also allowed |\n",
|
||
"| | `\"name\"` | |\n",
|
||
"| Range | `0 ... 100` | Matches any value in range, including the end value |\n",
|
||
"| | `'a' ... 'k'` | |\n",
|
||
"| Wildcard | `_` | Matches any value and ignores it |\n",
|
||
"| Variable | `name` | Like _ but moves or copies the value into a new local variable |\n",
|
||
"| | `mut count` | |\n",
|
||
"| ref variable | `ref field` | Borrows a reference to the matched value instead of moving or copying it |\n",
|
||
"| | `ref mut field` | |\n",
|
||
"| Binding with subpattern | `val @ 0 ... 99` | Matches the pattern to the right of @, using the variable name to the left |\n",
|
||
"| | `ref circle @` | |\n",
|
||
"| | `Shape::Circle { .. }` | |\n",
|
||
"| Enum pattern\t | `Some(value)` | |\n",
|
||
"| | `None` | |\n",
|
||
"| | `Message::Ok` | |\n",
|
||
"| Tuple pattern\t | `(key, value)` | |\n",
|
||
"| | `(r, g, b)` | |\n",
|
||
"| Struct pattern\t | `Color(r, g, b)` | |\n",
|
||
"| | `Point { x, y }` | |\n",
|
||
"| | `Card { suit: Clubs, rank: n }` | |\n",
|
||
"| | `Account { id, name, .. }` | | \n",
|
||
"| Reference\t | `&value` | Matches only reference values |\n",
|
||
"| | `&(k, v)`\t | |\n",
|
||
"| Multiple patterns\t | `'a' \\| 'A'` | In match only (not valid in let, etc.) |\n",
|
||
"| Guard expression\t | `x if x * x <= r2` | In match only (not valid in let, etc.) |"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Literals, Variables and Wildcards in Patterns"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 28,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"4 clicks\""
|
||
]
|
||
},
|
||
"execution_count": 28,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"let no_of_clicks = 4;\n",
|
||
"\n",
|
||
"match no_of_clicks {\n",
|
||
" 0 => format!(\"No one clicked...\"),\n",
|
||
" 1 => format!(\"Just one click...\"),\n",
|
||
" n => format!(\"{} clicks\", n)\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Rust requires every match expression to handle all possible values, a wildcard is often required at the end\n",
|
||
"* This ensures that the match is exhaustive and prevents runtime errors."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 29,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"Not Ok\""
|
||
]
|
||
},
|
||
"execution_count": 29,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"let http_code = HttpStatus::NotFound;\n",
|
||
"\n",
|
||
"match http_code {\n",
|
||
" HttpStatus::Ok => \"Ok\",\n",
|
||
" _ => \"Not Ok\"\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Tuple Patterns"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 30,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"fn describe_point(x: i32, y:i32) -> &'static str {\n",
|
||
" use std::cmp::Ordering::*;\n",
|
||
"\n",
|
||
" match (x.cmp(&0), y.cmp(&0)) {\n",
|
||
" (Equal, Equal) => \"at the origin\",\n",
|
||
" (_, Equal) => \"on the x axis\",\n",
|
||
" (Equal, _) => \"on the y axis\",\n",
|
||
" (Greater, Greater) => \"in the first quadrant\",\n",
|
||
" (Less, Greater) => \"in the second quadrant\",\n",
|
||
" _ => \"somewhere else\"\n",
|
||
" }\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 31,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"on the y axis\""
|
||
]
|
||
},
|
||
"execution_count": 31,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"describe_point(0, 42)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Struct Patterns"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 32,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"straight up 100 meters\""
|
||
]
|
||
},
|
||
"execution_count": 32,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"#[derive(Debug, PartialEq)]\n",
|
||
"struct Point {\n",
|
||
" x: i32, \n",
|
||
" y: i32\n",
|
||
"}\n",
|
||
"\n",
|
||
"let location = Point{x:0, y:100};\n",
|
||
"\n",
|
||
"match location {\n",
|
||
" Point{x: 0, y: height} => format!(\"straight up {} meters\", height),\n",
|
||
" Point{x: x, y: y } => format!(\"at ({},{})\", x, y)\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Patterns like `Point { x: x, y: y }` are common when matching structs, and the redundant names are visual clutter, so Rust has a shorthand for this: `Point {x, y}` - this pattern still stores a point’s `x` field in a new local `x` and its `y` field in a new local `y`."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 33,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"straight up 100 meters\""
|
||
]
|
||
},
|
||
"execution_count": 33,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"match location {\n",
|
||
" Point{x: 0, y} => format!(\"straight up {} meters\", y),\n",
|
||
" Point{x, y} => format!(\"at ({},{})\", x, y)\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Matching larger structs"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 34,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#[derive(Debug)]\n",
|
||
"struct Person {\n",
|
||
" id: u64,\n",
|
||
" first_name: String,\n",
|
||
" last_name: String,\n",
|
||
" age: u8,\n",
|
||
" salary: f32,\n",
|
||
" job: String\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 35,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"Jan Kowalski\""
|
||
]
|
||
},
|
||
"execution_count": 35,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"let person = Person{id: 665, first_name: \"Jan\".to_string(), last_name: \"Kowalski\".to_string(), age: 32, salary:9000.99, job: \"Rust Developer\".to_string() };\n",
|
||
"\n",
|
||
"match person {\n",
|
||
" Person{id: _, first_name, last_name, age: _, salary: _, job: _} => format!(\"{} {}\", first_name, last_name)\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* We can skip uninteresting fields with `..`"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 36,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"Jan Kowalski\""
|
||
]
|
||
},
|
||
"execution_count": 36,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"let person = Person{id: 665, first_name: \"Jan\".to_string(), last_name: \"Kowalski\".to_string(), age: 32, salary:9000.99, job: \"Rust Developer\".to_string() };\n",
|
||
"\n",
|
||
"match person {\n",
|
||
" Person{first_name, last_name, ..} => format!(\"{} {}\", first_name, last_name)\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Reference Patterns"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "rust"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### `ref` Patterns\n",
|
||
"\n",
|
||
"* `ref` patterns borrow parts of a matched value"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 37,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"fn print_names(person: &Person) {\n",
|
||
" print!(\"{} {}\", person.first_name, person.last_name); \n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 38,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"ename": "Error",
|
||
"evalue": "use of deprecated method `core::str::<impl str>::trim_right_matches`: superseded by `trim_end_matches`",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[31m[deprecated] Error:\u001b[0m use of deprecated method `core::str::<impl str>::trim_right_matches`: superseded by `trim_end_matches`"
|
||
]
|
||
},
|
||
{
|
||
"ename": "Error",
|
||
"evalue": "borrow of partially moved value: `person`",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[31m[E0382] Error:\u001b[0m borrow of partially moved value: `person`",
|
||
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_38: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;249mP\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\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;54mj\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mb\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;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\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;249ms\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;100m&\u001b[0m\u001b[38;5;100mp\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;100mo\u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\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;249mk\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ms\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;249mj\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mb\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;68m┬\u001b[0m\u001b[38;5;54m┬\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;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;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;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;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m help: borrow this binding in the pattern to avoid moving the value: `ref `",
|
||
" \u001b[38;5;240m │\u001b[0m \u001b[38;5;54m│\u001b[0m \u001b[38;5;100m│\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\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 value partially moved here",
|
||
" \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\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m value borrowed here after partial move",
|
||
"\u001b[38;5;246m───╯\u001b[0m"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"let person = Person{ id: 665, first_name: \"Jan\".to_string(), last_name: \"Kowalski\".to_string(), age: 32, salary:9000.99, job: \"Rust Developer\".to_string() };\n",
|
||
"\n",
|
||
"match person {\n",
|
||
" Person{ job, .. } => { print_names(&person); println!(\"Works as {}\", job) }\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 39,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Jan Kowalski Works as Rust Developer\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"()"
|
||
]
|
||
},
|
||
"execution_count": 39,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"let person = Person{ id: 665, first_name: \"Jan\".to_string(), last_name: \"Kowalski\".to_string(), age: 32, salary:9000.99, job: \"Rust Developer\".to_string() };\n",
|
||
"\n",
|
||
"match person {\n",
|
||
" Person{ ref job, .. } => { print_names(&person); println!(\" Works as {}\", job) }\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 40,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Person { id: 665, first_name: \"JAN\", last_name: \"KOWALSKI\", age: 32, salary: 9000.99, job: \"Rust Developer\" }"
|
||
]
|
||
},
|
||
"execution_count": 40,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"fn to_upper(text: &mut String) {\n",
|
||
" *text = text.to_uppercase();\n",
|
||
"}\n",
|
||
"\n",
|
||
"let mut person = Person{ id: 665, first_name: \"Jan\".to_string(), last_name: \"Kowalski\".to_string(), age: 32, salary:9000.99, job: \"Rust Developer\".to_string() };\n",
|
||
"\n",
|
||
"match person {\n",
|
||
" Person{ref mut first_name, ref mut last_name, ..} => { to_upper(first_name); to_upper(last_name) }\n",
|
||
"}\n",
|
||
"\n",
|
||
"person"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### & Pattern\n",
|
||
"\n",
|
||
"* A pattern starting with `&` matches a reference."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 41,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"x=100, y=200\""
|
||
]
|
||
},
|
||
"execution_count": 41,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"#[derive(Debug, PartialEq)]\n",
|
||
"struct ColorCircle { pos: Point, r: u32, color: (u8, u8, u8) }\n",
|
||
"\n",
|
||
"impl ColorCircle {\n",
|
||
" fn center(&mut self) -> &mut Point {\n",
|
||
" return &mut self.pos;\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"let mut c = ColorCircle{pos: Point{x: 100, y: 200}, r: 50, color: (255, 0, 0)};\n",
|
||
"\n",
|
||
"match c.center() {\n",
|
||
" &mut Point{x, y} => { format!(\"x={}, y={}\", x, y) },\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 42,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Point { x: 10, y: 200 }"
|
||
]
|
||
},
|
||
"execution_count": 42,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"match c.center() {\n",
|
||
" &mut Point{ref mut x, ..} => { *x = 10; },\n",
|
||
"}\n",
|
||
"\n",
|
||
"c.center()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 43,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"item peeked: Item(\"one\")\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"()"
|
||
]
|
||
},
|
||
"execution_count": 43,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"#[derive(Debug)]\n",
|
||
"struct Item(String);\n",
|
||
"\n",
|
||
"let items = [Item(\"one\".to_string()), Item(\"two\".to_string()), Item(\"three\".to_string())];\n",
|
||
"\n",
|
||
"{\n",
|
||
" let mut iter = items.iter().peekable();\n",
|
||
"\n",
|
||
" match iter.peek() {\n",
|
||
" Some(&item) => println!(\"item peeked: {:?}\", item),\n",
|
||
" None => println!(\"no item\")\n",
|
||
" }\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Matching Multiple Possibilities"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 44,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"true"
|
||
]
|
||
},
|
||
"execution_count": 44,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"let text = String::from(\"\\nBC\");\n",
|
||
"\n",
|
||
"{\n",
|
||
" let mut chars = text.chars().peekable();\n",
|
||
"\n",
|
||
" let at_end = match chars.peek() {\n",
|
||
" Some(&'\\r') | Some(&'\\n') | None => true,\n",
|
||
" _ => false\n",
|
||
" };\n",
|
||
"\n",
|
||
" at_end\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 45,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"lowercase letter: a\n",
|
||
"uppercase letter: B\n",
|
||
"digit: 1\n",
|
||
"digit: 2\n",
|
||
"whitespace\n",
|
||
"other character\n",
|
||
"special character: &\n",
|
||
"special character: ^\n",
|
||
"special character: %\n",
|
||
"special character: $\n",
|
||
"special character: #\n",
|
||
"whitespace\n",
|
||
"digit: 3\n",
|
||
"digit: 4\n",
|
||
"lowercase letter: c\n",
|
||
"lowercase letter: d\n",
|
||
"other character\n",
|
||
"newline\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"()"
|
||
]
|
||
},
|
||
"execution_count": 45,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"let text = String::from(\"aB12 -&^%$# 34cd\\r\\n\");\n",
|
||
"\n",
|
||
"for c in text.chars() {\n",
|
||
" match c {\n",
|
||
" 'a'..='z' => println!(\"lowercase letter: {}\", c),\n",
|
||
" 'A'..='Z' => println!(\"uppercase letter: {}\", c),\n",
|
||
" '0'..='9' => println!(\"digit: {}\", c),\n",
|
||
" ' ' | '\\t' => println!(\"whitespace\"),\n",
|
||
" '&' | '^' | '%' | '$' | '#' => println!(\"special character: {}\", c),\n",
|
||
" '\\n' => println!(\"newline\"),\n",
|
||
" _ => println!(\"other character\")\n",
|
||
" }\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Pattern Guards"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Pattern guards allow to add additional conditional checks to patterns in match arms."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 46,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"Inside the sphere: x=0.3, y=0.4, z=0.5\""
|
||
]
|
||
},
|
||
"execution_count": 46,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"struct Point3D {\n",
|
||
" x: f64,\n",
|
||
" y: f64,\n",
|
||
" z: f64\n",
|
||
"}\n",
|
||
"\n",
|
||
"impl Point3D {\n",
|
||
" fn new(x: f64, y: f64, z: f64) -> Point3D {\n",
|
||
" Point3D{x: x, y: y, z: z}\n",
|
||
" }\n",
|
||
"\n",
|
||
" fn distance_to_origin(&self) -> f64 {\n",
|
||
" (self.x.powf(2.0) + self.y.powf(2.0) + self.z.powf(2.0)).sqrt()\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"let point = Point3D::new(0.3, 0.4, 0.5);\n",
|
||
"\n",
|
||
"match point {\n",
|
||
" Point3D{x, y, z} if point.distance_to_origin() <= 1.0 => format!(\"Inside the sphere: x={}, y={}, z={}\", x, y, z),\n",
|
||
" Point3D{x, y, z} => format!(\"Outside the sphere: x={}, y={}, z={}\", x, y, z)\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### `@` Patterns\n",
|
||
"\n",
|
||
"* Finally, `x @` pattern matches exactly like the given pattern, but on success, instead of creating variables for parts of the matched value, it creates a single variable `x` and moves or copies the whole value into it"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 47,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Matched: 5\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"()"
|
||
]
|
||
},
|
||
"execution_count": 47,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"let number = Some(5);\n",
|
||
"\n",
|
||
"match number {\n",
|
||
" Some(n @ 1..=5) => println!(\"Matched: {}\", n),\n",
|
||
" Some(n) => println!(\"Other: {}\", n),\n",
|
||
" None => println!(\"No value\"),\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 48,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"x is in range 1 to 5: 5; y is 10\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"()"
|
||
]
|
||
},
|
||
"execution_count": 48,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"let point = Point { x: 5, y: 10 };\n",
|
||
"\n",
|
||
"match point {\n",
|
||
" Point { x: n @ 1..=5, y } => println!(\"x is in range 1 to 5: {}; y is {}\", n, y),\n",
|
||
" Point { x, y } => println!(\"x is {}; y is {}\", x, y),\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 49,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#[derive(Debug, PartialEq)]\n",
|
||
"struct Circle{ center: Point, radius: u32 }\n",
|
||
"\n",
|
||
"#[derive(Debug, PartialEq)]\n",
|
||
"struct Rectangle{ top_left: Point, width: u32, height: u32 }\n",
|
||
"\n",
|
||
"#[derive(Debug, PartialEq)]\n",
|
||
"enum Shape {\n",
|
||
" Circle(Circle),\n",
|
||
" Rectangle(Rectangle)\n",
|
||
"}\n",
|
||
"\n",
|
||
"fn inflate(shape: &mut Shape, factor: u32) {\n",
|
||
" match shape {\n",
|
||
" Shape::Circle(circle @ Circle{..}) => {\n",
|
||
" circle.radius *= factor;\n",
|
||
" },\n",
|
||
" Shape::Rectangle(rect @ Rectangle{..}) => {\n",
|
||
" rect.width *= factor; \n",
|
||
" rect.height *= factor; \n",
|
||
" }\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"let mut s = Shape::Circle(Circle{center: Point{x: 100, y: 200}, radius: 50});\n",
|
||
"\n",
|
||
"inflate(&mut s, 2);\n",
|
||
"\n",
|
||
"assert!(s == Shape::Circle(Circle{center: Point{x: 100, y: 200}, radius: 100}));"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Where Patterns Can Be Applied\n",
|
||
"\n",
|
||
"#### Irrefutable patterns\n",
|
||
"\n",
|
||
"* Patterns that always match are special in Rust. \n",
|
||
"* They’re called **irrefutable patterns**\n",
|
||
"* They’re the only patterns allowed places shown below"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### Unpack a struct into three new local variables"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 50,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"x=1, y=2\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"()"
|
||
]
|
||
},
|
||
"execution_count": 50,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"let point = Point3D::new(1.0, 2.0, 3.0);\n",
|
||
"\n",
|
||
"let Point3D{x, y, ..} = point; // unpacking\n",
|
||
"\n",
|
||
"println!(\"x={}, y={}\", x, y)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### Unpack a function argument that's a tuple"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 51,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"5.0"
|
||
]
|
||
},
|
||
"execution_count": 51,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"fn distance_to((x, y): (f64, f64)) -> f64 { \n",
|
||
" (x.powf(2.0) + y.powf(2.0)).sqrt() \n",
|
||
"}\n",
|
||
"\n",
|
||
"distance_to((3.0, 4.0))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### Iterate over keys and values of a HashMap"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 52,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"three: 3\n",
|
||
"one: 1\n",
|
||
"two: 2\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"()"
|
||
]
|
||
},
|
||
"execution_count": 52,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"use std::collections::HashMap;\n",
|
||
"\n",
|
||
"let mut dictionary = HashMap::new();\n",
|
||
"dictionary.insert(\"one\", 1);\n",
|
||
"dictionary.insert(\"two\", 2);\n",
|
||
"dictionary.insert(\"three\", 3);\n",
|
||
"\n",
|
||
"for (key, value) in &dictionary {\n",
|
||
" println!(\"{}: {}\", key, value);\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### Refutable Patterns\n",
|
||
"\n",
|
||
"* A **refutable pattern** is one that might not match, like `Ok(x)`, which doesn’t match an error result, or `'0' ... '9'`, which doesn’t match the character `'Q'`\n",
|
||
"\n",
|
||
"* Refutable patterns are also allowed in `if let` and `while let` expressions, which can be used to..."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 53,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"32 years ago\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"()"
|
||
]
|
||
},
|
||
"execution_count": 53,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"fn date_of_birth() -> RoughTime {\n",
|
||
" RoughTime::InThePast(TimeUnit::Years, 32)\n",
|
||
"}\n",
|
||
"\n",
|
||
"if let RoughTime::InThePast(units, count) = date_of_birth() {\n",
|
||
" println!(\"{} years ago\", count);\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Real-World Example - BinaryTree - 2"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"// An ordered collection of `T`s.\n",
|
||
"enum BinaryTree<T> {\n",
|
||
" Empty,\n",
|
||
" NonEmpty(Box<TreeNode<T>>)\n",
|
||
"}\n",
|
||
"\n",
|
||
"// A part of a BinaryTree.\n",
|
||
"struct TreeNode<T> {\n",
|
||
" element: T,\n",
|
||
" left: BinaryTree<T>,\n",
|
||
" right: BinaryTree<T>\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"impl<T: Ord> BinaryTree<T> {\n",
|
||
" fn add(&mut self, value: T) {\n",
|
||
" match *self {\n",
|
||
" BinaryTree::Empty => {\n",
|
||
" *self = BinaryTree::NonEmpty(Box::new(TreeNode {\n",
|
||
" element: value,\n",
|
||
" left: BinaryTree::Empty,\n",
|
||
" right: BinaryTree::Empty\n",
|
||
" }));\n",
|
||
" },\n",
|
||
" BinaryTree::NonEmpty(ref mut node) => {\n",
|
||
" if value <= node.element {\n",
|
||
" node.left.add(value);\n",
|
||
" } else {\n",
|
||
" node.right.add(value);\n",
|
||
" }\n",
|
||
" }\n",
|
||
" }\n",
|
||
" }\n",
|
||
"\n",
|
||
" fn preorder<'a>(&'a self, values: &mut Vec<&'a T>) {\n",
|
||
" match *self {\n",
|
||
" BinaryTree::Empty => {},\n",
|
||
" BinaryTree::NonEmpty(ref node) => {\n",
|
||
" values.push(&node.element);\n",
|
||
" node.left.preorder(values);\n",
|
||
" node.right.preorder(values);\n",
|
||
" }\n",
|
||
" }\n",
|
||
" }\n",
|
||
"\n",
|
||
" fn postorder<'a>(&'a self, values: &mut Vec<&'a T>) {\n",
|
||
" match *self {\n",
|
||
" BinaryTree::Empty => {},\n",
|
||
" BinaryTree::NonEmpty(ref node) => {\n",
|
||
" node.left.postorder(values);\n",
|
||
" node.right.postorder(values);\n",
|
||
" values.push(&node.element);\n",
|
||
" }\n",
|
||
" }\n",
|
||
" }\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"[\"Givry\", \"Beaune\", \"Mercurey\", \"Rully\", \"Pommard\"]"
|
||
]
|
||
},
|
||
"execution_count": 4,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"let mut tree = BinaryTree::Empty;\n",
|
||
"\n",
|
||
"{\n",
|
||
" tree.add(\"Givry\".to_string());\n",
|
||
" tree.add(\"Mercurey\".to_string());\n",
|
||
" tree.add(\"Rully\".to_string());\n",
|
||
" tree.add(\"Beaune\".to_string());\n",
|
||
" tree.add(\"Pommard\".to_string());\n",
|
||
"\n",
|
||
" let mut values: Vec<&String> = Vec::new();\n",
|
||
" tree.preorder(&mut values);\n",
|
||
"\n",
|
||
" values\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"[\"Cabernet Sauvignon\", \"Solaris\", \"Pinot Noir\", \"Merlot\", \"Tannat\", \"Chardonnay\"]"
|
||
]
|
||
},
|
||
"execution_count": 6,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"let mut another_tree = BinaryTree::Empty;\n",
|
||
"\n",
|
||
"{\n",
|
||
" another_tree.add(\"Chardonnay\");\n",
|
||
" another_tree.add(\"Tannat\");\n",
|
||
" another_tree.add(\"Cabernet Sauvignon\");\n",
|
||
" another_tree.add(\"Merlot\");\n",
|
||
" another_tree.add(\"Pinot Noir\");\n",
|
||
" another_tree.add(\"Solaris\");\n",
|
||
"\n",
|
||
" let mut values = Vec::new();\n",
|
||
" another_tree.postorder(&mut values);\n",
|
||
" values\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
|
||
}
|