From d163a72e0f5bc2caf91397f3d784bec0c4c6c4ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Doubravsk=C3=BD?= Date: Sun, 18 Oct 2026 11:46:43 +0200 Subject: [PATCH] Set up Cargo workspace with hello and variables examples --- CHANGELOG.md | 13 + Cargo.lock | 11 + Cargo.toml | 3 + crates/01-hello/Cargo.toml | 6 + crates/01-hello/src/main.rs | 3 + crates/02-variables/Cargo.toml | 6 + crates/02-variables/src/main.rs | 484 ++++++++++++++++++++++++++++++++ 7 files changed, 526 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 crates/01-hello/Cargo.toml create mode 100644 crates/01-hello/src/main.rs create mode 100644 crates/02-variables/Cargo.toml create mode 100644 crates/02-variables/src/main.rs diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a2daede --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). + +## [Unreleased] + +### Added + +- Cargo workspace (resolver 3) with all crates under `crates/*` picked up automatically. +- `crates/01-hello` (package `hello`): minimal binary crate. +- `crates/02-variables` (package `variables`): annotated showcase (comments in Czech) of working with variables in Rust: `let`/`mut`, shadowing, types and literals, overflow handling, casting, `const`/`static`, tuples/arrays/`Vec`, destructuring, deferred initialization, block/`if`/`match`/`loop` expressions, scope, move vs. copy, references, `&str` vs. `String`, `Option`/`if let` and `let-else`. diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4a980ed --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,11 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "hello" +version = "0.1.0" + +[[package]] +name = "variables" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a32b8d7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +resolver = "3" +members = ["crates/*"] \ No newline at end of file diff --git a/crates/01-hello/Cargo.toml b/crates/01-hello/Cargo.toml new file mode 100644 index 0000000..f6f3649 --- /dev/null +++ b/crates/01-hello/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/crates/01-hello/src/main.rs b/crates/01-hello/src/main.rs new file mode 100644 index 0000000..8a426b3 --- /dev/null +++ b/crates/01-hello/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Nazdar!"); +} diff --git a/crates/02-variables/Cargo.toml b/crates/02-variables/Cargo.toml new file mode 100644 index 0000000..c093eb6 --- /dev/null +++ b/crates/02-variables/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "variables" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/crates/02-variables/src/main.rs b/crates/02-variables/src/main.rs new file mode 100644 index 0000000..f8e10af --- /dev/null +++ b/crates/02-variables/src/main.rs @@ -0,0 +1,484 @@ +// Ukázka práce s proměnnými v Rustu. +// Každá sekce je ve vlastní funkci, main() je volá postupně. + +// --------------------------------------------------------------------------- +// Konstanty a statické proměnné (definují se mimo funkce, globálně) +// --------------------------------------------------------------------------- + +// `const` – hodnota známá při kompilaci, překladač ji vloží všude, kde se použije. +// Typ musí být uveden vždy. Název podle konvence VELKÝMI_PÍSMENY. +const MAX_BODU: u32 = 100; + +// Konstanta může být vypočtena z jiných konstant (výpočet proběhne při kompilaci). +const SEKUND_ZA_DEN: u32 = 24 * 60 * 60; + +// `static` – jedna pevná adresa v paměti po celou dobu běhu programu. +// Na rozdíl od `const` se nekopíruje, existuje právě jednou. +static NAZEV_PROGRAMU: &str = "Rust Playground"; + +fn main() { + zakladni_promenne(); + mutabilita(); + shadowing(); + typy_a_anotace(); + cisla_a_literaly(); + preteceni(); + pretypovani(); + konstanty_a_static(); + tuple_a_pole(); + destrukturalizace(); + odlozena_inicializace(); + bloky_jako_vyrazy(); + rozsah_platnosti(); + vlastnictvi_move_a_copy(); + reference(); + retezce(); + option_a_if_let(); + let_else(); + nepouzite_promenne(); +} + +// --------------------------------------------------------------------------- +// 1. Základní deklarace +// --------------------------------------------------------------------------- +fn zakladni_promenne() { + println!("\n== 1. Základní proměnné =="); + + // `let` vytvoří proměnnou. Ve výchozím stavu je NEMĚNNÁ (immutable). + let x = 5; + println!("x = {x}"); + + // x = 6; // CHYBA: cannot assign twice to immutable variable + + // Typ si překladač odvodí sám (type inference) – tady i32 (výchozí pro celá čísla). + let y = 2.5; // f64 (výchozí pro desetinná čísla) + println!("y = {y}"); +} + +// --------------------------------------------------------------------------- +// 2. Měnitelné proměnné +// --------------------------------------------------------------------------- +fn mutabilita() { + println!("\n== 2. Mutabilita =="); + + // `mut` povolí změnu hodnoty. Typ se ale měnit nesmí. + let mut pocitadlo = 0; + println!("pocitadlo = {pocitadlo}"); + + pocitadlo += 1; + pocitadlo *= 10; + println!("pocitadlo po změnách = {pocitadlo}"); + + // pocitadlo = "text"; // CHYBA: mismatched types – typ je pevně i32 +} + +// --------------------------------------------------------------------------- +// 3. Shadowing (zastínění) +// --------------------------------------------------------------------------- +fn shadowing() { + println!("\n== 3. Shadowing =="); + + // Novým `let` se stejným jménem vytvoříme NOVOU proměnnou, která tu starou zastíní. + let hodnota = 5; + let hodnota = hodnota + 1; // nová proměnná, stará už není dostupná + println!("hodnota = {hodnota}"); + + // Shadowing umí (na rozdíl od `mut`) změnit i typ. + let mezery = " "; // &str + let mezery = mezery.len(); // usize + println!("počet mezer = {mezery}"); + + // Shadowing ve vnořeném bloku platí jen uvnitř bloku. + let z = 1; + { + let z = z * 100; + println!("z uvnitř bloku = {z}"); + } + println!("z mimo blok = {z}"); +} + +// --------------------------------------------------------------------------- +// 4. Explicitní typy +// --------------------------------------------------------------------------- +fn typy_a_anotace() { + println!("\n== 4. Typy a anotace =="); + + // Typ lze uvést za dvojtečku. + let a: i64 = 42; + let b: f32 = 2.5; + let c: bool = true; + let d: char = 'ř'; // char je Unicode znak (4 bajty), píše se v jednoduchých uvozovkách + let e: () = (); // "unit" – prázdná hodnota, obdoba void + + println!("a={a}, b={b}, c={c}, d={d}, e={e:?}"); + + // Někdy je anotace nutná, protože překladač nemá z čeho typ odvodit. + let cislo: u8 = "200".parse().expect("není číslo"); + // Alternativa: typ zadaný přes "turbofish" ::<> + let cislo2 = "300".parse::().expect("není číslo"); + println!("cislo={cislo}, cislo2={cislo2}"); +} + +// --------------------------------------------------------------------------- +// 5. Číselné typy a zápisy literálů +// --------------------------------------------------------------------------- +fn cisla_a_literaly() { + println!("\n== 5. Čísla a literály =="); + + // Celá čísla se znaménkem: i8, i16, i32, i64, i128, isize + // Bez znaménka: u8, u16, u32, u64, u128, usize + // isize/usize mají velikost podle architektury (na 64bit = 64 bitů), usize se používá pro indexy. + println!("i8: {} až {}", i8::MIN, i8::MAX); + println!("u64: {} až {}", u64::MIN, u64::MAX); + + // Různé zápisy literálů: + let desitkove = 1_000_000; // podtržítka pro čitelnost + let hex = 0xFF; + let oktal = 0o77; + let binarni = 0b1010_1010; + let bajt = b'A'; // u8, jen ASCII + let s_priponou = 42u8; // typ přímo v literálu + let float = 1e3; // 1000.0 (f64) + + println!("{desitkove} {hex} {oktal} {binarni} {bajt} {s_priponou} {float}"); +} + +// --------------------------------------------------------------------------- +// 6. Přetečení +// --------------------------------------------------------------------------- +fn preteceni() { + println!("\n== 6. Přetečení =="); + + let x: u8 = 250; + + // let y = x + 10; // v debug režimu PANIKA (overflow), v release se tiše "přetočí" + // Proto existují metody, kterými chování určíš explicitně: + println!("wrapping_add: {}", x.wrapping_add(10)); // 4 – přetočí se + println!("checked_add: {:?}", x.checked_add(10)); // None – přetečení + println!("saturating_add: {}", x.saturating_add(10)); // 255 – zastaví se na max + println!("overflowing_add:{:?}", x.overflowing_add(10)); // (4, true) +} + +// --------------------------------------------------------------------------- +// 7. Přetypování +// --------------------------------------------------------------------------- +fn pretypovani() { + println!("\n== 7. Přetypování =="); + + // Rust NIKDY nepřetypovává čísla automaticky, musí se to napsat. + let a: i32 = 10; + let b: i64 = 20; + // let c = a + b; // CHYBA: mismatched types + + // `as` – rychlé, ale může tiše ořezat hodnotu + let c = a as i64 + b; + let orez = 300_i32 as u8; // 300 se nevejde do u8 -> 44 + let desetinne = 3.99_f64 as i32; // useknutí desetinné části -> 3 + println!("c={c}, orez={orez}, desetinne={desetinne}"); + + // `From`/`Into` – bezpečný převod, existuje jen tam, kde nemůže dojít ke ztrátě + let velke: i64 = i64::from(a); + let velke2: i64 = a.into(); + println!("velke={velke}, velke2={velke2}"); + + // `TryFrom`/`TryInto` – převod, který může selhat, vrací Result + let vysledek: Result = u8::try_from(300_i32); + println!("try_from(300) -> {vysledek:?}"); +} + +// --------------------------------------------------------------------------- +// 8. const a static +// --------------------------------------------------------------------------- +fn konstanty_a_static() { + println!("\n== 8. const a static =="); + + println!("MAX_BODU = {MAX_BODU}"); + println!("SEKUND_ZA_DEN = {SEKUND_ZA_DEN}"); + println!("NAZEV_PROGRAMU = {NAZEV_PROGRAMU}"); + + // Konstantu lze definovat i lokálně uvnitř funkce. + const LOKALNI: f64 = 9.81; + println!("LOKALNI = {LOKALNI}"); + + // Pozn.: existuje i `static mut`, ale přístup k němu vyžaduje `unsafe` + // a v edici 2024 je silně omezen. Pro sdílený měnitelný stav se používají + // atomické typy (std::sync::atomic) nebo Mutex. +} + +// --------------------------------------------------------------------------- +// 9. Složené typy: tuple a pole +// --------------------------------------------------------------------------- +fn tuple_a_pole() { + println!("\n== 9. Tuple a pole =="); + + // Tuple – pevný počet prvků, každý může mít jiný typ. + let osoba: (&str, u32, bool) = ("Honza", 30, true); + println!("jméno={}, věk={}, aktivní={}", osoba.0, osoba.1, osoba.2); + + // Pole – pevná délka (součást typu), všechny prvky stejného typu, leží na zásobníku. + let cisla: [i32; 5] = [1, 2, 3, 4, 5]; + let nuly = [0; 3]; // [0, 0, 0] – 3× hodnota 0 + println!("cisla={cisla:?}, první={}, délka={}", cisla[0], cisla.len()); + println!("nuly={nuly:?}"); + + // Měnitelné pole + let mut pole = [10, 20, 30]; + pole[1] = 99; + println!("pole={pole:?}"); + + // Vec – dynamické pole na haldě, může růst. + let mut v = vec![1, 2, 3]; + v.push(4); + println!("vec={v:?}"); +} + +// --------------------------------------------------------------------------- +// 10. Destrukturalizace (rozbalení do více proměnných) +// --------------------------------------------------------------------------- +fn destrukturalizace() { + println!("\n== 10. Destrukturalizace =="); + + // Tuple + let (x, y, z) = (1, 2.0, 'a'); + println!("x={x}, y={y}, z={z}"); + + // `_` ignoruje hodnotu + let (prvni, _, treti) = (10, 20, 30); + println!("prvni={prvni}, treti={treti}"); + + // Pole + let [a, b, c] = [1, 2, 3]; + println!("a={a}, b={b}, c={c}"); + + // `..` ignoruje zbytek + let [zacatek, .., konec] = [1, 2, 3, 4, 5]; + println!("zacatek={zacatek}, konec={konec}"); + + // Struktura + struct Bod { + x: i32, + y: i32, + } + let bod = Bod { x: 3, y: 7 }; + let Bod { x: bx, y: by } = bod; // přejmenování + println!("bx={bx}, by={by}"); + + // Přiřazení s destrukturalizací do existujících proměnných (prohození hodnot) + let mut m = 1; + let mut n = 2; + (m, n) = (n, m); + println!("m={m}, n={n}"); +} + +// --------------------------------------------------------------------------- +// 11. Odložená inicializace +// --------------------------------------------------------------------------- +// Clippy by tu radši viděl `let vysledek = if ...` (viz sekce 12), tady jde ale o ukázku. +#[allow(clippy::needless_late_init)] +fn odlozena_inicializace() { + println!("\n== 11. Odložená inicializace =="); + + // Proměnnou lze deklarovat bez hodnoty a přiřadit ji později – ale jen JEDNOU + // a překladač hlídá, že se nepoužije dřív, než má hodnotu. + let vysledek: &str; + let teplota = 25; + + if teplota > 20 { + vysledek = "teplo"; + } else { + vysledek = "zima"; + } + println!("je {vysledek}"); +} + +// --------------------------------------------------------------------------- +// 12. Bloky a if jako výrazy +// --------------------------------------------------------------------------- +fn bloky_jako_vyrazy() { + println!("\n== 12. Bloky jako výrazy =="); + + // Blok { } vrací hodnotu posledního výrazu (bez středníku!). + let y = { + let x = 3; + x * x + 1 // bez středníku = návratová hodnota bloku + }; + println!("y = {y}"); + + // `if` je výraz – idiomatičtější varianta příkladu z předchozí sekce. + let teplota = 15; + let popis = if teplota > 20 { "teplo" } else { "zima" }; + println!("je {popis}"); + + // `match` je také výraz. + let znamka = 2; + let slovy = match znamka { + 1 => "výborně", + 2 => "chvalitebně", + 3 => "dobře", + _ => "jiné", + }; + println!("známka {znamka} = {slovy}"); + + // `loop` umí vrátit hodnotu přes `break`. + let mut i = 0; + let prvni_nad_50 = loop { + i += 7; + if i > 50 { + break i; + } + }; + println!("první násobek 7 nad 50 = {prvni_nad_50}"); +} + +// --------------------------------------------------------------------------- +// 13. Rozsah platnosti (scope) +// --------------------------------------------------------------------------- +fn rozsah_platnosti() { + println!("\n== 13. Rozsah platnosti =="); + + let venku = "venku"; + { + let uvnitr = "uvnitř"; + println!("{venku} i {uvnitr} jsou dostupné"); + } // zde `uvnitr` zaniká (a uvolní se jeho paměť) + // println!("{uvnitr}"); // CHYBA: cannot find value `uvnitr` in this scope + println!("{venku} je stále dostupné"); +} + +// --------------------------------------------------------------------------- +// 14. Vlastnictví: move vs. copy +// --------------------------------------------------------------------------- +fn vlastnictvi_move_a_copy() { + println!("\n== 14. Move vs. copy =="); + + // Jednoduché typy (čísla, bool, char, tuple/pole z nich) implementují `Copy` + // – přiřazení vytvoří kopii a obě proměnné jsou dál platné. + let a = 5; + let b = a; + println!("a={a}, b={b}"); + + // Typy na haldě (String, Vec, ...) se při přiřazení PŘESOUVAJÍ (move). + let s1 = String::from("ahoj"); + let s2 = s1; // vlastnictví přešlo na s2 + // println!("{s1}"); // CHYBA: borrow of moved value: `s1` + println!("s2={s2}"); + + // Pokud chceme skutečnou kopii, musíme explicitně zavolat `.clone()`. + let s3 = s2.clone(); + println!("s2={s2}, s3={s3}"); +} + +// --------------------------------------------------------------------------- +// 15. Reference (půjčování) +// --------------------------------------------------------------------------- +fn reference() { + println!("\n== 15. Reference =="); + + let text = String::from("Rust"); + + // `&` – neměnná reference. Těch může být libovolně mnoho současně. + let r1 = &text; + let r2 = &text; + println!("r1={r1}, r2={r2}, délka={}", delka(&text)); + + // `&mut` – měnitelná reference. Proměnná musí být `mut` + // a v jednu chvíli smí existovat JEN JEDNA (a žádná neměnná zároveň). + let mut cislo = 10; + { + let r = &mut cislo; + *r += 5; // `*` = dereference, přístup k hodnotě, na kterou reference ukazuje + } + println!("cislo={cislo}"); + + let mut seznam = vec![1, 2]; + pridej(&mut seznam, 3); + println!("seznam={seznam:?}"); +} + +// Parametr je `&str`, ne `&String` – funkce pak přijme oba typy +// (`&String` se na `&str` převede automaticky, tzv. deref coercion). +fn delka(s: &str) -> usize { + s.len() // funkce si hodnotu jen půjčila, vlastnictví zůstává volajícímu +} + +fn pridej(v: &mut Vec, hodnota: i32) { + v.push(hodnota); +} + +// --------------------------------------------------------------------------- +// 16. Řetězce: &str vs String +// --------------------------------------------------------------------------- +fn retezce() { + println!("\n== 16. Řetězce =="); + + // &str – "řez" řetězce, neměnný, často přímo v binárce (literály). + let pozdrav: &str = "Ahoj"; + + // String – vlastněný, měnitelný řetězec na haldě. + let mut jmeno = String::from("Hon"); + jmeno.push_str("za"); + jmeno.push('!'); + + // Převody + let z_str: String = pozdrav.to_string(); + let jako_str: &str = &jmeno; + + // Spojování + let veta = format!("{pozdrav}, {jmeno}"); + println!("{veta} | {z_str} | {jako_str}"); + + // Raw string – bez escapování + let cesta = r"C:\Users\honza"; + println!("{cesta}"); +} + +// --------------------------------------------------------------------------- +// 17. Option a if let +// --------------------------------------------------------------------------- +fn option_a_if_let() { + println!("\n== 17. Option a if let =="); + + // Rust nemá null. Chybějící hodnota se vyjadřuje typem Option. + let neco: Option = Some(42); + let nic: Option = "abc".parse().ok(); // parsování selže -> None + + // `if let` – rozbalení hodnoty, pokud odpovídá vzoru + if let Some(hodnota) = neco { + println!("neco obsahuje {hodnota}"); + } + + // Výchozí hodnota, pokud je None + let s_vychozi = nic.unwrap_or(0); + println!("nic s výchozí hodnotou = {s_vychozi}"); +} + +// --------------------------------------------------------------------------- +// 18. let-else +// --------------------------------------------------------------------------- +fn let_else() { + println!("\n== 18. let-else =="); + + // `let ... else` – rozbalí hodnotu, a pokud vzor nesedí, MUSÍ blok else + // z funkce odejít (return, break, continue, panic). + let vstup = "123"; + let Ok(cislo) = vstup.parse::() else { + println!("'{vstup}' není číslo"); + return; + }; + println!("načteno číslo {cislo}"); +} + +// --------------------------------------------------------------------------- +// 19. Nepoužité proměnné +// --------------------------------------------------------------------------- +fn nepouzite_promenne() { + println!("\n== 19. Nepoužité proměnné =="); + + // Překladač varuje u nepoužitých proměnných. Podtržítko na začátku varování potlačí. + let _zatim_nepouzito = 10; + + // Samotné `_` hodnotu vůbec nesváže (a u typů na haldě ji rovnou zahodí). + let _ = String::from("zahozeno"); + + println!("(žádné varování)"); +}