Přehled & Hello World

Rust je systémový jazyk zaměřený na výkon, bezpečnost paměti a souběžnost — bez garbage collectoru.

// Hello, World!
fn main() {
    println!("Hello, {}!", "světe");
}
# Cargo – package manager
cargo new hello    # nový projekt
cargo build        # build
cargo run          # spustit
cargo test         # testy
cargo fmt          # formátovat
cargo clippy       # linter
cargo doc --open   # dokumentace

Primitivní typy

TypPopisPříklad
i8…i128, isizeZnaménkové celé číslolet x: i32 = -42;
u8…u128, usizeNeznaménkové celé číslolet x: u8 = 255;
f32, f64Plovoucí desetinná čárkalet pi: f64 = 3.14;
booltrue / falselet ok = true;
charUnicode scalar (4 B)let c = 'ř';
(T, U, …)Tuplelet t = (1, 2.0, true);
[T; N]Array – fixní délkalet a = [0i32; 5];
&[T]Slice – pohled na částlet s = &a[1..3];
let t: (i32, f64, bool) = (1, 2.0, true);
let (a, b, _) = t;          // destructuring
println!("{}", t.0);        // přístup indexem

let arr: [i32; 5] = [1, 2, 3, 4, 5];
let zeros = [0; 10];
let slice: &[i32] = &arr[1..4];

Proměnné & konstanty

let x = 5;                     // immutable (výchozí)
let mut y = 5; y = 10;        // mutable
let z = 5; let z = z * 2;     // shadowing (z = 10)
const MAX: u32 = 100_000;     // konstanta – vždy s typem
static HELLO: &str = "Hi";    // statická životnost

Operátory

KategorieOperátory
Aritmetika+ - * / %
Bitové& | ^ ! << >>
Porovnání== != < > <= >=
Logika&& || !
Přiřazení= += -= *= /= …
Reference& &mut *
Rozsah.. ..=
let a = 10; let b = 3;
a / b      // 3 (celočíselné)
a % b      // 1
a & b      // 2
a | b      // 11
a ^ b      // 9
a << 1    // 20
255u8.wrapping_add(1)    // 0
200u8.saturating_add(100) // 255

Řízení toku

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

// loop s návratovou hodnotou
let result = loop {
    counter += 1;
    if counter == 10 { break counter * 2; }
};

// while
while i < 5 { i += 1; }

// for
for x in 0..5  { print!("{x} "); }    // 0 1 2 3 4
for x in 0..=5 { print!("{x} "); }   // 0 1 2 3 4 5
for item in &vec { println!("{item}"); }

// Labely
'outer: for i in 0..3 {
    for j in 0..3 {
        if i == j { continue 'outer; }
    }
}

Structs

#[derive(Debug, Clone)]
struct Point { x: f64, y: f64 }

let p = Point { x: 1.0, y: 2.0 };
let q = Point { x: 5.0, ..p };   // struct update syntax

// Tuple struct
struct Color(u8, u8, u8);
let red = Color(255, 0, 0);

// Metody
impl Point {
    fn new(x: f64, y: f64) -> Self { Self { x, y } }
    fn distance(&self, o: &Point) -> f64 {
        ((self.x-o.x).powi(2) + (self.y-o.y).powi(2)).sqrt()
    }
    fn translate(&mut self, dx: f64, dy: f64) {
        self.x += dx; self.y += dy;
    }
}

Enums & Pattern matching

#[derive(Debug)]
enum Shape {
    Circle(f64),
    Rectangle { w: f64, h: f64 },
    Triangle(f64, f64, f64),
}

impl Shape {
    fn area(&self) -> f64 {
        match self {
            Shape::Circle(r)          => std::f64::consts::PI * r * r,
            Shape::Rectangle { w, h } => w * h,
            Shape::Triangle(a, b, c)  => {
                let s = (a+b+c)/2.0;
                (s*(s-a)*(s-b)*(s-c)).sqrt()
            }
        }
    }
}

// match s guard
match &shape {
    Shape::Circle(r) if *r > 3.0 => println!("velký kruh"),
    Shape::Circle(_)               => println!("malý kruh"),
    _                               => println!("jiný tvar"),
}

// Option<T>
let opt: Option<i32> = Some(42);
if let Some(v) = opt { println!("{v}"); }
let val = opt.unwrap_or(0);

// while let
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() { print!("{top} "); }

Kolekce

Vec<T>

let mut v = vec![1, 2, 3];
v.push(4);           v.pop();
v.insert(1, 10);     v.remove(1);
v.len();             v.is_empty();
v.contains(&3);     v.sort();
v.sort_by(|a,b| b.cmp(a));        // sestupně
v.dedup();           v.retain(|&x| x > 2);
v.extend([5,6,7]);
let s: i32 = v.iter().sum();

HashMap & HashSet

use std::collections::{HashMap, HashSet};

let mut map: HashMap<String, i32> = HashMap::new();
map.insert("jablka".to_string(), 3);
if let Some(v) = map.get("jablka") { println!("{v}"); }

// Entry API – vlož jen pokud neexistuje
map.entry("hrušky".into()).or_insert(0);
*map.entry("jablka".into()).or_insert(0) += 1;
for (k, v) in &map { println!("{k}: {v}"); }

let a: HashSet<i32> = [1,2,3].into();
let b: HashSet<i32> = [2,3,4].into();
let prunik: HashSet<_> = a.intersection(&b).collect(); // {2,3}

Řetězce

Dva typy &str — neměnný pohled (string slice). String — vlastněný, heap-alokovaný, měnitelný.
let s: &str = "statický";
let mut owned = String::from("Ahoj");
owned.push_str(", světe");
owned.push('!');

let s1 = String::from("Rust");
let s2 = s1 + " je super";      // s1 přesunuto
let s3 = format!("{s2}!");      // nepřesouvá

"  hello  ".trim()
"hello".to_uppercase()
"a,b,c".split(',').collect::<Vec<_>>()
"42".parse::<i32>()            // Ok(42)
42.to_string()                  // "42"
"česky".chars().count()        // 6 znaků (ne bajtů!)

Ownership

3 pravidla 1. Každá hodnota má právě jednoho vlastníka. 2. V daném okamžiku existuje jen jeden vlastník. 3. Při opuštění scope se hodnota zahodí (drop).
let s1 = String::from("hello");
let s2 = s1;           // move – s1 nelze použít
let s3 = s2.clone();  // hluboká kopie – s2 stále platí

// Copy typy (i32, f64, bool, char…) se kopírují automaticky
let x = 5; let y = x;  // x stále platí

fn takes(s: String) {}       // spotřebuje vlastnictví
fn gives() -> String { String::from("nové") }

Borrowing & References

Pravidlo Buď libovolný počet &T (immutable) nebo právě jedna &mut T — nikdy obojí zároveň.
fn len(s: &String) -> usize { s.len() }
fn append(s: &mut String) { s.push_str("!"); }

let mut s = String::from("hello");
len(&s);          // immutable borrow
append(&mut s);   // mutable borrow

// Dereferencing
let mut x = 5;
let r = &mut x;
*r += 1;   // x == 6

Lifetimes

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

// Lifetime ve struct
struct Excerpt<'a> { part: &'a str }

// 'static – platné po celou dobu běhu
let s: &'static str = "navždy";

Funkce

fn add(a: i32, b: i32) -> i32 { a + b }  // výraz = implicitní return
fn forever() -> ! { loop {} }           // divergující
fn sum_all(nums: &[i32]) -> i32 { nums.iter().sum() }

// Function pointer
fn apply(f: fn(i32) -> i32, x: i32) -> i32 { f(x) }

// Default přes Option
fn greet(name: &str, prefix: Option<&str>) -> String {
    format!("{}, {name}!", prefix.unwrap_or("Ahoj"))
}

Closures

let add = |a: i32, b| a + b;
let factor = 3;
let mul = |x| x * factor;          // capture by borrow
let owned = move || factor * 2;   // přesune factor

// Fn / FnMut / FnOnce
fn call<F: Fn(i32) -> i32>(f: F) -> i32 { f(1) }

// Řetězení s iterátory
let evens: Vec<i32> = (1..10)
    .filter(|x| x % 2 == 0)
    .map(|x| x * 10)
    .collect();

Generika

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

struct Pair<T> { first: T, second: T }

// where clause
fn dbg_print<T, U>(t: T, u: U)
where
    T: std::fmt::Display + Clone,
    U: std::fmt::Debug,
{ println!("{t} {:?}", u); }

// Turbofish
let n = "42".parse::<i32>().unwrap();

Traits

trait Animal {
    fn name(&self) -> &str;
    fn sound(&self) -> &str;
    fn describe(&self) -> String {  // defaultní impl
        format!("{} říká {}", self.name(), self.sound())
    }
}
struct Dog;
impl Animal for Dog {
    fn name(&self) -> &str { "Pes" }
    fn sound(&self) -> &str { "Haf" }
}

// impl Trait (staticky)
fn print_animal(a: &impl Animal) { println!("{}", a.describe()); }
// dyn Trait (dynamicky)
fn call_sound(a: &dyn Animal) { println!("{}", a.sound()); }
let animals: Vec<Box<dyn Animal>> = vec![Box::new(Dog)];

impl bloky & standardní traits

use std::fmt;

// Display
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

// From / Into
impl From<(f64, f64)> for Point {
    fn from((x, y): (f64, f64)) -> Self { Self { x, y } }
}
let p: Point = (1.0, 2.0).into();

// Operator overloading
use std::ops::Add;
impl Add for Point {
    type Output = Point;
    fn add(self, o: Point) -> Point {
        Point { x: self.x+o.x, y: self.y+o.y }
    }
}

Error handling

// ? operátor propaguje Err nahoru
fn double(s: &str) -> Result<i32, std::num::ParseIntError> {
    Ok(s.parse::<i32>()? * 2)
}

// Vlastní chyba
#[derive(Debug)]
enum AppError { Parse(std::num::ParseIntError), TooLarge(i32) }
impl std::fmt::Display for AppError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            AppError::Parse(e)     => write!(f, "parse: {e}"),
            AppError::TooLarge(n) => write!(f, "{n} je příliš velké"),
        }
    }
}
impl std::error::Error for AppError {}
impl From<std::num::ParseIntError> for AppError {
    fn from(e: std::num::ParseIntError) -> Self { AppError::Parse(e) }
}

// Box<dyn Error> – rychlé prototypy
fn quick() -> Result<(), Box<dyn std::error::Error>> {
    let n: i32 = "10".parse()?; println!("{n}"); Ok(())
}

// Metody na Result / Option
res.unwrap_or(default)    res.map(|v| v*2)
res.map_err(|e| ...)       res.and_then(|v| next(v))
res.ok()                   // Result → Option
opt.ok_or(err)             // Option → Result

Iterátory

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

v.iter().filter(|&&x| x%2==0).map(|&x| x*10).collect::<Vec<_>>()
v.iter().sum::<i32>()         // 15
v.iter().max()                  // Some(5)
v.iter().any(|&x| x>3)         // true
v.iter().position(|&x| x==3)   // Some(2)
v.iter().fold(0, |acc,&x| acc+x)
v.iter().enumerate()
v.iter().zip(other.iter())
v.iter().chain(other.iter())
v.iter().take(3)                // první 3
v.iter().skip(2)                // od indexu 2
v.iter().flat_map(|&x| 0..x)

// into_iter vs iter vs iter_mut
v.into_iter()   // spotřebuje Vec, dává T
v.iter()        // &T, Vec zůstane
v.iter_mut()   // &mut T

// Vlastní iterátor
struct Counter { n: u32 }
impl Iterator for Counter {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        if self.n < 5 { self.n += 1; Some(self.n) } else { None }
    }
}

Smart Pointers

TypPopis
Box<T>Heap-alokace, jeden vlastník; rekurzivní typy
Rc<T>Sdílené vlastnictví (počítání referencí), single-thread
Arc<T>Jako Rc, ale atomický → thread-safe
RefCell<T>Interior mutability — borrow checks za běhu
Mutex<T>Mutexem chráněná hodnota; s Arc přes vlákna
use std::rc::Rc; use std::cell::RefCell;

enum List { Cons(i32, Box<List>), Nil }  // Box pro rekurzi

let a = Rc::new(5);
let b = Rc::clone(&a);   // počítadlo → 2

let shared = Rc::new(RefCell::new(vec![1]));
let c = Rc::clone(&shared);
shared.borrow_mut().push(2);
println!("{:?}", c.borrow());  // [1, 2]

Concurrency

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

// Vlákno
let h = thread::spawn(|| println!("z vlákna"));
h.join().unwrap();

// Channel (mpsc)
let (tx, rx) = mpsc::channel();
let tx2 = tx.clone();
thread::spawn(move || tx.send("zpráva 1").unwrap());
thread::spawn(move || tx2.send("zpráva 2").unwrap());
for msg in rx { println!("{msg}"); }

// Arc + Mutex – sdílená paměť
let counter = Arc::new(Mutex::new(0));
let handles: Vec<_> = (0..10).map(|_| {
    let c = Arc::clone(&counter);
    thread::spawn(move || { *c.lock().unwrap() += 1; })
}).collect();
for h in handles { h.join().unwrap(); }
println!("{}", *counter.lock().unwrap()); // 10

Async / Await

Požadavky Přidej do Cargo.toml: tokio = { version = "1", features = ["full"] }
use tokio::time::{sleep, Duration};

async fn fetch(id: u32) -> String {
    sleep(Duration::from_millis(100)).await;
    format!("data #{id}")
}

#[tokio::main]
async fn main() {
    let a = fetch(1).await;
    let (b, c) = tokio::join!(fetch(2), fetch(3));

    use tokio::time::timeout;
    match timeout(Duration::from_millis(50), fetch(99)).await {
        Ok(data) => println!("{data}"),
        Err(_)   => println!("Timeout!"),
    }
}

Makra

// Vestavěná
println!("{val}")          format!("{a}+{b}")
eprintln!("err")          vec![1,2,3]
assert!(x > 0)            assert_eq!(x, 5)
panic!("oops")            todo!()  unreachable!()
dbg!(&x)                  include_str!("f.txt")
env!("CARGO_PKG_VERSION")

// Deklarativní makro
macro_rules! my_vec {
    () => { Vec::new() };
    ($($x:expr),+ $(,)?) => {{
        let mut v = Vec::new();
        $(v.push($x);)+
        v
    }};
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
struct Foo { x: i32 }

Moduly & Cargo

mod math {
    pub fn add(a: i32, b: i32) -> i32 { a + b }
    pub mod trig { pub fn sin(x: f64) -> f64 { x.sin() } }
}
use math::{add, trig::sin as tsin};

// Cargo.toml
// [dependencies]
// serde  = { version = "1", features = ["derive"] }
// tokio  = { version = "1", features = ["full"] }
// anyhow = "1"
//
// cargo add serde --features derive
// cargo check      ← rychlá kontrola bez buildu
// cargo publish    ← publikuj na crates.io

Unsafe Rust

Pozor Odpovědnost za bezpečnost paměti přechází na programátora.
let mut x = 5;
let r = &mut x as *mut i32;
unsafe { *r = 10; }

unsafe fn dangerous() {}
extern "C" { fn abs(x: i32) -> i32; }
unsafe { dangerous(); println!("{}", abs(-5)); }

std::mem::size_of::<i32>()      // 4
std::mem::swap(&mut a, &mut b)
std::mem::replace(&mut x, 0)    // vrátí starou hodnotu

Testování

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn basic() { assert_eq!(add(2, 3), 5); }

    #[test]
    #[should_panic(expected = "záporné")]
    fn panics() { must_be_positive(-1); }

    #[test]
    fn with_result() -> Result<(), String> {
        let n = "5".parse::<i32>().map_err(|e| e.to_string())?;
        assert_eq!(n, 5); Ok(())
    }

    #[test]
    #[ignore = "pomalý"]
    fn slow() {}
}
// cargo test           – všechny testy
// cargo test basic     – konkrétní
// cargo test -- --nocapture

Cheatsheet

Formátování
{}Display
{:?}Debug
{:#?}Pretty debug
{:b} / {:o} / {:x}bin / oct / hex
{:e}vědecká notace
{:>10}zarovnání vpravo šířka 10
{:0>5}doplnit nulami (00042)
{:.3}3 desetinná místa
{val}named (Rust 1.58+)
Atributy
#[derive(…)]auto-implementace
#[allow(unused)]potlačit warning
#[must_use]varovat při ignoraci
#[inline]doporučit inlining
#[deprecated]zastaralé API
#[cfg(test)]jen při testech
#[cfg(feature="x")]podmíněná kompilace
#[repr(C)]C-kompatibilní layout
Doporučené zdroje