Obsah
1. Vytvoření nového vektoru makrem vec!
2. Měnitelný a neměnitelný vektor
3. Indexování prvků vektoru a typ usize
4. Získání iterátoru pro vektory a průchod všemi prvky vektoru
6. Modifikace prvků vektoru přes slice
8. Nastavení kapacity vektoru, zmenšení vektoru na základě skutečného počtu prvků
9. Vytvoření nového vektoru z iterátoru
10. Vytvoření nového vektoru z kolekce
11. Vytvoření nového vektoru z objektu typu range
12. Vektor obsahující další vektory
15. Repositář s demonstračními příklady
1. Vytvoření nového vektoru makrem vec!
Jak jsme se dozvěděli minule, obsahuje programovací jazyk Rust podporu pro pole (array), která jsou zde dokonce považována za primitivní datový typ. Připomeňme si, že pole se může alokovat na zásobníku, překladač potřebuje znát počet prvků pole již při překladu, z polí lze vytvářet řezy (slices), délka polí se zjišťuje metodou len() a pro pole lze mj. získat i iterátor, a to konkrétně metodou iter().
V mnoha případech je však zapotřebí používat takové homogenní datové struktury, u nichž je možné v době běhu programu měnit počet prvků, tj. prvky přidávat a ubírat (navíc by všechny operace měly mít složitost O(1)). Takovou strukturou jsou v programovacím jazyku Rust objekty typu Vec nazývané vektory. Interně Vec obsahuje několik atributů, především kapacitu vektoru, počet prvků vektoru (může být menší než kapacita) a taktéž ukazatel na vlastní prvky, které jsou však umístěny na haldě (dokonce musí být na haldě, protože překladač nezná délku vektoru). Vektory lze vytvořit konstruktorem Vec::new(), ovšem častěji uvidíme použití makra vec!. Podívejme se, jak lze vytvořit vektor s pěti prvky, jejichž typ překladač použije pro odvození typu vektoru. V příkladu je ukázáno i indexování prvků a použití metody len() pro zjištění aktuální délky vektoru:
fn main() { let vector = vec![1, 2, 3, 4, 5]; println!("vector has {} items", vector.len()); for i in 0..vector.len() { println!("item #{} = {}", i+1, vector[i]); } }
Výsledek běhu programu:
vector has 5 items item #1 = 1 item #2 = 2 item #3 = 3 item #4 = 4 item #5 = 5
Alternativně je možné všechny prvky nastavit na stejnou hodnotu, a to použitím stejné syntaxe, jakou známe z článku o polích – [hodnota;počet_prvků]:
fn main() { let vector = vec![1; 10]; println!("vector has {} items", vector.len()); for i in 0..vector.len() { println!("item #{} = {}", i+1, vector[i]); } }
Výsledek běhu programu:
vector has 10 items item #1 = 1 item #2 = 1 item #3 = 1 item #4 = 1 item #5 = 1 item #6 = 1 item #7 = 1 item #8 = 1 item #9 = 1 item #10 = 1
2. Měnitelný a neměnitelný vektor
Podobně jako u polí platí, že vektory jsou implicitně neměnitelné (immutable), což znamená, že ve chvíli, kdy je vektor vytvořen a přiřazen do proměnné, už nelze měnit hodnoty jeho prvků či počet prvků. Z tohoto důvodu je následující příklad nekorektní:
fn main() { let vector = vec![1; 10]; println!("vector has {} items", vector.len()); print!("["); for i in 0..vector.len() { print!("{} ", vector[i]); } println!("]"); vector[5] = 100; print!("["); for i in 0..vector.len() { print!("{} ", vector[i]); } println!("]"); }
Překlad skončí s chybou nalezenou na řádku, kde se pokoušíme modifikovat prvek vektoru:
error: cannot borrow immutable local variable `vector` as mutable --> 155_immutable_vector.rs:12:5 | 2 | let vector = vec![1; 10]; | ------ use `mut vector` here to make mutable ... 12 | vector[5] = 100; | ^^^^^^ cannot borrow mutably error: aborting due to previous error
Oprava programu je snadná – postačuje použít nám již známý modifikátor mut, a to následovně:
fn main() { let mut vector = vec![1; 10]; println!("vector has {} items", vector.len()); print!("["); for i in 0..vector.len() { print!("{} ", vector[i]); } println!("]"); vector[5] = 100; print!("["); for i in 0..vector.len() { print!("{} ", vector[i]); } println!("]"); }
Nyní je již možné příklad přeložit a spustit s následujícím výsledkem (prvek byl skutečně modifikován):
vector has 10 items [1 1 1 1 1 1 1 1 1 1 ] [1 1 1 1 1 100 1 1 1 1 ]
3. Indexování prvků vektoru a typ usize
Přístup k prvkům vektorů s využitím celočíselného indexu je jednoduchý a už jsme si ho vlastně ukázali v předchozích příkladech. Takže jen pro ilustraci, jak lze přistoupit ke třetímu prvku (s indexem rovným dvěma):
fn main() { let vector = vec![1, 2, 3, 4, 5]; let index = 2; let item = vector[index]; println!("vector[5] == {}", item); }
Předchozí příklad byl přeložen v pořádku, ale pokud se pokusíme o použití celočíselné konstanty některého z typů integer (například i32, tedy 32bitový integer se znaménkem), dojde při překladu k chybě:
fn main() { let vector = vec![1, 2, 3, 4, 5]; let index = 2i32; let item = vector[index]; println!("vector[5] == {}", item); }
Chyba při překladu:
error[E0277]: the trait bound `std::vec::Vec<{integer}>: std::ops::Index<i32>` is not satisfied --> 158_vector_integer_index.rs:5:16 | 5 | let item = vector[index]; | ^^^^^^^^^^^^^ | = note: the type `std::vec::Vec<{integer}>` cannot be indexed by `i32` error: aborting due to previous error
Podobně dopadneme ve chvíli, kdy specifikujeme typ proměnné obsahující index (což je vlastně to samé):
fn main() { let vector = vec![1, 2, 3, 4, 5]; let index:i32 = 2; let item = vector[index]; println!("vector[5] == {}", item); }
Problém spočívá v tom, že vektory implementují trait Index<usize>, aby vůbec bylo možné použít syntaxi vektor[index_prvku]. A právě kvůli tomu je nutné pro indexaci použít hodnotu typu usize (dokonce ani není možné použít isize). Následující dvojice příkladů je tedy korektní:
fn main() { let vector = vec![1, 2, 3, 4, 5]; let index:usize = 2; let item = vector[index]; println!("vector[5] == {}", item); }
Povšimněte si, že u číselných proměnných lze jejich typ přesně specifikovat zápisem typu proměnné ihned za číselnou konstantou, která je do proměnné přiřazována:
fn main() { let vector = vec![1, 2, 3, 4, 5]; let index = 2usize; let item = vector[index]; println!("vector[5] == {}", item); }
Poznámka: vektory ve skutečnosti implementují dva podobně pojmenované traity Index a IndexMut. První trait se používá ve chvíli, kdy se prvek čte, druhý se používá při zápisu (modifikaci, mutaci):
let x = vector[10]; vector[20] = x;
4. Získání iterátoru pro vektory a průchod všemi prvky vektoru
Podobně jako u polí lze i pro vektory získat iterátor metodou iter(). Idiomatický zápis smyčky, v níž se prochází všemi prvky vektoru, vypadá takto:
fn main() { let vector = vec![1, 2, 3, 4, 5]; println!("vector has {} items", vector.len()); for item in vector.iter() { println!("{}", item); } }
Vektory mají s poli společnou i další vlastnost – iterátor lze získat zápisem &vektor. Přitom nedojde ke změně vlastníka vektoru:
fn main() { let vector = vec![1, 2, 3, 4, 5]; println!("vector has {} items", vector.len()); for item in &vector { println!("{}", item); } }
Zatímco u polí byl předchozí zápis omezen pouze na pole s maximální velikostí 32 prvků, u vektorů tomu tak není, o čemž se lze snadno přesvědčit:
fn main() { let vector = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; println!("vector has {} items", vector.len()); for item in &vector { println!("{}", item); } }
5. Řezy (slice) vektoru
Z vektorů je možné, podobně jako u polí, získat „řezy“ zápisem vektor[dolní_mez..horní_mez], přičemž platí, že v řezu je prvním prvkem prvek s indexem dolní_mez a posledním prvkem prvek s indexem horní_mez-1 – teoreticky by tedy zápis řezu měl vypadat takto: [dolní_mez..horní_mez), to by však pravděpodobně zmátlo textové editory, takže se tento zápis nepoužívá. Podívejme se na jednoduchý příklad získání řezu z desetiprvkového vektoru:
fn main() { let vector = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; println!("vector has {} items", vector.len()); let slice = vector[3..7]; println!("slice has {} items", slice.len()); for item in slice { println!("{}", item); } }
Překlad tohoto příkladu se však nepovede:
error[E0277]: the trait bound `[{integer}]: std::marker::Sized` is not satisfied --> 165_slice_incorrect.rs:6:9 | 6 | let slice = vector[3..7]; | ^^^^^ | = note: `[{integer}]` does not have a constant size known at compile-time = note: all local variables must have a statically known size
Chybové hlášení je sice poněkud kryptické, ale říká nám, že překladač není schopen odvodit velikost výsledné struktury. Pomůže nám maličkost (opět stejně jako u polí) – použít &, takže řez bude ukazovat do existujícího vektoru:
fn main() { let vector = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; println!("vector has {} items", vector.len()); let slice = &vector[3..7]; println!("slice has {} items", slice.len()); for item in slice { println!("{}", item); } }
Výsledek běhu programu:
vector has 10 items slice has 4 items 4 5 6 7
6. Modifikace prvků vektoru přes slice
V diskuzi u předchozího článku zazněl dotaz (a správné odpovědi), jak je to s modifikací původního pole přes řez. Podívejme se nyní na toto téma z pohledu vektorů. Například získáme řez z desetiprvkového vektoru a budeme se snažit změnit hodnotu prvku přes tento řez:
fn main() { let mut vector = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; println!("vector has {} items", vector.len()); let mut slice = &vector[3..7]; slice[1] = 100; for item in &vector { println!("{}", item); } }
Proměnná slice je sice označena modifikátorem mut, to ovšem znamená, že do proměnné lze přiřadit jiný řez a nikoli to, že obsah samotného řezu (a tedy i vektoru) je měnitelný:
error: cannot assign to immutable indexed content `slice[..]` --> 167_modify_via_slice_incorrect.rs:7:5 | 7 | slice[1] = 100; | ^^^^^^^^^^^^^^ error: aborting due to previous error
Následující příklad již sice správně používá &mut (tj. prvek vektoru lze přes řez změnit), ovšem nesmíme zapomenout na to, že se v tomto případě změní i vlastník vektoru, což způsobí problém při překladu programové smyčky:
fn main() { let mut vector = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; println!("vector has {} items", vector.len()); let slice = &mut vector[3..7]; slice[1] = 100; for item in &vector { println!("{}", item); } }
error[E0502]: cannot borrow `vector` as immutable because it is also borrowed as mutable --> 168_modify_via_slice_incorrect2.rs:9:18 | 6 | let slice = &mut vector[3..7]; | ------ mutable borrow occurs here ... 9 | for item in &vector { | ^^^^^^ immutable borrow occurs here ... 12 | } | - mutable borrow ends here error: aborting due to previous error
Jedno z možných řešení (či možná lépe řečeno obejití) tohoto problému spočívá v omezení viditelnosti proměnné slice pomocí programového bloku:
fn main() { let mut vector = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; println!("vector has {} items", vector.len()); { let slice = &mut vector[3..7]; slice[1] = 100; } for item in &vector { println!("{}", item); } }
Výsledek běhu programu:
vector has 10 items 1 2 3 4 100 6 7 8 9 10
7. Operace push a pop
V úvodní kapitole jsme si řekli, že počet prvků vektoru může růst či klesat, protože jsou podporovány dvě operace nazvané push() a pop(), které dokážou na konec vektoru přidat nový prvek popř. tento prvek odebrat. Je to umožněno díky tomu, že prvky vektoru jsou umístěny na haldu a vektor může v případě potřeby růst. Pokud má vektor dostatečnou kapacitu, mají tyto operace složitost O(1), což je samozřejmě příjemné. Podívejme se na velmi jednoduchý příklad použití:
fn main() { let mut vector = vec![]; for i in 0..10 { vector.push(2*i); } println!("vector has {} items", vector.len()); for item in &vector { println!("{}", item); } for _ in 0..5 { vector.pop(); } println!("-------------------------"); for item in &vector { println!("{}", item); } }
Výsledek běhu programu:
vector has 10 items 0 2 4 6 8 10 12 14 16 18 ------------------------- 0 2 4 6 8
8. Nastavení kapacity vektoru, zmenšení vektoru na základě skutečného počtu prvků
Aby bylo přidávání prvků na konec vektoru efektivní, je zapotřebí zajistit, aby měl vektor potřebnou kapacitu pro přidávání prvků. Pokud totiž bude kapacita vektoru překročena, dojde k jejímu zvětšení, což je již složitější operace, které se většinou budeme chtít vyhnout. V případě, že je počet prvků vektoru dopředu alespoň přibližně známý, je možné vektor vytvořit již s potřebnou kapacitou, a to konkrétně konstruktorem Vec::with_capacity(počet_předalokovaných_prvků). Pokud zadáte příliš velkou počáteční kapacitu, bude se zbytečně alokovat paměť na haldě, na druhou stranu se zaručí, že se vektor nebude realokovat. Kapacitu je možné zjistit snadno metodou capacity(). Tato hodnota by měla být větší nebo rovna hodnotě vrácené metodou len():
fn main() { let mut vector = Vec::with_capacity(10); println!("vector has capacity for {} items", vector.capacity()); println!("vector has {} items", vector.len()); for i in 0..10 { vector.push(2*i); } println!("vector has {} items", vector.len()); for item in &vector { println!("{}", item); } for _ in 0..5 { vector.pop(); } println!("-------------------------"); for item in &vector { println!("{}", item); } }
Výsledek běhu programu:
vector has capacity for 10 items vector has 0 items vector has 10 items 0 2 4 6 8 10 12 14 16 18 ------------------------- 0 2 4 6 8
V případě potřeby lze kapacitu vektoru kdykoli zmenšit na nejmenší možnou velikost odpovídající počtu skutečně vložených prvků. Změnu velikosti zajistí metoda shrink_to_fit(), která však provádí realokaci, a proto ji většinou není vhodné volat příliš často:
fn main() { let mut vector = Vec::with_capacity(10); println!("vector has capacity for {} items", vector.capacity()); println!("vector has {} items", vector.len()); for i in 0..10 { vector.push(2*i); } println!("vector has {} items", vector.len()); for item in &vector { println!("{}", item); } for _ in 0..5 { vector.pop(); } println!("-------------------------"); vector.shrink_to_fit(); println!("vector has capacity for {} items", vector.capacity()); println!("vector has {} items", vector.len()); for item in &vector { println!("{}", item); } }
Výsledek ukazuje, že se kapacita vektoru skutečně zmenšila na pouhých pět prvků:
vector has capacity for 10 items vector has 0 items vector has 10 items 0 2 4 6 8 10 12 14 16 18 ------------------------- vector has capacity for 5 items vector has 5 items 0 2 4 6 8
U vektorů vytvořených konstruktorem Vec::with_capacity() dokáže překladač odvodit typ prvků z prvního přiřazení, což mj. znamená, že následující příklad nebude přeložen, protože se do vektoru snažíme uložit prvky nekompatibilních typů:
fn main() { let mut vector = Vec::with_capacity(10); vector.push(10.0); vector.push(10); println!("vector has {} items", vector.len()); }
Samozřejmě není problém zapsat typ prvků explicitně:
fn main() { let mut vector : Vec<i8> = Vec::with_capacity(10); vector.push(10); vector.push(100); vector.push(1000); println!("vector has {} items", vector.len()); }
Zde překladač pouze vypíše varování, že se snažíme uložit příliš velkou hodnotu 1000 do prvku typu i8.
9. Vytvoření nového vektoru z iterátoru
V případě potřeby je možné vektor vytvořit z iterátoru, a to metodou from_iter(). V následujícím příkladu je iterátor tvořen sekvencí čísel od 1 do 9, v praxi však samozřejmě nejsme omezeni na to, jak a čím je iterátor vytvořen (typ generovaných prvků je známý při překladu):
use std::iter::FromIterator; fn main() { let vector = Vec::from_iter(1..10); println!("vector has {} items", vector.len()); for item in &vector { println!("{}", item); } }
10. Vytvoření nového vektoru z kolekce
Velmi užitečný je i další způsob převedení iterátoru či kolekce na vektor, a to konkrétně metodou collect(). Nejprve se podívejme na převod pole→iterátor→vektor:
fn main() { let array = [1, 2, 3, 4, 5]; let vector:Vec<_> = array.iter().collect(); println!("vector has {} items", vector.len()); for item in &vector { println!("{}", item); } }
Připomeňme si, že v Rustu je možné použít i funkce vyššího řádu, například map, filter, take či take_while, takže lze převody mezi různými kolekcemi vyřešit funkcionálním stylem, například:
fn main() { let array = [1, 2, 3, 4, 5]; let vector:Vec<_> = array.iter().map(|x| x*2).collect(); println!("vector has {} items", vector.len()); for item in &vector { println!("{}", item); } }
Příklad použití kombinace take+filter+map s následným převodem na vektor:
fn main() { let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; let vector:Vec<_> = array.iter() .take(10) .filter(|&x| x % 3 ==0) .map(|&x| x*2) .collect(); println!("vector has {} items", vector.len()); for item in &vector { println!("{}", item); } }
Samozřejmě je možné explicitně specifikovat jak typ vstupní kolekce, tak i typ prvků vektoru:
fn main() { let array:[i32;15] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; let vector:Vec<i32> = array.iter() .take(10) .filter(|&x| x % 3 ==0) .map(|&x| x*2) .collect(); println!("vector has {} items", vector.len()); for item in &vector { println!("{}", item); } }
Výsledkem bude:
vector has 3 items 6 12 18
Tedy prvky dělitelné třemi z prvních deseti prvků pole, které jsou následně vynásobeny dvěma.
11. Vytvoření nového vektoru z objektu typu range
Vektor je možné vytvořit i z objektu typu range, zadaný rozsah však musíme uzavřít do kulatých závorek (záležitost syntaxe):
fn main() { let vector:Vec<_> = (0..10).collect(); println!("vector has {} items", vector.len()); for item in &vector { println!("{}", item); }
Povšimněte si, že jak s vektorem, tak i s poli je možné pracovat naprosto stejným způsobem, pokud k nim přistupujeme přes referenci či řez:
fn print_slice(slice :&[i32]) { print!("["); for i in slice { print!("{} ", i); } println!("]"); } fn main() { let array1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let array2 = [1; 10]; let vector:Vec<_> = (0..10).collect(); print_slice(&array1); print_slice(&array2); print_slice(&vector); }
Výsledek běhu programu:
[0 1 2 3 4 5 6 7 8 9 ] [1 1 1 1 1 1 1 1 1 1 ] [0 1 2 3 4 5 6 7 8 9 ]
12. Vektor obsahující další vektory
Poměrně často se setkáme s požadavkem, aby vektor obsahoval jako své prvky další vektory. Díky typovému systému programovacího jazyka Rust je to samozřejmě možné, protože vektory jsou plnohodnotným datovým typem. Výsledné „dvourozměrné vektory“ se od dvourozměrných polí odlišují jak způsobem alokace (zásobník versus halda), tak i tím, že výsledná datová struktura složená z vektorů nemusí být obdélníková, tj. vektory mohou mít rozdílnou a navíc i v čase proměnnou délku. Podívejme se, jak se deklaruje typ proměnné s vektorem obsahujícím další vektory:
let vec2:Vec<Vec<typ_prvků>>
V některých případech se můžeme spolehnout na typovou inferenci a typ prvků explicitně neudávat (což použijeme v demonstračním příkladu):
let vec2:Vec<Vec<_>>
Při přístupu k prvkům lze použít běžné indexování:
println!("{}", vec2[2][1])
V příkladu namísto explicitního indexování použijeme iteraci přes všechny prvky vektoru. Víme již, že prvky jsou taktéž vektory a i pro ně lze získat iterátor, takže výpis „vektoru vektorů“ je vlastně velmi jednoduchý:
fn main() { let vec2:Vec<Vec<_>> = vec![vec![1,2,3], vec![4], vec![5,6,7,8,]]; println!("vector has {} items", vec2.len()); for vec1 in vec2.iter() { for i in vec1.iter() { print!("{} ", i); } println!(""); } }
Výsledek běhu programu:
vector has 3 items 1 2 3 4 5 6 7 8
13. Vektor obsahující pole
Možné jsou samozřejmě i další kombinace, například vektor obsahující pole. V takovém případě je nutné správně zapsat datový typ prvků vektoru, protože překladač Rustu vyžaduje znalost typů a počtu prvků polí vkládaných do vektoru. Připomeňme si z předchozího článku, že typ pole se zapisuje [typ_prvku;počet_prvků]. V následujícím demonstračním příkladu je zajímavé, že samotné vnořené programové smyčky jsou vlastně totožné s předchozím příkladem, protože iterátory lze použít jak u polí, tak i u vektorů (a samozřejmě nejenom pro tyto datové struktury):
fn main() { let vec2:Vec<[i32;3]> = vec![[1,2,3], [4,5,6], [7,8,9]]; println!("vector has {} items", vec2.len()); for array in vec2.iter() { for i in array.iter() { print!("{} ", i); } println!(""); } }
Výsledek běhu programu:
vector has 3 items 1 2 3 4 5 6 7 8 9
14. Pole obsahující vektory
Poslední možnou kombinací je pole obsahující vektory (první kombinaci – pole polí – jsme si popsali již minule). Vzhledem k tomu, že již víme, že typ pole se zapisuje formou [typ_prvku;počet_prvků], nebude pro nás žádným problémem za typ_prvku dosadit například Vec<i32> atd. Opět si povšimněte toho, že výpis obsahu takto vytvořené datové struktury je zcela totožný, jako v obou předchozích příkladech:
fn main() { let array:[Vec<i32>;4] = [vec![1], vec![2,3], vec![4,5,6], vec![7,8,9,0]]; println!("array has {} items", array.len()); for vec1 in array.iter() { for i in vec1.iter() { print!("{} ", i); } println!(""); } }
Takto vytvořené pole vlastně obsahuje jednoduché objekty (struktury) s konstantní velikostí, které obsahují ukazatel na vlastní prvky vektoru umístěné na haldě.
Výsledek běhu programu:
array has 4 items 1 2 3 4 5 6 7 8 9 0
15. Repositář s demonstračními příklady
Všechny dnes popisované demonstrační příklady byly, 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/presentations. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář:
16. Odkazy na Internetu
- Module std::vec
https://doc.rust-lang.org/nightly/std/vec/index.html - Primitive Type isize
https://doc.rust-lang.org/nightly/std/primitive.isize.html - Primitive Type usize
https://doc.rust-lang.org/nightly/std/primitive.usize.html - Primitive Type array
https://doc.rust-lang.org/nightly/std/primitive.array.html - Module std::slice
https://doc.rust-lang.org/nightly/std/slice/ - Rust by Example: 2.3 Arrays and Slices
http://rustbyexample.com/primitives/array.html - What is the difference between Slice and Array (stackoverflow)
http://stackoverflow.com/questions/30794235/what-is-the-difference-between-slice-and-array - Learning Rust With Entirely Too Many Linked Lists
http://cglab.ca/~abeinges/blah/too-many-lists/book/ - Testcase: linked list
http://rustbyexample.com/custom_types/enum/testcase_linked_list.html - Operators and Overloading
https://doc.rust-lang.org/book/operators-and-overloading.html - Module std::ops
https://doc.rust-lang.org/std/ops/index.html - Module std::cmp
https://doc.rust-lang.org/std/cmp/index.html - Trait std::ops::Add
https://doc.rust-lang.org/stable/std/ops/trait.Add.html - Trait std::ops::AddAssign
https://doc.rust-lang.org/std/ops/trait.AddAssign.html - Trait std::ops::Drop
https://doc.rust-lang.org/std/ops/trait.Drop.html - Trait std::cmp::Eq
https://doc.rust-lang.org/std/cmp/trait.Eq.html - Struct std::boxed::Box
https://doc.rust-lang.org/std/boxed/struct.Box.html - Explore the ownership system in Rust
https://nercury.github.io/rust/guide/2015/01/19/ownership.html - Rust's ownership and move semantic
http://www.slideshare.net/saneyuki/rusts-ownership-and-move-semantics - Trait std::marker::Copy
https://doc.rust-lang.org/stable/std/marker/trait.Copy.html - Trait std::clone::Clone
https://doc.rust-lang.org/stable/std/clone/trait.Clone.html - The Stack and the Heap
https://doc.rust-lang.org/book/the-stack-and-the-heap.html - Rust Compare: Pointers & References
http://www.rust-compare.com/site/pointers.html - Rust Compare: Parameters
http://www.rust-compare.com/site/params.html - Why does this compile? Automatic dereferencing?
https://users.rust-lang.org/t/why-does-this-compile-automatic-dereferencing/2183 - Understanding Pointers, Ownership, and Lifetimes in Rust
http://koerbitz.me/posts/Understanding-Pointers-Ownership-and-Lifetimes-in-Rust.html - Rust lang series episode #25 — pointers (#rust-series)
https://steemit.com/rust-series/@jimmco/rust-lang-series-episode-25-pointers-rust-series - Rust – home page
https://www.rust-lang.org/en-US/ - Rust – Frequently Asked Questions
https://www.rust-lang.org/en-US/faq.html - Destructuring and Pattern Matching
https://pzol.github.io/getting_rusty/posts/20140417_destructuring_in_rust/ - The Rust Programming Language
https://doc.rust-lang.org/book/ - Rust (programming language)
https://en.wikipedia.org/wiki/Rust_%28programming_language%29 - Go – home page
https://golang.org/ - Stack Overflow – Most Loved, Dreaded, and Wanted language
https://stackoverflow.com/research/developer-survey-2016#technology-most-loved-dreaded-and-wanted - 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/ - Rust vs Go: My experience
https://www.reddit.com/r/golang/comments/21m6jq/rust_vs_go_my_experience/ - Friends of Rust (Organizations running Rust in production)
https://www.rust-lang.org/en-US/friends.html - Rust programs versus C++ g++
https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=rust&lang2=gpp - Další benchmarky (nejedná se o reálné příklady „ze života“)
https://github.com/kostya/benchmarks - Go na Redditu
https://www.reddit.com/r/golang/ - Rust vs. Go
http://vschart.com/compare/rust/vs/go-language - Abstraction without overhead: traits in Rust
https://blog.rust-lang.org/2015/05/11/traits.html - Method Syntax
https://doc.rust-lang.org/book/method-syntax.html - Traits in Rust
https://doc.rust-lang.org/book/traits.html - Functional Programming in Rust – Part 1 : Function Abstraction
http://blog.madhukaraphatak.com/functional-programming-in-rust-part-1/ - 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 - Chytré ukazatele (moderní verze jazyka C++) [MSDN]
https://msdn.microsoft.com/cs-cz/library/hh279674.aspx - UTF-8 Everywhere
http://utf8everywhere.org/ - Rust by Example
http://rustbyexample.com/ - Rust oficiálně ve Fedoře
https://mojefedora.cz/rust-oficialne-ve-fedore/ - Resource acquisition is initialization
https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization - TIOBE index (October 2016)
http://www.tiobe.com/tiobe-index/ - Porovnání Go, D a Rustu na OpenHubu:
https://www.openhub.net/languages/compare?language_name[]=-1&language_name[]=-1&language_name[]=dmd&language_name[]=golang&language_name[]=rust&language_name[]=-1&measure=commits - String Types in Rust
http://www.suspectsemantics.com/blog/2016/03/27/string-types-in-rust/ - Trait (computer programming)
https://en.wikipedia.org/wiki/Trait_%28computer_programming%29 - Type inference
https://en.wikipedia.org/wiki/Type_inference