trainings/Rust_2026/rust-bs-2026-09-14/notebooks/07_enums_patterns.ipynb

1784 lines
48 KiB
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"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
}