{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Arrays, Vectors & Slices" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Arrays\n", "\n", "* The type `[T; N]` represents an array of `N` values, each of type `T`.\n", "* An array’s size is a constant determined at compile time, and is part of the type; \n", " * you can’t append new elements, \n", " * or shrink an array." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Creating arrays" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 4, 9, 16, 25]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let data: [i32; 6] = [0, 1, 4, 9, 16, 25];\n", "data" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[\"zero\", \"one\", \"two\", \"three\", \"four\", \"five\"]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let words: [&str; 6] = [\"zero\", \"one\", \"two\", \"three\", \"four\", \"five\"];\n", "words" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[1, 2, 3], [4, 5, 6], [7, 8, 9]]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let mut matrix: [[i32; 3]; 3] = [\n", " [1, 2, 3],\n", " [4, 5, 6],\n", " [7, 8, 9],\n", "];\n", "matrix" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Assignment of `[V; N]` fills an array of size `N` with a value `V`" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let mut buffer = [0u8; 32]; // 32-byte buffer, filled with zero bytes\n", "buffer" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Accessing Array Elements\n", "\n", "* Accessing an element of an array can be done using the index operator `[]`\n", "* Indexing is 0-based\n", "* Accessing an element outside the bounds of an array will cause a panic" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"two\"" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let numbers = [\"zero\", \"one\", \"two\", \"three\", \"four\", \"five\"];\n", "numbers[2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Safe indexing can be done using the `get` method of the slice\n", "* The `get` method returns an `Option` type, which is `Some` if the index is in bounds, and `None` if it is out of bounds" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\"two\"\n" ] } ], "source": [ "match numbers.get(2) {\n", " Some(&x) => println!(\"{:?}\", x),\n", " None => println!(\"No such element\"),\n", "};" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Modifying Array Elements" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 42, 3, 4, 665]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let mut numbers = [1, 2, 3, 4, 5];\n", "\n", "numbers[1] = 42;\n", "\n", "if let Some(x) = numbers.get_mut(4) {\n", " *x = 665;\n", "}\n", "\n", "numbers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Iterating Through Arrays\n", "\n", "* `for` loop" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Monday\n", "Tuesday\n", "Wednesday\n", "Thursday\n", "Friday\n", "Saturday\n", "Sunday\n" ] }, { "data": { "text/plain": [ "()" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let days = [\"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\", \"Sunday\"];\n", "\n", "// using a for-in loop\n", "for day in days {\n", " println!(\"{day}\");\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* is using the `iter()` method that creates an iterator over the elements of the array" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Monday\n", "Tuesday\n", "Wednesday\n", "Thursday\n", "Friday\n", "Saturday\n", "Sunday\n" ] }, { "data": { "text/plain": [ "()" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// using a for loop with an iterator\n", "for day in days.iter() {\n", " println!(\"{}\", day);\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* it is also possible to iterate over elements of an array using indexes" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 - Monday\n", "1 - Tuesday\n", "2 - Wednesday\n", "3 - Thursday\n", "4 - Friday\n", "5 - Saturday\n", "6 - Sunday\n" ] }, { "data": { "text/plain": [ "()" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// using a for loop with index\n", "for index in 0..days.len() {\n", " println!(\"{} - {}\", index, days[index])\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `iter_mut()` method that creates an iterator over mutable references to the elements of the array" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2, 4, 6, 8, 10]" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let mut numbers = [1, 2, 3, 4, 5];\n", "\n", "for number in &mut numbers {\n", " *number *= 2;\n", "}\n", "\n", "numbers" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[5, 7, 9, 11, 13]" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "for number in numbers.iter_mut() {\n", " *number += 3;\n", "}\n", "\n", "numbers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Array Length" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let array_size = days.len();\n", "array_size" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Copying Arrays\n", "\n", "* Arrays are copied by value (if the element type is `Copy`)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 2, 3, 4]\n", "[42, 2, 3, 4]\n" ] } ], "source": [ "let mut original: [i32; 4] = [1, 2, 3, 4];\n", "let mut copied: [i32; 4] = original;\n", "\n", "copied[0] = 42;\n", "assert_eq!(&copied, &[42, 2, 3, 4]); \n", "\n", "println!(\"{:?}\", original);\n", "println!(\"{:?}\", copied);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* When elements are not `Copy`, the array is moved" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [], "source": [ "let mut words: [String; 4] = [\"zero\".to_string(), \"one\".to_string(), \"two\".to_string(), \"three\".to_string()];\n", "let target = words; // move words into target" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* To copy an array, you can use the `clone()` method" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[\"zero!!!\", \"one\", \"two\", \"three\"]\n", "[\"zero\", \"one\", \"two\", \"three\"]\n" ] } ], "source": [ "let mut words: [String; 4] = [\"zero\".to_string(), \"one\".to_string(), \"two\".to_string(), \"three\".to_string()];\n", "let backup_words = words.clone();\n", "\n", "words[0].push_str(\"!!!\");\n", "assert_eq!(words[0], \"zero!!!\");\n", "\n", "println!(\"{:?}\", words);\n", "println!(\"{:?}\", backup_words);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### to_owned()\n", "\n", "* The `to_owned()` method can be applied to borrowed array to create a copy of the array" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "original_array = [\"one\", \"two\", \"three\", \"four\"] - [&str; 4]\n", "borrowed_array = [\"one\", \"two\", \"three\", \"four\"] - &[&str; 4]\n", "owned_vector = [\"one\", \"two\", \"three\", \"four\"] - [&str; 4]\n" ] } ], "source": [ "use std::any::{TypeId, type_name};\n", "\n", "fn get_type(_: &T) -> String {\n", " format!(\"{}\", type_name::())\n", "}\n", "\n", "fn main() {\n", " let original_array: [&str; 4] = [\"one\", \"two\", \"three\", \"four\"];\n", " let borrowed_array: &[&str; 4] = &original_array;\n", " let owned_vector = borrowed_array.to_owned();\n", "\n", " println!(\"original_array = {original_array:?} - {}\", get_type(&original_array));\n", " println!(\"borrowed_array = {original_array:?} - {}\", get_type(&borrowed_array));\n", " println!(\"owned_vector = {owned_vector:?} - {}\", get_type(&owned_vector));\n", "}\n", "\n", "main();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Arrays - Example" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[false, false, true, true, false, true, false, true, false, false, false, true, false, true, false, false, false, true, false, true, false, false, false, true, false, false, false, false, false, true, false, true, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, true, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false]" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fn is_prime(n: usize) -> bool {\n", " if n < 2 {\n", " return false;\n", " }\n", " for i in 2..=((n as f64).sqrt() as usize) {\n", " if n % i == 0 {\n", " return false;\n", " }\n", " }\n", " true\n", "}\n", "\n", "const N: usize = 100;\n", "\n", "let mut primes_sieve = [true; N];\n", "primes_sieve[0] = false;\n", "primes_sieve[1] = false;\n", "\n", "for i in 2..10 {\n", " if primes_sieve[i] {\n", " let mut j = i * i;\n", " while j < N {\n", " primes_sieve[j] = false;\n", " j += i;\n", " }\n", " }\n", "}\n", "\n", "primes_sieve" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[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]" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "primes_sieve.iter().enumerate()\n", " .filter_map(|(index, &is_prime)| if is_prime { Some(index) } else { None })\n", " .collect::>()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Multi-dimensionals Arrays" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "_ X O \n", "O X _ \n", "X _ O \n", "\n", "Updated Tic-Tac-Toe Board:\n", "_ X O \n", "O X X \n", "X O O \n" ] } ], "source": [ "fn main() {\n", " let mut tic_tac_toe: [[char; 3]; 3] = [\n", " ['_', 'X', 'O'],\n", " ['O', 'X', '_'],\n", " ['X', '_', 'O']\n", " ];\n", "\n", " print_tic_tac_toe(&tic_tac_toe);\n", "\n", " tic_tac_toe[1][2] = 'X';\n", " tic_tac_toe[2][1] = 'O';\n", "\n", " println!(\"\\nUpdated Tic-Tac-Toe Board:\");\n", " print_tic_tac_toe(&tic_tac_toe);\n", "}\n", "\n", "fn print_tic_tac_toe(board: &[[char; 3]; 3]) {\n", " for row in board {\n", " for cell in row {\n", " print!(\"{cell} \");\n", " }\n", " println!();\n", " }\n", "}\n", "\n", "main();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Vectors" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* A vector `Vec` is a resizable array of elements of type `T`, allocated on the heap." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Creating Vectors" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `Vec::new()` - creates empty vector" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let mut v = Vec::::new();\n", "assert_eq!(v.len(), 0);\n", "\n", "v" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* vector is resized automatically when elements are added" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2, 3, 7, 11]" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.push(2);\n", "v.push(3);\n", "v.push(7);\n", "v.push(11);\n", "\n", "assert_eq!(v.len(), 4);\n", "\n", "v" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `vec!` macro allows to create a vector initialized with given items" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2, 3, 7, 11]" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let mut v = vec![2, 3, 7, 11];\n", "\n", "v" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `vec![V; N]` - creates a vector with size `N` filled with `V`" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fn create_pixel_buffer(rows: usize, cols: usize) -> Vec {\n", " vec![0u8; rows * cols]\n", "}\n", "\n", "create_pixel_buffer(4, 3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Another possibility is to build a vector from the values produced by an iterator:" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let numbers: Vec = (1..=10).collect();\n", "\n", "numbers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Accessing and Modifying Elements" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [], "source": [ "let mut words: Vec = [\"one\".to_string(), \"two\".to_string(), \"three\".to_string()].to_vec();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Indexing" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"one\"" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "words[0]" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[\"one\", \"two and a half\", \"three\"]" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "words[1].push_str(\" and a half\");\n", "words" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* moving elements out of a vector when indexing is not allowed by default\n", "* to move elements, use `drain` or `into_iter`" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "ename": "Error", "evalue": "cannot move out of index of `Vec`", "output_type": "error", "traceback": [ "\u001b[31m[E0507] Error:\u001b[0m cannot move out of index of `Vec`", " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_70: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;249mr\u001b[0m\u001b[38;5;249ms\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;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" ] } ], "source": [ "let first = words[0];\n", "first" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[\"one\", \"two and three quarters\", \"three\"]" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{\n", " let second: &String = &words[1];\n", " let second_mutable: &mut String = &mut words[1];\n", " *second_mutable = \"two and three quarters\".to_string();\n", "}\n", "\n", "words" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Safe Access\n", "* indexing with `[]` operator - panics if index is out of bounds\n", "* `get()` method - safe access returning `Option<&T>`\n", "* `get_mut()` method - safe mutable access returning `Option<&mut T>`\n" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "\n", "thread '' panicked at src\\lib.rs:188:6:\n", "index out of bounds: the len is 3 but the index is 3\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: core::panicking::panic_bounds_check\n", " at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library\\core\\src\\panicking.rs:280\n", " 3: \n", " 4: \n", " 5: \n", " 6: \n", " 7: \n", " 8: \n", " 9: \n", " 10: \n", " 11: \n", " 12: \n", " 13: BaseThreadInitThunk\n", " 14: RtlUserThreadStart\n", "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n" ] } ], "source": [ "words[3]" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "No third word\n" ] }, { "data": { "text/plain": [ "()" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{\n", " let third: Option<&String> = words.get(3);\n", "\n", " match third {\n", " Some(word) => println!(\"{}\", word),\n", " None => println!(\"No third word\")\n", " }\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Length & Capacity\n", "\n", "* A `Vec` consists of three values: \n", " * a pointer to the heap-allocated buffer allocated to hold the elements; \n", " * the number of elements that buffer has the capacity to store; \n", " * and the number it actually contains now (in other words, its length). \n", "* When the buffer has reached its capacity, adding another element to the vector entails allocating a larger buffer, copying the present contents into it, updating the vector’s pointer and capacity to describe the new buffer, and finally freeing the old one." ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [], "source": [ "let mut v = Vec::with_capacity(2);\n", "assert_eq!(v.len(), 0);\n", "assert_eq!(v.capacity(), 2);\n", "\n", "v.push(1);\n", "v.push(2);\n", "assert_eq!(v.len(), 2);\n", "assert_eq!(v.capacity(), 2);\n", "\n", "v.push(3);\n", "assert_eq!(v.len(), 3);\n", "assert_eq!(v.capacity(), 4);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Removing elements" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `pop()` method removes the last element and returns it as `Option`:\n", " * `None` if the vector was already empty, \n", " * or `Some(v)` if its last element had been `v`" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [], "source": [ "let mut guitars = vec![\"fender\", \"gibson\"];\n", "assert_eq!(guitars.pop(), Some(\"gibson\"));\n", "assert_eq!(guitars.pop(), Some(\"fender\"));\n", "assert_eq!(guitars.pop(), None);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `remove(index)` - removes item with a given index" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[\"fender\", \"yamaha\"]" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let mut guitars = vec![\"fender\", \"gibson\", \"yamaha\"];\n", "guitars.remove(1);\n", "guitars" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Iterating over Vectors" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Using `for` loop" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 2 3 4 5 \n" ] } ], "source": [ "let numbers = vec![1, 2, 3, 4, 5];\n", "\n", "for number in numbers {\n", " print!(\"{} \", number);\n", "}\n", "\n", "println!();" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "ename": "Error", "evalue": "borrow of moved value: `words`", "output_type": "error", "traceback": [ "\u001b[31m[E0382] Error:\u001b[0m borrow of moved value: `words`", " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_80: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;100mw\u001b[0m\u001b[38;5;100mo\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100md\u001b[0m\u001b[38;5;100ms\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;249me\u001b[0m\u001b[38;5;249mc\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;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m\"\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;249m\"\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m\"\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;249m\"\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m\"\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;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 move occurs because `words` has type `Vec`, which does not implement the `Copy` trait", " \u001b[38;5;240m │\u001b[0m ", " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\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;249mi\u001b[0m\u001b[38;5;249mn\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;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;54m─\u001b[0m\u001b[38;5;54m─\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 help: consider iterating over a slice of the `Vec`'s content to avoid moving into the `for` loop: `&`", " \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 `words` moved due to this implicit call to `.into_iter()`", " \u001b[38;5;240m │\u001b[0m ", " \u001b[38;5;240m │\u001b[0m \u001b[38;5;115mNote\u001b[0m: note: `into_iter` takes ownership of the receiver `self`, which moves `words`", "\u001b[38;5;246m───╯\u001b[0m" ] } ], "source": [ "let words = vec![\"one\".to_string(), \"two\".to_string(), \"three\".to_string()];\n", "\n", "for word in words {\n", " println!(\"{}\", word);\n", "}\n", "\n", "words" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "one\n", "two\n", "three\n" ] }, { "data": { "text/plain": [ "[\"one\", \"two\", \"three\"]" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let words = vec![\"one\".to_string(), \"two\".to_string(), \"three\".to_string()];\n", "\n", "for word in words.iter() {\n", " println!(\"{}\", word);\n", "}\n", "\n", "words" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Using `iter_mut()` for Mutable Iteration" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `iter_mut()` creates an iterator over mutable references to the elements of the vector" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[11, 12, 13, 14, 15]" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let mut numbers = vec![1, 2, 3, 4, 5];\n", "\n", "for n in numbers.iter_mut() {\n", " *n += 10;\n", "}\n", "\n", "numbers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* the same can be achieved using iteration over mutable slice - `&mut collection`" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[33, 36, 39, 42, 45]" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "for n in &mut numbers {\n", " *n *= 3;\n", "}\n", "\n", "numbers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Using `enumerate` for Index & Value" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Index: 0 - fender\n", "Index: 1 - gibson\n", "Index: 2 - yamaha\n" ] }, { "data": { "text/plain": [ "()" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let mut guitars = vec![\"fender\", \"gibson\", \"yamaha\"];\n", "\n", "for (index, guitar) in guitars.iter().enumerate() {\n", " println!(\"Index: {} - {}\", index, guitar);\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Slices" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* A **slice**, written `[T]` without specifying the length, is a region of an array or vector. \n", "* Since a slice can be any length, slices can’t be stored directly in variables or passed as function arguments. **Slices are always passed by reference**.\n", "* A reference to a slice is a **fat pointer**: a two-word value comprising a pointer to the slice’s first element, and the number of elements in the slice.\n", "* A reference to a slice is a non-owning pointer to several values" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "sv: 0 0.707 1 0.707 \n", "sa: 0 -0.707 -1 -0.707 \n" ] } ], "source": [ "fn main() {\n", " let v: Vec = vec![0.0, 0.707, 1.0, 0.707];\n", " let a: [f64; 4] = [0.0, -0.707, -1.0, -0.707];\n", "\n", " let sv: &[f64] = &v;\n", " let sa: &[f64] = &a;\n", "\n", " fn print(data: &[f64], desc: &str) {\n", " print!(\"{desc}: \");\n", " for item in data {\n", " print!(\"{} \", item);\n", " }\n", " println!();\n", " }\n", "\n", " print(sv, \"sv\");\n", " print(sa, \"sa\");\n", "}\n", "\n", "main();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![image](./images/rust-slices.png)" ] }, { "cell_type": "markdown", "metadata": { "vscode": { "languageId": "rust" } }, "source": [ "### Creating slices" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "slice_all: [ 1 2 3 4 5 6 7 8 9 10 ]\n", "slice_first_five: [ 1 2 3 4 5 ]\n", "slice_last_five: [ 6 7 8 9 10 ]\n", "data: [ 1 2 3 4 0 0 0 8 9 10 ]\n" ] } ], "source": [ "// Function to print elements of a slice with a description\n", "fn print(data: &[i32], desc: &str) {\n", " print!(\"{desc}: [ \");\n", " for item in data {\n", " print!(\"{} \", item);\n", " }\n", " println!(\"]\");\n", "}\n", "\n", "// Function to set all elements of a mutable slice to zero\n", "fn zero(data: &mut [i32]) {\n", " for item in data {\n", " *item = 0;\n", " }\n", "}\n", "\n", "fn main() {\n", " let mut data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n", "\n", " let slice_all: &[i32] = &data[..];\n", " print(slice_all, \"slice_all\");\n", "\n", " let slice_first_five: &[i32] = &data[0..5];\n", " print(slice_first_five, \"slice_first_five\");\n", "\n", " let slice_last_five: &[i32] = &data[5..];\n", " print(slice_last_five, \"slice_last_five\");\n", "\n", " let slice_middle_three: &mut [i32] = &mut data[4..7];\n", " zero(slice_middle_three);\n", " print(&data, \"data\");\n", "}\n", "\n", "main();" ] }, { "cell_type": "code", "execution_count": 102, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "working_days: [\"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\"]\n", "weekend: [\"Saturday\", \"Sunday\"]\n", "days: [\"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\", \"Sunday\"]\n" ] } ], "source": [ "fn main() {\n", " let days = [\"Monday\".to_string(), \"Tuesday\".to_string(), \"Wednesday\".to_string(), \"Thursday\".to_string(), \"Friday\".to_string(), \"Saturday\".to_string(), \"Sunday\".to_string()];\n", "\n", " let working_days = &days[..5];\n", " println!(\"working_days: {:?}\", working_days);\n", "\n", " let weekend: &[String] = &days[5..];\n", " println!(\"weekend: {:?}\", weekend);\n", "\n", " println!(\"days: {:?}\", days);\n", "}\n", "\n", "main();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Accessing Slice Elements" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "20\n", "30\n", "40\n" ] } ], "source": [ "fn main() {\n", " let data: [i32; 5] = [10, 20, 30, 40, 50];\n", " let slice: &[i32] = &data[1..4];\n", "\n", " // Accessing elements by index\n", " let second_element = slice[0];\n", " assert!(second_element == 20);\n", "\n", " // Accessing elements by get method\n", " let third_element: Option<&i32> = slice.get(2);\n", " assert!(third_element == Some(&40));\n", "\n", " // Accessing elements by iteration\n", " for item in slice {\n", " println!(\"{}\", item);\n", " }\n", "}\n", "\n", "main();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Modifing Slice Elements" ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n", "data: [-1, -2, -3, -4, -5, 6, 7, 8, 9, 10]\n" ] } ], "source": [ "fn negate(data: &mut[i32]) {\n", " for item in data {\n", " *item = -*item;\n", " }\n", "}\n", "\n", "\n", "fn main() {\n", " let mut data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n", " println!(\"data: {:?}\", data);\n", "\n", " let n = data.len()/2;\n", " negate(&mut data[0..n]);\n", " \n", " println!(\"data: {:?}\", data);\n", "}\n", "\n", "main();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## String Types" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### String Literals" ] }, { "cell_type": "code", "execution_count": 106, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "And now \"something\" completely different...\n" ] } ], "source": [ "let text: &str = \"And now \\\"something\\\" completely different...\\n\";\n", "\n", "print!(\"{text}\");" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* raw string literals - `r\"...\"`" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [], "source": [ "let default_win_install_path: &str = r\"C:\\Program Files\\Gorillas\";\n", "\n", "let regex_pattern: &str = r\"\\d+(\\.\\d+)*\";" ] }, { "cell_type": "code", "execution_count": 108, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", " This raw string started with 'r###\"'.\n", " Therefore it does not end until we reach a quote mark ('\"')\n", " followed immediately by three pound signs ('###'):\n", "\n" ] } ], "source": [ "println!(r###\"\n", " This raw string started with 'r###\"'.\n", " Therefore it does not end until we reach a quote mark ('\"')\n", " followed immediately by three pound signs ('###'):\n", "\"###);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Byte Strings" ] }, { "cell_type": "markdown", "metadata": { "vscode": { "languageId": "rust" } }, "source": [ "* A string literal with the `b` prefix is a **byte string**. \n", "* Raw byte strings start with `br\"`\n", "* Such a string is a slice of `u8` values—that is, bytes—rather than Unicode text:" ] }, { "cell_type": "code", "execution_count": 109, "metadata": {}, "outputs": [], "source": [ "let method: &[u8; 3] = b\"GET\";\n", "assert_eq!(method, &[b'G', b'E', b'T']);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Strings in Memory" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Rust strings are sequences of Unicode characters**, but they are not stored in memory as arrays of chars. \n", "\n", "Instead, they are stored using UTF-8, a variable-width encoding. Each ASCII character in a string is stored in one byte. Other characters take up multiple bytes." ] }, { "cell_type": "code", "execution_count": 110, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "()" ] }, "execution_count": 110, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{\n", " let noodles = \"noodles\".to_string();\n", " let oodles = &noodles[1..];\n", " let poodles = \"ಠ_ಠ\";\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `&str`\n", "\n", "* A `&str` (pronounced “stir” or “string slice”) is a reference to a run of UTF-8 text owned by someone else: it “borrows” the text\n", "* It is a **fat pointer**, containing both the address of the actual data and its length - `&str` is nothing more than a `&[u8]` that is guaranteed to hold well-formed UTF-8\n", "* A string literal is a `&str` that refers to preallocated text, typically stored in read-only memory along with the program’s machine code\n", "* It is impossible to modify a `&str`:" ] }, { "cell_type": "code", "execution_count": 113, "metadata": {}, "outputs": [ { "ename": "Error", "evalue": "the type `str` cannot be indexed by `{integer}`", "output_type": "error", "traceback": [ "\u001b[31m[E0277] Error:\u001b[0m the type `str` cannot be indexed by `{integer}`", " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_113:1:1 \u001b[38;5;246m]\u001b[0m", " \u001b[38;5;246m│\u001b[0m", " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m[\u001b[0m\u001b[38;5;54m0\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;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;240m │\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m string indices are ranges of `usize`", "\u001b[38;5;246m───╯\u001b[0m" ] }, { "ename": "Error", "evalue": "no method named `push` found for reference `&str` in the current scope", "output_type": "error", "traceback": [ "\u001b[31m[E0599] Error:\u001b[0m no method named `push` found for reference `&str` in the current scope", " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_113:1:1 \u001b[38;5;246m]\u001b[0m", " \u001b[38;5;246m│\u001b[0m", " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mh\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m'\u001b[0m\u001b[38;5;249m\\\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;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;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 method not found in `&str`", "\u001b[38;5;246m───╯\u001b[0m" ] } ], "source": [ "let mut text = \"hello\";\n", "text[0] = 'H';\n", "text.push('\\n');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* A `String` or `&str`’s .`len()` method returns its length. The length is measured in bytes, not characters:" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [], "source": [ "assert_eq!(\"ಠ_ಠ\".len(), 7);\n", "assert_eq!(\"ಠ_ಠ\".chars().count(), 3);\n", "\n", "\n", "let first_char = \"ಠ_ಠ\".chars().nth(0).unwrap();\n", "assert_eq!(first_char, 'ಠ');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `String`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* A `String` has a resizable buffer holding UTF-8 text. \n", "* The buffer is allocated on the heap, so it can resize its buffer as needed or requested. \n", "* You can think of a `String` as a `Vec` that is guaranteed to hold well-formed UTF-8; in fact, this is how `String` is implemented." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Creating Strings" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Creating an empty `String` with `String::new()`" ] }, { "cell_type": "code", "execution_count": 121, "metadata": {}, "outputs": [], "source": [ "let empty_string = String::new();\n", "assert_eq!(empty_string.len(), 0);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Converting &str to String with `to_string()` or `String::from()` or `into()`" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "let error_message: String = \"too many arguments\".to_string();\n", "let warning_message: String = String::from(\"deprecated function\");\n", "let info_message: String = \"operation successful\".into();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Using `format!` to create formatted strings" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "let location = format!(\"{}°{:02}′{:02}″N\", 24, 5, 23);\n", "assert_eq!(location, \"24°05′23″N\".to_string());" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Concatenating vector of strings with `concat()` or `join()`" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"venividivici\"" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let words: Vec<&str> = vec![\"veni\", \"vidi\", \"vici\"];\n", "words.concat()" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"veni, vidi, vici\"" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "words.join(\", \")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* If you have a vector of UTF-8 bytes, you can create a `String` from it with the from_utf8 method:" ] }, { "cell_type": "code", "execution_count": 120, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "💖\n" ] } ], "source": [ "// some bytes, in a vector\n", "let sparkle_heart = vec![240, 159, 146, 150];\n", "\n", "// We know these bytes are valid, so we'll use `unwrap()`.\n", "let sparkle_heart = String::from_utf8(sparkle_heart).unwrap();\n", "\n", "assert_eq!(\"💖\", sparkle_heart);\n", "\n", "println!(\"{}\", sparkle_heart);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### String like Vec" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"one!\\ntwo!\\nthree!\\n\"" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let mut text = \"one\".to_string();\n", "\n", "text.push('!');\n", "text.push('\\n');\n", "text.push_str(\"two!\\n\");\n", "text.push_str(\"three!\\n\");\n", "\n", "text" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"one!\\ntwo!\\nthree!\"" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "text.pop();\n", "text" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "| | Vec | String |\n", "| ------------------------------------------------ | ------------------- | ------------------- |\n", "| Automatically frees buffers | Yes | Yes |\n", "| Growable | Yes | Yes |\n", "| `::new()` and `::with_capacity()` static methods | Yes | Yes |\n", "| `.reserve()` and `.capacity()` methods | Yes | Yes |\n", "| `.push()` and `.pop()` methods | Yes | Yes |\n", "| Range syntax `v[start..stop]` | Yes, returns `&[T]` | Yes, returns `&str` |\n", "| Automatic conversion | `&Vec` to `&[T]` | `&String` to `&str` |\n", "| Inherits methods | From `&[T]` | From `&str` |" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Comparing Strings\n", "\n", "* Strings support the `==` and `!=` operators" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [], "source": [ "assert!(\"ONE\".to_lowercase() == \"one\");" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Deref\n", "\n", "* String implements `Deref`, and so inherits all methods `str`\n", "* You can use string slices (`&str`) and `String` interchangeably in many cases\n", "* You can also pass a `&String` where a `&str` is expected" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\"Rusty Cage\"\n" ] } ], "source": [ "fn takes_str(text: &str) {\n", " println!(\"{:?}\", text);\n", "}\n", "\n", "let s = String::from(\"Rusty Cage\");\n", "takes_str(&s);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Using Strings" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "veni\n", "vidi\n", "vici\n" ] }, { "data": { "text/plain": [ "()" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "assert!(\"peanut\".contains(\"nut\"));\n", "assert_eq!(\"ಠ_ಠ\".replace(\"ಠ\", \"■\"), \"■_■\");\n", "assert_eq!(\" clean\\n\".trim(), \"clean\");\n", "\n", "for word in \"veni, vidi, vici\".split(\", \") {\n", " assert!(word.starts_with(\"v\"));\n", " println!(\"{word}\");\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Other String Like Types\n", "\n", "Rust’s solution is to offer a few string-like types for these situations:\n", "\n", "* Stick to `String` and `&str` for Unicode text.\n", "* When working with filenames, use `std::path::PathBuf` and `&Path` instead.\n", "* When working with binary data that isn’t character data at all, use `Vec` and `&[u8]`.\n", "* When working with environment variable names and command-line arguments in the native form presented by the operating system, use `OsString` and `&OsStr`.\n", "* When interoperating with C libraries that use null-terminated strings, use `std::ffi::CString` and `&CStr`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Real-World Examples" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### String Manipulation" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "File extension: txt\n" ] } ], "source": [ "let filename = \"example.txt\";\n", "let extension: &str = &filename[filename.len() - 3..];\n", "println!(\"File extension: {}\", extension);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Data Processing" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Average: 2.62\n" ] } ], "source": [ "fn calculate_average(slice: &[f64]) -> f64 {\n", " let sum: f64 = slice.iter().sum();\n", " sum / slice.len() as f64\n", "}\n", "\n", "fn main() {\n", " let data: [f64; 6] = [2.5, 3.0, 1.5, 4.0, 2.0, 3.5];\n", " let slice: &[f64] = &data[1..5];\n", " let average = calculate_average(slice);\n", " println!(\"Average: {:.2}\", average);\n", "}\n", "\n", "main();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Text Tokenization" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Words: [\"Rust\", \"is\", \"a\", \"systems\", \"programming\", \"language.\"]\n" ] } ], "source": [ "fn tokenize_sentence(sentence: &str) -> Vec<&str> {\n", " sentence.split_whitespace().collect()\n", "}\n", "\n", "let text: &str = \"Rust is a systems programming language.\";\n", "let words = tokenize_sentence(text);\n", "println!(\"Words: {:?}\", words);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Binary Data Handling" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "fn parse_header(header_data: &[u8]) {\n", " // Parse the binary header data here\n", "}\n", "\n", "fn main() {\n", " let binary_data: [u8; 16] = [0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x20, 0x52, 0x75, 0x73, 0x74, 0x21, 0x00, 0x00, 0x0A, 0x0D];\n", " let header_slice: &[u8] = &binary_data[0..8];\n", " parse_header(header_slice);\n", "}\n", "\n", "main();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Memory mapping" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Read 30 bytes: [84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 102, 105, 108, 101, 32, 119, 105, 116, 104, 32, 115, 111, 109, 101, 32, 116, 101, 120, 116, 46]\n" ] } ], "source": [ "use std::fs::File;\n", "use std::io::{self, Read};\n", "\n", "fn main() -> io::Result<()> {\n", " let mut file = File::open(\"file.txt\")?;\n", " let mut buffer = [0; 1024];\n", "\n", " // read a portion of the file to the buffer\n", " let bytes_read = file.read(&mut buffer)?;\n", "\n", " // process the buffer as a slice\n", " let slice = &buffer[0..bytes_read];\n", " println!(\"Read {} bytes: {:?}\", bytes_read, slice);\n", "\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 }