REFERENČNÍ PŘÍRUČKA

Programování
v Rustu

Kompletní přehled jazyka Rust — od základů po pokročilé koncepty. Český výklad, anglický kód.

Instalace


Rust se instaluje pomocí nástroje rustup, který spravuje verze kompilátoru a nástrojů.

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup update
rustc --version
rustup doc
PříkazPopis
rustcKompilátor Rustu
rustupSprávce verzí Rustu
cargoSprávce balíčků a build tool

Cargo


Cargo je build systém a správce závislostí. Každý Rust projekt je řízen souborem Cargo.toml.

cargo new muj_projekt
cargo new --lib moje_knihovna
cargo build
cargo run
cargo test
cargo build --release
cargo add serde

Cargo.toml — ukázka

# Cargo.toml — konfigurační soubor projektu
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
rand = "0.8"

Datové typy


Rust je staticky typovaný jazyk — každá hodnota má přesně daný typ, který kompilátor zná v době překladu.

Skalární typy

TypPopisRozsah / příklad
i8, i16, i32, i64, i128Celé číslo se znaménkemi32: −2³¹ až 2³¹−1
u8, u16, u32, u64, u128Celé číslo bez znaménkau8: 0–255
f32, f64Desetinné číslo3.14, 2.718
boolLogická hodnotatrue / false
charUnicode znak (4 bajty)'a', '€', '🦀'
isize, usizeVelikost závisí na architektuře64bit: 8 bajtů

Složené typy

// Tuple — fixní počet prvků různých typů
let tup: (i32, f64, bool) = (42, 3.14, true);
let x = tup.0;   // přístup přes index
let (a, b, c) = tup;  // destructuring

// Array — fixní délka, stejný typ
let arr: [i32; 5] = [1, 2, 3, 4, 5];
let zeros = [0; 10];  // 10 nul
let first = arr[0];

// Slice — pohled do části pole
let slice: &[i32] = &arr[1..3];  // prvky 1 a 2

String typy

// &str — reference na string slice (neměnné, statické)
let hello: &str = "Ahoj světe";

// String — vlastněný, měnitelný, heap-allocated
let mut s = String::from("Hello");
s.push_str(" World");
s.push('!');

// Konverze
let owned: String = hello.to_string();
let borrowed: &str = &s;

Proměnné


V Rustu jsou proměnné ve výchozím stavu neměnné (immutable). Klíčové slovo mut umožňuje měnit hodnotu.

// Neměnná proměnná (immutable) — výchozí
let x = 5;
// x = 6;  ← chyba kompilace!

// Měnitelná proměnná (mutable)
let mut y = 5;
y = 10;  // OK

// Explicitní typová anotace
let z: u32 = 42;

// Shadowing — nová proměnná se stejným názvem
let x = 5;
let x = x * 2;  // x je teď 10
let x = "text"; // může změnit i typ!

// Konstanty — vždy neměnné, typ povinný, platné celý program
const MAX_POINTS: u32 = 100_000;

// Statické proměnné
static GREETING: &str = "Hello";

Funkce


Funkce se definují klíčovým slovem fn. Návratový typ se uvádí za šipkou ->. Poslední výraz bez středníku je automaticky vrácen.

// Základní funkce
fn greet(name: &str) {
    println!("Ahoj, {}!", name);
}

// Funkce s návratovou hodnotou
fn add(a: i32, b: i32) -> i32 {
    a + b  // bez středníku = return
}

// Explicitní return
fn abs_value(n: i32) -> i32 {
    if n < 0 {
        return -n;
    }
    n
}

// Více návratových hodnot (tuple)
fn min_max(arr: &[i32]) -> (i32, i32) {
    let min = arr.iter().min().copied().unwrap();
    let max = arr.iter().max().copied().unwrap();
    (min, max)
}

Řízení toku


if / else

let n = 42;

if n < 0 {
    println!("záporné");
} else if n == 0 {
    println!("nula");
} else {
    println!("kladné");
}

// if jako výraz
let label = if n % 2 == 0 { "sudé" } else { "liché" };

Smyčky

// loop — nekonečná smyčka
let result = loop {
    let x = get_value();
    if x > 10 { break x * 2; }
};

// while
let mut i = 0;
while i < 10 {
    i += 1;
}

// for — iterace přes rozsah
for i in 0..10 {           // 0 až 9
    print!("{} ", i);
}
for i in 0..=10 {         // 0 až 10 včetně
    print!("{} ", i);
}

// for — iterace přes kolekci
let v = vec![1, 2, 3];
for x in &v {
    println!("{}", x);
}

match

let n = 3;
match n {
    1       => println!("jedna"),
    2 | 3   => println!("dvě nebo tři"),
    4..=10 => println!("čtyři až deset"),
    _       => println!("cokoliv jiného"),
}

// match jako výraz
let text = match n {
    1 => "one",
    2 => "two",
    _ => "other",
};

Ownership


Ownership je nejdůležitější a nejunikátnější koncept Rustu. Zajišťuje bezpečnost paměti bez garbage collectoru.

📌 Tři pravidla Ownership 1. Každá hodnota má právě jednoho vlastníka.
2. Může existovat pouze jeden vlastník najednou.
3. Když vlastník opustí scope, hodnota je uvolněna (drop).
// Move — přenesení vlastnictví
let s1 = String::from("hello");
let s2 = s1;  // s1 je přesunuto do s2
// println!("{}", s1);  ← chyba! s1 již neplatí
println!("{}", s2);   // OK

// Clone — hluboká kopie
let s3 = s2.clone();
println!("{} {}", s2, s3);  // obě platí

// Copy typy (jednoduché skalární hodnoty) se kopírují automaticky
let x = 5;
let y = x;  // x i y jsou platné (i32 implementuje Copy)

// Ownership a funkce
fn takes_ownership(s: String) {
    println!("{}", s);
}  // s je uvolněno (drop)

let my_str = String::from("ahoj");
takes_ownership(my_str);
// my_str zde již nelze použít

Borrowing & Reference


Reference umožňují předat hodnotu funkci bez přenosu vlastnictví — vypůjčení (borrow).

// Neměnná reference (&T)
fn calculate_length(s: &String) -> usize {
    s.len()
}

let s = String::from("hello");
let len = calculate_length(&s);
println!("{} má {} znaků", s, len);  // s stále platí

// Měnitelná reference (&mut T)
fn append(s: &mut String) {
    s.push_str(" world");
}

let mut s = String::from("hello");
append(&mut s);
⚠ Pravidla referencí • Libovolný počet neměnných referencí (&T) najednou.
• NEBO právě jedna měnitelná reference (&mut T).
• Nikdy obě zároveň! Toto kompilátor vynucuje.

Lifetimes


Lifetimes říkají kompilátoru, jak dlouho jsou reference platné. Zabraňují dangling references.

// Explicitní lifetime anotace
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

// Lifetime ve structu
struct Important<'a> {
    part: &'a str,
}

// 'static — platné po celou dobu běhu programu
let s: &'static str = "Jsem vždy platný";

Struct


Struktury jsou základní způsob vytváření vlastních datových typů v Rustu.

// Definice structu
struct User {
    username: String,
    email: String,
    age: u32,
    active: bool,
}

// Vytvoření instance
let user = User {
    username: String::from("alice"),
    email: String::from("[email protected]"),
    age: 30,
    active: true,
};

// Struct update syntax
let user2 = User {
    email: String::from("[email protected]"),
    username: String::from("bob"),
    ..user  // zbytek zkopíruj z user
};

// Implementace metod
impl User {
    // associated function (konstruktor)
    fn new(username: String, email: String) -> Self {
        User { username, email, age: 0, active: true }
    }

    // metoda (&self = neměnná reference na sebe)
    fn display(&self) {
        println!("{} ({})", self.username, self.email);
    }

    // měnitelná metoda
    fn deactivate(&mut self) {
        self.active = false;
    }
}

// Tuple struct
struct Point(f64, f64);
let p = Point(3.0, 4.0);
println!("x={}, y={}", p.0, p.1);

Enum


Enumerace v Rustu jsou velmi výkonné — každá varianta může nést vlastní data.

// Jednoduchý enum
enum Direction {
    North, South, East, West,
}

// Enum s daty
enum Shape {
    Circle(f64),              // poloměr
    Rectangle(f64, f64),     // šířka, výška
    Triangle { base: f64, height: f64 },
}

impl Shape {
    fn area(&self) -> f64 {
        match self {
            Shape::Circle(r) => 3.14159 * r * r,
            Shape::Rectangle(w, h) => w * h,
            Shape::Triangle { base, height } => base * height / 2.0,
        }
    }
}

// Option enum — absence hodnoty (nahrazuje null)
let some: Option<i32> = Some(42);
let none: Option<i32> = None;

if let Some(val) = some {
    println!("Hodnota: {}", val);
}

// unwrap_or pro výchozí hodnotu
let x = none.unwrap_or(0);  // 0

Kolekce


Vec<T> — dynamické pole

let mut v: Vec<i32> = Vec::new();
v.push(1);
v.push(2);
v.push(3);

// Makro
let v2 = vec![1, 2, 3, 4, 5];

// Přístup k prvkům
let third = &v2[2];             // panic při out-of-bounds
let third = v2.get(2);          // vrací Option<&i32>

// Iterace
for x in &v2 { print!("{} ", x); }
for x in &mut v { *x *= 2; }  // měnitelná iterace

HashMap<K, V>

use std::collections::HashMap;

let mut map = HashMap::new();
map.insert("name", "Alice");
map.insert("city", "Praha");

// Čtení
let name = map.get("name");    // Option<&&str>

// Vložit jen pokud klíč neexistuje
map.entry("age").or_insert("25");

// Iterace
for (key, value) in &map {
    println!("{}: {}", key, value);
}

Traits


Traits definují sdílené chování — podobné rozhraním (interface) v jiných jazycích.

// Definice traitu
trait Animal {
    fn name(&self) -> &str;
    fn sound(&self) -> &str;
    
    // Defaultní implementace
    fn describe(&self) {
        println!("{} říká: {}", self.name(), self.sound());
    }
}

struct Dog;
struct Cat;

impl Animal for Dog {
    fn name(&self) -> &str { "Pes" }
    fn sound(&self) -> &str { "Haf" }
}

impl Animal for Cat {
    fn name(&self) -> &str { "Kočka" }
    fn sound(&self) -> &str { "Mňau" }
}

// Trait jako parametr funkce
fn make_sound(animal: &impl Animal) {
    animal.describe();
}

// Trait object (dynamická dispatch)
let animals: Vec<Box<dyn Animal>> = vec![
    Box::new(Dog),
    Box::new(Cat),
];

Generics


Generiky umožňují psát kód, který funguje pro různé typy bez duplikace.

// Generická funkce
fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];
    for item in list {
        if item > largest { largest = item; }
    }
    largest
}

// Generický struct
struct Pair<T> {
    first: T,
    second: T,
}

impl<T: std::fmt::Display + PartialOrd> Pair<T> {
    fn cmp_display(&self) {
        if self.first >= self.second {
            println!("Větší: {}", self.first);
        }
    }
}

Error handling


Rust nemá výjimky. Chyby se zpracovávají přes typ Result<T, E>.

use std::fs::File;
use std::io::{self, Read};

// Základní match na Result
let f = File::open("hello.txt");
let f = match f {
    Ok(file) => file,
    Err(e) => {
        panic!("Nelze otevřít soubor: {}", e);
    }
};

// Operátor ? — propagace chyby
fn read_username() -> Result<String, io::Error> {
    let mut s = String::new();
    File::open("user.txt")?.read_to_string(&mut s)?;
    Ok(s)
}

// Vlastní typ chyby
use std::fmt;

enum MyError {
    NotFound,
    InvalidInput(String),
}

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            MyError::NotFound           => write!(f, "Nenalezeno"),
            MyError::InvalidInput(msg) => write!(f, "Chybný vstup: {}", msg),
        }
    }
}

Closures


Closure je anonymní funkce, která může zachytit proměnné z okolního scope.

// Základní closure
let add = |a, b| a + b;
println!("{}", add(2, 3));

// Zachytávání prostředí
let multiplier = 3;
let triple = |x| x * multiplier;  // borrowuje multiplier

// move closure — přebírá ownership
let s = String::from("ahoj");
let greet = move || println!("{}", s);

// Closure jako parametr
fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
    f(x)
}

let result = apply(|x| x * x, 5);  // 25

Iterátory


Iterátory jsou líné (lazy) — výpočet probíhá až při konzumaci. Jsou velmi výkonné a idiomatické v Rustu.

let v = vec![1, 2, 3, 4, 5];

// map, filter, collect
let result: Vec<i32> = v.iter()
    .filter(|&&x| x % 2 == 0)   // sudá čísla
    .map(|&x| x * 10)            // vynásob 10
    .collect();                   // [20, 40]

// sum, product
let total: i32 = v.iter().sum();
let product: i32 = v.iter().product();

// fold — obecná redukce
let sum = v.iter().fold(0, |acc, &x| acc + x);

// enumerate, zip
for (i, val) in v.iter().enumerate() {
    println!("[{}] = {}", i, val);
}

// any, all, count, find
let has_even = v.iter().any(|&x| x % 2 == 0);
let all_pos = v.iter().all(|&x| x > 0);

Moduly


Moduly organizují kód do logických celků a řídí viditelnost (public/private).

// src/main.rs
mod math {
    pub fn add(a: i32, b: i32) -> i32 { a + b }
    
    pub mod advanced {
        pub fn sqrt(x: f64) -> f64 { x.sqrt() }
    }
}

// Použití
use math::advanced::sqrt;
let r = math::add(2, 3);
let s = sqrt(16.0);

// Soubor jako modul: src/utils.rs
mod utils;  // Rust hledá src/utils.rs nebo src/utils/mod.rs
use utils::helper;

Concurrency


Rust garantuje bezpečné souběžné programování díky systému ownership. Kompilátor zabraňuje data races.

use std::thread;
use std::sync::{Arc, Mutex};

// Spuštění vlákna
let handle = thread::spawn(|| {
    println!("Jsem v novém vlákně!");
});
handle.join().unwrap();  // čekej na dokončení

// Sdílená data — Arc + Mutex
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];

for _ in 0..10 {
    let c = Arc::clone(&counter);
    handles.push(thread::spawn(move || {
        let mut num = c.lock().unwrap();
        *num += 1;
    })));
}

for h in handles { h.join().unwrap(); }
println!("Výsledek: {}", *counter.lock().unwrap());  // 10

// Kanály (channels) — komunikace mezi vlákny
use std::sync::mpsc;

let (tx, rx) = mpsc::channel();
thread::spawn(move || {
    tx.send("Zpráva z vlákna").unwrap();
});
let msg = rx.recv().unwrap();
println!("{}", msg);
📌 Async/Await — asynchronní programování Pro async kód přidej do Cargo.toml: tokio = { version = "1", features = ["full"] }
use tokio;

#[tokio::main]
async fn main() {
    let result = fetch_data().await;
    println!("{:?}", result);
}

async fn fetch_data() -> String {
    // async operace</