trainings/Rust_2026/rust-bs-2026-09-14/notebooks/04_arrays_vectors_slices.ipynb

2377 lines
60 KiB
Text
Raw 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": [
"# 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>(_: &T) -> String {\n",
" format!(\"{}\", type_name::<T>())\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::<Vec<usize>>()"
]
},
{
"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<T>` 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::<i32>::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<u8> {\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<i32> = (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<String> = [\"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<String>`",
"output_type": "error",
"traceback": [
"\u001b[31m[E0507] Error:\u001b[0m cannot move out of index of `Vec<String>`",
" \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_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 '<unnamed>' 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: <unknown>\n",
" 4: <unknown>\n",
" 5: <unknown>\n",
" 6: <unknown>\n",
" 7: <unknown>\n",
" 8: <unknown>\n",
" 9: <unknown>\n",
" 10: <unknown>\n",
" 11: <unknown>\n",
" 12: <unknown>\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<T>` 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<T>`:\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<String>`, 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<String>`'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<f64> = 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<u8>` 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<T> | 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<T>` 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<Target=str>`, 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<u8>` 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
}