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 # dokumentacePrimitivní typy
| Typ | Popis | Příklad |
|---|---|---|
i8…i128, isize | Znaménkové celé číslo | let x: i32 = -42; |
u8…u128, usize | Neznaménkové celé číslo | let x: u8 = 255; |
f32, f64 | Plovoucí desetinná čárka | let pi: f64 = 3.14; |
bool | true / false | let ok = true; |
char | Unicode scalar (4 B) | let c = 'ř'; |
(T, U, …) | Tuple | let t = (1, 2.0, true); |
[T; N] | Array – fixní délka | let a = [0i32; 5]; |
&[T] | Slice – pohled na část | let 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
| Kategorie | Operá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
| Typ | Popis |
|---|---|
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
- The Rust Book – doc.rust-lang.org/book
- Rust by Example – doc.rust-lang.org/rust-by-example
- Rustlings – github.com/rust-lang/rustlings
- crates.io – registr balíčků
- docs.rs – dokumentace ke každému crate