@@ -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 ::< u16 > ( ) . 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 = 42 u8 ; // 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 , _ > = 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 < i32 > , 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<T>.
let neco : Option < i32 > = Some ( 42 ) ;
let nic : Option < i32 > = " 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 ::< i32 > ( ) 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í) " ) ;
}