Ukazatele v Rustu aneb temná strana Síly

18. 5. 2017
Doba čtení: 19 minut

Sdílet

 Autor: Rust project
V jazyku Rust nalezneme kromě referencí, jejichž použití je kontrolované překladačem, i ukazatele (pointer). S nimi lze realizovat některé „triky“ známé z jazyků C a C++, ale některé operace jsou potenciálně nebezpečné.

Obsah

1. Ukazatele v Rustu aneb temná strana Síly

2. Deklarace a inicializace proměnné typu ukazatel

3. První demonstrační příklad – deklarace a inicializace ukazatele

4. Přístup k hodnotám proměnných přes ukazatel – blok unsafe

5. Kontrola překladačem na použití bloku unsafe

6. Měnitelné versus neměnitelné ukazatele, měnitelné versus neměnitelné proměnné

7. Ukazatele pro čtení či pro zápis hodnot do referencovaných proměnných

8. Demonstrační příklad – zápis do proměnné přes ukazatel

9. Kontrola, zda je možné do proměnné skutečně zapisovat

10. Krátká rekapitulace – deklarace a inicializace ukazatelů různých typů

11. Čtení či zápis do proměnné mimo oblast její životnosti?

12. Ukazatel na datovou strukturu

13. Přístup k prvkům struktury přes ukazatel

14. Repositář s demonstračními příklady

15. Odkazy na Internetu

1. Ukazatele v Rustu aneb temná strana Síly

V programovacím jazyku Rust je možné a v některých případech dokonce i nutné používat ukazatele reprezentované primitivním typem pointer, které se však v některých ohledech liší od „klasických“ ukazatelů známých z jazyků C či C++. Na základě mnohaletých zkušeností vývojářů Rustu se zmíněnými programovacími jazyky C/C++ totiž byly ukazatele v Rustu navrženy takovým způsobem, aby práce s nimi byla poněkud bezpečnější (pokud je to vůbec možné) a aby všechny potenciálně nebezpečné operace byly umístěny do speciálního bloku nazvaného unsafe. Do určité míry se zjednodušila i ukazatelová aritmetika (pointer arithmetic/pointer math) díky existenci funkce pointer.offset(). I tak je však při práci s ukazateli nutné dbát zvýšené opatrnosti, protože překladač například nehlídá to, jestli ukazatel obsahuje adresu stále živé proměnné atd.

V praxi se většinou snažíme se použití ukazatelů zcela vyhnout, samozřejmě za předpokladu, že je to možné. Mnoho programů vytvořených v Rustu ukazatele vůbec nepoužívá.

Poznámka: v minulosti existovalo v Rustu několik typů ukazatelů, navíc je slovo pointer dodnes používáno v několika kontextech. Ukazatele popisované dnes spadají do kategorie „raw pointers“.

2. Deklarace a inicializace proměnné typu ukazatel

V programovacím jazyku Rust rozeznáváme dva typy „raw“ ukazatelů – ukazatele používané pro čtení konstantní i měnitelné hodnoty a ukazatele na hodnoty, které lze přes ukazatel změnit (mutable). Nejdříve se seznámíme s ukazateli používanými jen pro čtení hodnoty (read only). Jejich typ je vždy *const T, kde T je prakticky libovolný datový typ Rustu. Pokud například budeme chtít nadefinovat proměnnou nazvanou pointer, která je ukazatelem na konstantní či měnitelnou 32bitovou celou hodnotu se znaménkem, bude deklarace vypadat následovně:

let pointer: *const i32;

Přiřazení adresy do ukazatele se do značné míry podobá zápisu používaném v céčku nebo i v Rustu při získávání reference:

let value: i32 = 42;
 
pointer = &value;

Deklaraci ukazatele můžeme spojit s jeho inicializací:

let value: i32 = 42;
 
let pointer: *const i32 = &value;

Poznámka: v tomto případě ovšem vždy musíte explicitně uvést datový typ ukazatele, jinak by se vytvořila „pouze“ reference na hodnotu (což již známe). Následující kód má tedy odlišný význam:

let value: i32 = 42;
 
let reference = &value;

Popř. explicitně:

let value: i32 = 42;
 
let reference: &i32 = &value;

Poznámka: interně se reference a ukazatele vlastně neliší, protože obsahují stejnou hodnotu = adresu proměnné. Práce s nimi je však odlišná, stejně jako kontroly, které provádí překladač.

3. První demonstrační příklad – deklarace a inicializace ukazatele

V dnešním prvním demonstračním příkladu vytvoříme neměnitelnou (immutable) proměnnou nazvanou value, k ní získáme referenci a taktéž ukazatel na ni. Následně je na standardní výstup vypsána hodnota proměnné, hodnota téže proměnné, ale přes referenci a konečně též obsah samotného ukazatele. Ovšem ukazatel obsahuje adresu proměnné, takže třetí řádek nevypíše 42, ale hexadecimální adresu value umístěné na zásobníkovém rámci funkce main (u reference se naproti tomu automaticky provede dereference a tudíž přečtení hodnoty proměnné). Povšimněte si, že získání reference na proměnnou a adresy proměnné se zapisuje stejným znakem &, jediný rozdíl spočívá v odlišném datovém typu:

fn main() {
    let value: i32 = 42;
 
    let reference: &i32 = &value;
    let pointer: *const i32 = &value;
 
    println!("{}", value);
    println!("{}", reference);
    println!("{:?}", pointer);
}

Po spuštění může tento příklad vypsat například následující hodnoty. Adresa proměnné value (tedy hodnota ukazatele) se samozřejmě může ve vašem případě lišit:

42
42
0x7fffc7039394

4. Přístup k hodnotám proměnných přes ukazatel – blok unsafe

K hodnotám proměnných lze samozřejmě přistupovat i přes ukazatel (jinak by ostatně nemělo smysl s ukazateli pracovat). Zápis je v tomto případě prakticky stejný, jak ho známe z céčka či z C++:

*ukazatel

Velký rozdíl mezi Rustem na jedné straně a jazyky C/C++ na straně druhé však spočívá v tom, že přístup přes ukazatel je považován za potenciálně nebezpečnou operaci a musí být za všech okolností uzavřen do speciálního bloku unsafe:

unsafe {
    ...
    *ukazatel
    ...
}

Podívejme se nyní na druhý demonstrační příklad, který na posledním řádku vypíše hodnotu proměnné získané nepřímo přes ukazatel:

fn main() {
    let value: i32 = 42;
 
    let reference: &i32 = &value;
    let pointer: *const i32 = &value;
 
    println!("{}", value);
    println!("{}", reference);
    println!("{:?}", pointer);
 
    unsafe {
        println!("{}", *pointer);
    }
}

Příklad výstupu tohoto demonstračního příkladu (třetí řádek se opět pravděpodobně bude na vašem počítači lišit):

42
42
0x7fff56270904
42

Alternativně je možné příklad přepsat takto (vložením bloku unsafe dovnitř makra println!):

fn main() {
    let value: i32 = 42;
 
    let reference: &i32 = &value;
    let pointer: *const i32 = &value;
 
    println!("{}", value);
    println!("{}", reference);
    println!("{:?}", pointer);
 
    println!("{}", unsafe {*pointer});
}

5. Kontrola překladačem na použití bloku unsafe

Ve chvíli, kdy blok unsafe nepoužijeme, bude se na nás překladač zlobit. Ostatně si to můžeme velmi snadno vyzkoušet na nepatrně upraveném příkladu, tentokrát ovšem bez unsafe bloku:

fn main() {
    let value: i32 = 42;
 
    let reference: &i32 = &value;
    let pointer: *const i32 = &value;
 
    println!("{}", value);
    println!("{}", reference);
    println!("{:?}", pointer);
 
    println!("{}", *pointer);
}

Překladač skutečně při pokusu o vytvoření binárního spustitelného souboru vypíše chybové hlášení:

  --> pointers02_no_unsafe.rs:11:20
   |
11 |     println!("{}", *pointer);
   |                    ^^^^^^^^ unsafe call requires unsafe function or block
<std macros>:2:27: 2:58 note: in this expansion of format_args!
<std macros>:3:1: 3:54 note: in this expansion of print! (defined in <std macros>)
pointers02_no_unsafe.rs:11:5: 11:30 note: in this expansion of println! (defined in <std macros>)
 
error: aborting due to previous error

Podobně je tomu i u dalších potenciálně nebezpečných operací, tj. u většiny operací s ukazateli.

6. Měnitelné versus neměnitelné ukazatele, měnitelné versus neměnitelné proměnné

Vzhledem k tomu, že ukazatele jsou primitivním datovým typem, rozeznává Rust měnitelné a neměnitelné ukazatele. Ovšem je rozdíl například mezi ukazatelem na měnitelnou hodnotu a měnitelným ukazatelem (a aby toho nebylo málo, rozeznáváme ještě typy *const a *mut popsané v navazujících kapitolách). Podívejme se nyní na jednotlivé varianty.

Neměnitelný ukazatel na neměnitelnou hodnotu – ten již známe z předchozích kapitol. Samotnou hodnotu nelze změnit, ovšem ani ukazatel nelze „přesměrovat“ na jinou proměnnou. Jediná povolená operace s ukazatelem je přečtení hodnoty proměnné přes její adresu (tj. dereferencování) v bloku unsafe:

fn main() {
    let value: i32 = 42;
 
    let pointer: *const i32 = &value;
 
    println!("{}", value);
    println!("{:?}", pointer);
}

Neměnitelný ukazatel na měnitelnou hodnotu. Samotný ukazatel vždy ukazuje na jedinou proměnnou, jejíž hodnota se však může změnit. Tento ukazatel lze ovšem použít pouze pro čtení hodnoty proměnné, nikoli pro zápis (což je velmi rozumné, jinými slovy kde to jde používejte *const a nikoli dále popsaný *mut):

fn main() {
    let mut value: i32 = 42;
 
    let pointer: *const i32 = &value;
 
    println!("{}", value);
    println!("{:?}", pointer);
 
    unsafe {
        println!("{}", *pointer);
    }
 
    value = 100;
    println!("{}", value);
    println!("{:?}", pointer);
 
    unsafe {
        println!("{}", *pointer);
    }
}

Měnitelný ukazatel na neměnitelnou (konstantní) hodnotu. Nyní jedna proměnná pointer v první části programu obsahuje adresu proměnné value1, v další části pak adresu proměnné value2. Jinými slovy adresa uložena v proměnné pointer se sice může změnit, nikoli však hodnoty uložené na této adrese:

fn main() {
    let value1: i32 = 42;
    let value2: i32 = 100;
 
    let mut pointer: *const i32;
 
    println!("{}", value1);
 
    pointer = &value1;
    println!("{:?}", pointer);
    println!("{}", unsafe {*pointer});
 
    pointer = &value2;
    println!("{:?}", pointer);
    println!("{}", unsafe {*pointer});
}

Měnitelný je ukazatel i samotná hodnota. Kombinace předchozích dvou příkladů (stále však platí, že přes ukazatel je možné proměnnou pouze číst, protože typ ukazatele je *const i32):

fn main() {
    let mut value1: i32 = 1;
    let mut value2: i32 = 3;
 
    let mut pointer: *const i32;
 
    pointer = &value1;
    println!("{}", unsafe {*pointer});
    value1 = 2;
    println!("{}", unsafe {*pointer});
 
    pointer = &value2;
    println!("{}", unsafe {*pointer});
    value2 = 4;
    println!("{}", unsafe {*pointer});
}

7. Ukazatele pro čtení či pro zápis hodnot do referencovaných proměnných

Aby toho nebylo málo, má klíčové slovo mut ještě jeden význam. Odlišujeme jím totiž ukazatele používané pouze pro čtení a ukazatele, přes něž můžeme měnit (mutovat) proměnnou, na níž ukazují. Prakticky to znamená, že se striktně rozlišuje mezi těmito typy:

let pointer1: *const i32 = &value;
let pointer2: *mut   i32 = &mut value;

Pokud se použije druhý zápis, musí být i samotná proměnná měnitelná! Tím je zajištěno, že se nikdo nebude snažit modifikovat immutable hodnotu (tedy snažit se může, ale překladač mu to nedovolí).

8. Demonstrační příklad – zápis do proměnné přes ukazatel

Rozdíl spočívá v tom, že ve druhém případě můžeme do proměnné zapisovat přes ukazatel. Podívejme se nyní na demonstrační příklad, z něhož je patrné, že i zápis přes ukazatel je – pochopitelně – potenciálně nebezpečná operace, která musí být uzavřena do bloku unsafe:

fn main() {
    let mut value: i32 = 42;
 
    let pointer: *mut i32 = &mut value;
 
    println!("{}", value);
    unsafe {
        println!("{}", *pointer);
    }
 
    value = 1;
 
    println!("{}", value);
    unsafe {
        println!("{}", *pointer);
    }
 
    unsafe {
        *pointer = 20;
    }
    println!("{}", value);
    unsafe {
        println!("{}", *pointer);
    }
}

Po překladu a spuštění tohoto příkladu dostaneme tento výstup:

42
42
1
1
20
20

9. Kontrola, zda je možné do proměnné skutečně zapisovat

Opět platí, že si překladač hlídá, zda se ukazatel typu *mut skutečně vytváří pro měnitelnou proměnnou. Zkusme na první modifikátor mut zapomenout:

fn main() {
    let mut value: i32 = 42;
 
    let pointer: *mut i32 = &mut value;
 
    println!("{}", value);
    unsafe {
        println!("{}", *pointer);
    }
 
    value = 1;
 
    println!("{}", value);
    unsafe {
        println!("{}", *pointer);
    }
 
    unsafe {
        *pointer = 20;
    }
    println!("{}", value);
    unsafe {
        println!("{}", *pointer);
    }
}

Překladač v takovém případě vypíše chybové hlášení, jehož druhou část již známe:

error: cannot borrow immutable local variable `value` as mutable
 --> pointers04_immut_var.rs:4:34
  |
2 |     let value: i32 = 42;
  |         ----- use `mut value` here to make mutable
3 |
4 |     let pointer: *mut i32 = &mut value;
  |                                  ^^^^^ cannot borrow mutably
 
error[E0384]: re-assignment of immutable variable `value`
  --> pointers04_immut_var.rs:11:5
   |
2  |     let value: i32 = 42;
   |         ----- first assignment to `value`
...
11 |     value = 1;
   |     ^^^^^^^^^ re-assignment of immutable variable
 
error: aborting due to 2 previous errors

10. Krátká rekapitulace – deklarace a inicializace ukazatelů různých typů

Prozatím jsme se setkali se dvěma způsoby deklarace proměnných – immutable (výchozí volba) a mutable. U ukazatelů taktéž existují varianty, přičemž klíčovými slovy const/mut se určuje, zda se přes ukazatel může do proměnné zapisovat či nikoli. Další varianty určují, zda i samotný ukazatel je immutable či mutable, tj. zde se může ukazatel změnit. Povšimněte si, že dvě možnosti jsou chybné – pokus o vytvoření ukazatele typu *mut na neměnitelnou proměnnou:

Proměnná Ukazatel Čtení proměnné Zápis do proměnné Čtení přes ukazatel Zápis přes ukazatel Ukazatel lze změnit
let v: i32; let p: *const i32; ano ne ano ne ne
let v: i32; let mut p: *const i32; ano ne ano ne ano
let v: i32; let p: *mut i32; ano ne chyba chyba chyba
let v: i32; let mut p: *mut i32; ano ne chyba chyba chyba
             
let mut v: i32; let p: *const i32; ano ano ano ne ne
let mut v: i32; let mut p: *const i32; ano ano ano ne ano
let mut v: i32; let p: *mut i32; ano ano ano ano ne
let mut v: i32; let mut p: *mut i32; ano ano ano ano ano

11. Čtení či zápis do proměnné mimo oblast její životnosti?

Programovací jazyk Rust (resp. přesněji řečeno jeho překladač) sice hlídá mnoho operací prováděných s ukazateli, ovšem nedokáže (a pravděpodobně to ani není prakticky možné) určit, zda ukazatel ještě obsahuje adresu živé proměnné či zda se již proměnná nachází mimo oblast své platnosti. Proto je možné přeložit následující program, který může (ale také nemusí) fungovat, protože v poslední části přistupujeme přes ukazatel k proměnné mimo oblast její viditelnosti:

 
fn main() {
    let pointer: *mut i32;
 
    {
        let mut value: i32 = 42;
 
        pointer = &mut value;
 
        println!("{}", value);
        unsafe {
            println!("{}", *pointer);
        }
 
        value = 1;
 
        println!("{}", value);
        unsafe {
            println!("{}", *pointer);
        }
 
        unsafe {
            *pointer = 20;
        }
        println!("{}", value);
        unsafe {
            println!("{}", *pointer);
        }
    }
 
    // !!!
    unsafe {
        *pointer = 99;
        println!("{}", *pointer);
    }
}

Poznámka: toto je asi největší praktický rozdíl mezi referencemi a ukazateli.

12. Ukazatel na datovou strukturu

Ukazatel samozřejmě nemusí obsahovat jen adresu primitivní proměnné, ale i adresu datové struktury. Opět se na chvíli vraťme k naší struktuře s komplexními čísly, jejíž nejjednodušší varianta vypadá takto:

#[derive(Debug)]
struct Complex {
    real: f32,
    imag: f32,
}
 
impl Complex {
    fn new(real: f32, imag: f32) -> Complex {
        println!("Constructing complex number: {:}+{:}i", real, imag);
        Complex{real:real, imag:imag}
    }
}

Nyní si můžeme vytvořit novou proměnnou typu Complex, deklarovat ukazatel na tuto datovou strukturu a naplnit ho. Pro zajímavost bude struktura měnitelná a tudíž si můžeme dovolit vytvořit i ukazatel typu *mut:

let mut value: Complex = Complex::new(1.0, 2.0);
let pointer: *mut Complex;
 
pointer = &mut value;

13. Přístup k prvkům struktury přes ukazatel

Změna složek datové struktury přímo (přes příslušnou proměnnou) je triviální:

value.real = 10.0;
value.imag = 20.0;

Totéž lze provést nepřímo přes ukazatel. Závorky pro dereferenci jsou nutné:

unsafe {
    (*pointer).real = 20.0;
    (*pointer).imag = 40.0;
}

Poznámka: kupodivu zde nelze použít operátor ->, což je škoda, protože mi připadá mnohem čitelnější.

Celý příklad, v němž se použije ukazatel na strukturu typu Complex, může vypadat takto:

bitcoin_skoleni

#[derive(Debug)]
struct Complex {
    real: f32,
    imag: f32,
}
 
impl Complex {
    fn new(real: f32, imag: f32) -> Complex {
        println!("Constructing complex number: {:}+{:}i", real, imag);
        Complex{real:real, imag:imag}
    }
}
 
fn main() {
    let mut value: Complex = Complex::new(1.0, 2.0);
    let pointer: *mut Complex;
 
    pointer = &mut value;
 
    println!("{:?}", value);
    unsafe {
        println!("{:?}", *pointer);
    }
 
    value.real = 10.0;
    value.imag = 20.0;
 
    println!("{:?}", value);
    unsafe {
        println!("{:?}", *pointer);
    }
 
    unsafe {
        (*pointer).real = 20.0;
        (*pointer).imag = 40.0;
    }
    println!("{:?}", value);
    unsafe {
        println!("{:?}", *pointer);
    }
}

14. Repositář s demonstračními příklady

Všechny dnes popisované demonstrační příklady byly, ostatně podobně jako ve všech předchozích částech tohoto seriálu, uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/pre­sentations. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář:

Další příklady byly připraveny pro navazující část tohoto seriálu, takže jen pro úplnost:

15. Odkazy na Internetu

  1. Primitive Type pointer
    https://doc.rust-lang.org/std/primitive.pointer.html
  2. Cargo: správce projektů a balíčků pro programovací jazyk Rust
    https://mojefedora.cz/cargo-spravce-projektu-a-balicku-pro-programovaci-jazyk-rust/
  3. Network Communication and Serialization in Rust
    https://www.safaribookson­line.com/blog/2014/01/28/net­work-communication-serialization-rust/
  4. Crate bincode
    http://tyoverby.com/binco­de/bincode/index.html
  5. Struct std::fs::File
    https://doc.rust-lang.org/std/fs/struct.File.html
  6. Trait std::io::Seek
    https://doc.rust-lang.org/std/io/trait.Seek.html
  7. Trait std::io::Read
    https://doc.rust-lang.org/std/io/trait.Read.html
  8. Trait std::io::Write
    https://doc.rust-lang.org/std/io/trait.Write.html
  9. Trait std::io::BufRead
    https://doc.rust-lang.org/std/io/trait.BufRead.html
  10. Module std::io::prelude
    https://doc.rust-lang.org/std/io/prelude/index.html
  11. std::net::IpAddr
    https://doc.rust-lang.org/std/net/enum.IpAddr.html
  12. std::net::Ipv4Addr
    https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html
  13. std::net::Ipv6Addr
    https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html
  14. TcpListener
    https://doc.rust-lang.org/std/net/struct.TcpLis­tener.html
  15. TcpStream
    https://doc.rust-lang.org/std/net/struct.TcpStream.html
  16. Binary heap (Wikipedia)
    https://en.wikipedia.org/wi­ki/Binary_heap
  17. Binární halda (Wikipedia)
    https://cs.wikipedia.org/wi­ki/Bin%C3%A1rn%C3%AD_halda
  18. Halda (datová struktura)
    https://cs.wikipedia.org/wi­ki/Halda_%28datov%C3%A1_struk­tura%29
  19. Struct std::collections::HashSet
    https://doc.rust-lang.org/std/collections/struc­t.HashSet.html
  20. Struct std::collections::BTreeSet
    https://doc.rust-lang.org/std/collections/struc­t.BTreeSet.html
  21. Struct std::collections::BinaryHeap
    https://doc.rust-lang.org/std/collections/struc­t.BinaryHeap.html
  22. Set (abstract data type)
    https://en.wikipedia.org/wi­ki/Set_%28abstract_data_ty­pe%29#Language_support
  23. Associative array
    https://en.wikipedia.org/wi­ki/Associative_array
  24. Hash Table
    https://en.wikipedia.org/wi­ki/Hash_table
  25. B-tree
    https://en.wikipedia.org/wiki/B-tree
  26. Pedro Celis: Robin Hood Hashing (naskenované PDF!)
    https://cs.uwaterloo.ca/re­search/tr/1986/CS-86–14.pdf
  27. Robin Hood hashing
    http://codecapsule.com/2013/11/11/ro­bin-hood-hashing/
  28. Robin Hood hashing: backward shift deletion
    http://codecapsule.com/2013/11/17/ro­bin-hood-hashing-backward-shift-deletion/
  29. Module std::collections
    https://doc.rust-lang.org/std/collections/
  30. Module std::vec
    https://doc.rust-lang.org/nightly/std/vec/index.html
  31. Struct std::collections::VecDeque
    https://doc.rust-lang.org/std/collections/struc­t.VecDeque.html
  32. Struct std::collections::LinkedList
    https://doc.rust-lang.org/std/collections/struc­t.LinkedList.html
  33. Module std::fmt
    https://doc.rust-lang.org/std/fmt/
  34. Macro std::println
    https://doc.rust-lang.org/std/macro.println.html
  35. Enum std::result::Result
    https://doc.rust-lang.org/std/result/enum.Result.html
  36. Module std::result
    https://doc.rust-lang.org/std/result/
  37. Result
    http://rustbyexample.com/std/re­sult.html
  38. Rust stdlib: Option
    https://doc.rust-lang.org/std/option/enum.Option.html
  39. Module std::option
    https://doc.rust-lang.org/std/option/index.html
  40. Rust by example: option
    http://rustbyexample.com/std/op­tion.html
  41. Rust by example: if-let
    http://rustbyexample.com/flow_con­trol/if_let.html
  42. Rust by example: while let
    http://rustbyexample.com/flow_con­trol/while_let.html
  43. Rust by example: Option<i32>
    http://rustbyexample.com/std/op­tion.html
  44. An Overview of Macros in Rust
    http://words.steveklabnik.com/an-overview-of-macros-in-rust
  45. A Practical Intro to Macros in Rust 1.0
    https://danielkeep.github.io/practical-intro-to-macros.html
  46. The Rust Programming Language: macros
    https://doc.rust-lang.org/beta/book/macros.html
  47. Rust by example: 15 macro_rules!
    http://rustbyexample.com/macros.html
  48. Primitive Type isize
    https://doc.rust-lang.org/nightly/std/primi­tive.isize.html
  49. Primitive Type usize
    https://doc.rust-lang.org/nightly/std/primi­tive.usize.html
  50. Primitive Type array
    https://doc.rust-lang.org/nightly/std/primi­tive.array.html
  51. Module std::slice
    https://doc.rust-lang.org/nightly/std/slice/
  52. Rust by Example: 2.3 Arrays and Slices
    http://rustbyexample.com/pri­mitives/array.html
  53. What is the difference between Slice and Array (stackoverflow)
    http://stackoverflow.com/qu­estions/30794235/what-is-the-difference-between-slice-and-array
  54. Learning Rust With Entirely Too Many Linked Lists
    http://cglab.ca/~abeinges/blah/too-many-lists/book/
  55. Testcase: linked list
    http://rustbyexample.com/cus­tom_types/enum/testcase_lin­ked_list.html
  56. Operators and Overloading
    https://doc.rust-lang.org/book/operators-and-overloading.html
  57. Module std::ops
    https://doc.rust-lang.org/std/ops/index.html
  58. Module std::cmp
    https://doc.rust-lang.org/std/cmp/index.html
  59. Trait std::ops::Add
    https://doc.rust-lang.org/stable/std/ops/trait.Add.html
  60. Trait std::ops::AddAssign
    https://doc.rust-lang.org/std/ops/trait.AddAssign.html
  61. Trait std::ops::Drop
    https://doc.rust-lang.org/std/ops/trait.Drop.html
  62. Trait std::cmp::Eq
    https://doc.rust-lang.org/std/cmp/trait.Eq.html
  63. Struct std::boxed::Box
    https://doc.rust-lang.org/std/boxed/struct.Box.html
  64. Explore the ownership system in Rust
    https://nercury.github.io/rus­t/guide/2015/01/19/ownership­.html
  65. Rust's ownership and move semantic
    http://www.slideshare.net/sa­neyuki/rusts-ownership-and-move-semantics
  66. Trait std::marker::Copy
    https://doc.rust-lang.org/stable/std/marker/tra­it.Copy.html
  67. Trait std::clone::Clone
    https://doc.rust-lang.org/stable/std/clone/tra­it.Clone.html
  68. The Stack and the Heap
    https://doc.rust-lang.org/book/the-stack-and-the-heap.html
  69. Rust Compare: Pointers & References
    http://www.rust-compare.com/site/pointers.html
  70. Rust Compare: Parameters
    http://www.rust-compare.com/site/params.html
  71. Why does this compile? Automatic dereferencing?
    https://users.rust-lang.org/t/why-does-this-compile-automatic-dereferencing/2183
  72. Understanding Pointers, Ownership, and Lifetimes in Rust
    http://koerbitz.me/posts/Understanding-Pointers-Ownership-and-Lifetimes-in-Rust.html
  73. Rust lang series episode #25 — pointers (#rust-series)
    https://steemit.com/rust-series/@jimmco/rust-lang-series-episode-25-pointers-rust-series
  74. Rust – home page
    https://www.rust-lang.org/en-US/
  75. Rust – Frequently Asked Questions
    https://www.rust-lang.org/en-US/faq.html
  76. Destructuring and Pattern Matching
    https://pzol.github.io/get­ting_rusty/posts/20140417_des­tructuring_in_rust/
  77. The Rust Programming Language
    https://doc.rust-lang.org/book/
  78. Rust (programming language)
    https://en.wikipedia.org/wi­ki/Rust_%28programming_lan­guage%29
  79. Go – home page
    https://golang.org/
  80. Stack Overflow – Most Loved, Dreaded, and Wanted language
    https://stackoverflow.com/re­search/developer-survey-2016#technology-most-loved-dreaded-and-wanted
  81. Rust vs Go (dva roky staré hodnocení, od té doby došlo k posunům v obou jazycích)
    http://jaredforsyth.com/2014/03/22/rust-vs-go/
  82. Rust vs Go: My experience
    https://www.reddit.com/r/go­lang/comments/21m6jq/rust_vs_go_my_ex­perience/
  83. Friends of Rust (Organizations running Rust in production)
    https://www.rust-lang.org/en-US/friends.html
  84. Rust programs versus C++ g++
    https://benchmarksgame.ali­oth.debian.org/u64q/compa­re.php?lang=rust&lang2=gpp
  85. Další benchmarky (nejedná se o reálné příklady „ze života“)
    https://github.com/kostya/benchmarks
  86. Go na Redditu
    https://www.reddit.com/r/golang/
  87. Rust vs. Go
    http://vschart.com/compare/rust/vs/go-language
  88. Abstraction without overhead: traits in Rust
    https://blog.rust-lang.org/2015/05/11/traits.html
  89. Method Syntax
    https://doc.rust-lang.org/book/method-syntax.html
  90. Traits in Rust
    https://doc.rust-lang.org/book/traits.html
  91. Functional Programming in Rust – Part 1 : Function Abstraction
    http://blog.madhukaraphatak­.com/functional-programming-in-rust-part-1/
  92. Of the emerging systems languages Rust, D, Go and Nim, which is the strongest language and why?
    https://www.quora.com/Of-the-emerging-systems-languages-Rust-D-Go-and-Nim-which-is-the-strongest-language-and-why
  93. Chytré ukazatele (moderní verze jazyka C++) [MSDN]
    https://msdn.microsoft.com/cs-cz/library/hh279674.aspx
  94. UTF-8 Everywhere
    http://utf8everywhere.org/
  95. Rust by Example
    http://rustbyexample.com/
  96. Rust oficiálně ve Fedoře
    https://mojefedora.cz/rust-oficialne-ve-fedore/
  97. Resource acquisition is initialization
    https://en.wikipedia.org/wi­ki/Resource_acquisition_is_i­nitialization
  98. TIOBE index (nejnovější data)
    http://www.tiobe.com/tiobe-index/
  99. Porovnání Go, D a Rustu na OpenHubu:
    https://www.openhub.net/lan­guages/compare?language_na­me[]=-1&language_name[]=-1&language_name[]=dmd&lan­guage_name[]=golang&langu­age_name[]=rust&language_na­me[]=-1&measure=commits
  100. String Types in Rust
    http://www.suspectsemantic­s.com/blog/2016/03/27/str­ing-types-in-rust/
  101. Trait (computer programming)
    https://en.wikipedia.org/wi­ki/Trait_%28computer_program­ming%29
  102. Type inference
    https://en.wikipedia.org/wi­ki/Type_inference

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.