Obsah
1. Programovací jazyk Rust: knihovna ndarray pro práci s n-rozměrnými poli
2. Základní datový typ, na němž je postavena knihovna ndarray
4. Konverze vektoru na pole, vytvoření pole z iterátoru
5. Konstruktory pro nulové vektory a matice
6. Vytvoření jednotkové matice
7. Vytvoření jednorozměrného pole funkcí Array::range()
8. Vytvoření jednorozměrného pole funkcí Array::linspace()
9. Specifikace tvaru pole při jeho konstrukci z vektoru
11. Změna tvaru při konverzi polí
12. Zjištění délky, dimenze, tvaru a kroku mezi jednotlivými prvky pole
13. Repositář s demonstračními příklady
1. Programovací jazyk Rust: knihovna ndarray pro práci s n-rozměrnými poli
Jednou poměrně rozsáhlou oblastí v IT je zpracování vektorů a matic, protože s těmito strukturami se můžeme setkat v různých disciplínách, například ve finančnictví, pojišťovnictví, statistice, zpracování numerických dat, simulacích atd. Současně se jedná i o velmi zajímavou oblast, neboť právě kvůli co nejrychlejší práci s velkými maticemi byly vytvořeny speciální výpočetní bloky v některých superpočítačích (příkladem mohou být superpočítače Cray). Současné knihovny dokážou v případě potřeby využít jak některé rozšíření instrukčních sad (SIMD instrukce typu SSE, původně též MMX či 3DNow!, viz též úterní článek na toto téma), tak i programovatelné grafické akcelerátory (GPU). Práce s vektory a maticemi byla (a samozřejmě doposud je) podporována v překladačích FORTRANu, které začaly být po vzniku superpočítačů vybaveny algoritmy, které dokázaly převést některé typy programových smyček na „vektorové operace“. Paralelně vznikly i specializované jazyky určené téměř výhradně pro práci s vektory i maticemi – příkladem jsou jazyky APL a J.
V současnosti je používáno relativně velké množství programovacích jazyků popř. specializovaných knihoven orientovaných na práci s vektory a poli. Z komerčních nástrojů je zapotřebí jmenovat především známý MATLAB vydávaný společností MathWorks, nativní práci s maticemi a vektory ovšem velmi dobře podporuje také nástroj GNU Octave (https://gnu.org/software/octave/), jazyk R (http://www.r-project.org/) a také relativně nový jazyk Julia (http://julialang.org/, zajímavé výsledky benchmarků lze najít na adrese http://julialang.org/benchmarks/). Z knihoven jmenujme především oblíbenou a dnes dosti intenzivně využívanou Pythonovskou knihovnu NumPy (http://www.numpy.org/).
2. Základní datový typ, na němž je postavena knihovna ndarray
V knihovně ndarray se základní datová struktura taktéž jmenuje ndarray. Tato struktura ve své základní podobě reprezentuje pole o prakticky libovolném počtu dimenzí (ostatně „nd“ ve jménu „ndarray“ je odvozeno od N-dimensional). Tato pole se v některých ohledech odlišují od běžných rustovských polí, řezů i vektorů, což poznáme zejména ve chvíli, kdy se pokusíme změnit „tvar“ (shape) pole popř. z pole získat řez (slice). Ve skutečnosti se v knihovně ndarray setkáme i s takzvaným pohledem (view) na pole, který může být určen buď pouze pro čtení či pro čtení i zápis (což mj. v Rustu znamená, že i pole musí být měnitelné neboli mutable – tato podmínka je kontrolovaná překladačem). Samotná datová struktura ndarray je vždy homogenní, tj. může obsahovat pouze prvky stejného typu, ovšem tento typ může být prakticky libovolný. Tím se knihovna ndarray poněkud odlišuje například od známé knihovny Numpy určené pro Python, v níž je typ prvků n-dimenzionálních polí omezen.
3. Použití ndarray
Aby bylo možné používat dále popsané funkce, makra a traity, je nutné do projektového souboru (spravovaného systémem Cargo) přidat do sekce [dependencies] řádek s verzí knihovny ndarray. Současná verze je sice teprve 0.9.1, ovšem projekt se dostal do stabilního stavu:
[dependencies] ndarray = "0.9.1"
Dále na začátek všech zdrojových kódů přidejte následujících pět programových řádků, aby došlo k importu funkcí, struktur a traitů ze všech používaných modulů. Povšimněte si, že pro jednorozměrná, dvourozměrná, trojrozměrná atd. pole existují speciální moduly, které někdy nabízí unikátní funkce (eye() atd.):
extern crate ndarray; use ndarray::Array; use ndarray::Array1; use ndarray::Array2; use ndarray::Array3;
Poznámka: podobné moduly existují i pro čtyřrozměrná až pětirozměrná pole:
use ndarray::Array4; use ndarray::Array5; use ndarray::Array6;
Pokud navíc budete potřebovat použít dále popsané makro array!, je nutné toto makro povolit následující deklarací:
#[macro_use(array)]
4. Konverze vektoru na pole, vytvoření pole z iterátoru
V této kapitole i kapitolách navazujících si ukážeme, jakými způsoby se n-dimenzionální pole vytváří.
Pole typu ndarray je možné vytvořit několika různými způsoby. Základní funkcí sloužící k převodu z vektoru (ve smyslu programovacího jazyka Rust) na pole typu ndarray je funkce nazvaná jednoduše Array::from_vec(). Výsledkem bude pole, jehož prvky budou mít stejný typ, jako prvky zdrojového vektoru:
let array1 = Array::from_vec(vec![10, 9, 8, 1]); let array2 = Array::from_vec(vec![10.0, 9.0, 8.0, 1.0]);
Obě vzniklá pole vypadají na první pohled stejně, ovšem typy prvků jsou odlišné (celá čísla versus čísla s plovoucí řádovou čárkou):
[10, 9, 8, 1] [10, 9, 8, 1]
K prvkům polí se přistupuje běžným zápisem indexů do hranatých závorek:
println!("{}", array_c[5]);
Samozřejmě je možné pracovat i s vektory řetězců:
let array3 = Array::from_vec(vec!["www", "root", "cz"]);
S výsledkem:
[www, root, cz]
Dalším užitečným konstruktorem jednorozměrných polí je funkce nazvaná Array::from_iter(), která pole vytvoří z předaného iterátoru. Připomeňme si, že v programovacím jazyku Rust je nejjednodušším iterátorem range, který je možné zapsat přímo:
let array = Array::from_iter(0..10);
Výsledek:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Při povolení (stále ještě nestabilní) volby #![feature(inclusive_range_syntax)] lze u iterátoru použít z obou stran uzavřený interval namísto intervalu polouzavřeného. Povšimněte si použití tří teček namísto teček dvou:
let array_b = Array::from_iter(0...10);
Výsledné pole v tomto případě obsahuje i prvek 10:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I funkce vyššího řádu, mezi něž patří zejména filter() a map(), dokážou zpracovat iterátory, takže lze napsat:
let array_c = Array::from_iter((0...100).filter(|x| (x % 3 == 0))); let array_d = Array::from_iter((0...10).map(|x| (x * 42)));
S očekávaným výsledkem:
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99] [0, 42, 84, 126, 168, 210, 252, 294, 336, 378, 420]
Poznámka: funkcím filter() a map() jsem předal anonymní funkci, ale samozřejmě lze v případě potřeby použít i běžnou funkci odpovídající požadovanému rozhraní.
5. Konstruktory pro nulové vektory a matice
Poměrně často se setkáme s nutností vytvořit vektor či matici s nulovými prvky. V tomto případě samozřejmě není nutné složitě konstruovat a předávat rustovskévektory, ale lze namísto toho lze využít funkci nazvanou zeros deklarovanou pro jednorozměrná, dvourozměrná … atd. pole, což je rychlejší i méně paměťově náročnější. Pro jednorozměrné pole je nutné jen specifikovat typ prvků a požadovaný tvar (shape) pole, který v tomto případě odpovídá počtu prvků. Tvar se zadává n-ticí, v tomto případě obsahující jedinou hodnotu (10):
let array = Array1::<f32>::zeros((10));
Výsledek – jednorozměrné pole s deseti nulami:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Vzhledem k tomu, že tvar je u jednorozměrných polí představován jediným celým číslem, lze zápis zkrátit (o dvě závorky okolo desítky):
let array = Array1::<i8>::zeros(10);
Výsledek je v tomto případě naprosto stejný:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
U dvourozměrných polí se zadává počet řádků následovaný počtem prvků na řádku:
let array = Array2::<f32>::zeros((4, 3));
Výsledek:
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
U trojrozměrného pole musí mít n-tice specifikující tvar tři prvky – počet submatic, počet řádků každé matice a počet sloupců matice (tedy současně počet prvků na řádku):
let array = Array3::<f32>::zeros((4, 3, 2));
Výsledek:
[[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]]
Pozor – u dvou a vícerozměrných polí se při indexaci prvků používají dvojité závorky:
println!("{}", array[[0,0]]);
6. Vytvoření jednotkové matice
Speciální a často používanou maticí (tedy dvourozměrným polem se shodným počtem řádků a sloupců) je jednotková matice, pro jejíž konstrukci slouží funkce eye(), které se pouze předá velikost matice a navíc se specifikuje typ prvků vytvářeného pole. Výsledkem je pochopitelně pole se stejným počtem řádků i sloupců:
let array = Array2::<f32>::eye(4);
Výsledek:
[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
Použití jiného datového typu:
let array = Array2::<i8>::eye(10);
[[1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1]]
Použít lze jakýkoli datový typ implementující traity Zero a One.
7. Vytvoření jednorozměrného pole funkcí Array::range()
Jednorozměrné pole je možné vytvořit i s využitím funkce Array::range(), které se předávají tři parametry: počáteční mez intervalu (který je z levé strany uzavřen, tedy „včetně“), koncová mez intervalu (zde je otevřen, tedy „kromě“) a krok:
let array1 = Array::range(0.0, 10.0, 1.0); let array2 = Array::range(0.0, 10.0, 2.0); let array3 = Array::range(0.0, 10.0, 1.5);
Výsledek je předvídatelný:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 2, 4, 6, 8] [0, 1.5, 3, 4.5, 6, 7.5, 9]
V případě potřeby je možné zvolit i záporný krok; potom se samozřejmě musí prohodit i horní a dolní mez. Povšimněte si, že se stále jedná o polouzavřený interval, tj. pole nebude obsahovat prvek s druhou mezní hodnotou:
let array1 = Array::range(10.0, 0.0, -1.0); let array2 = Array::range(10.0, 0.0, -2.0); let array3 = Array::range(10.0, 0.0, -1.5);
Výsledky:
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1] [10, 8, 6, 4, 2] [10, 8.5, 7, 5.5, 4, 2.5, 1]
8. Vytvoření jednorozměrného pole funkcí Array::linspace()
V některých případech nemusí být použití výše popsané funkce Array::range() tím nejlepším řešením při vytváření vektoru obsahujícího sekvenci číselných hodnot. Typickým příkladem je sekvence generovaná s krokem 0.1, protože hodnotu 0.1 není možné formáty IEEE 754 single ani double přesně reprezentovat. Tím pádem nemusí být z volání funkce Array::range() ihned zřejmé, kolik prvků se nakonec vygeneruje (typická chyba ±1). Pokud je nutné vytvořit vektor s přesným počtem prvků, může se namísto Array::range() hodit spíše funkce Array::linspace(), které se předá počáteční hodnota, koncová hodnota a popř. i počet prvků vektoru. Použití funkce Array::linspace je tak ve skutečnosti velmi jednoduché a přirozené:
let array1 = Array::linspace(1.0, 10.0, 10); let array2 = Array::linspace(1.0, 10.0, 5); let array3 = Array::linspace(1.0, 10.0, 3);
S výsledky:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [1, 3.25, 5.5, 7.75, 10] [1, 5.5, 10]
Hodnoty prvního a posledního prvku můžeme klidně prohodit, na rozdíl od Array::range(), kde se současně musel změnit i krok:
let array1 = Array::linspace(10.0, 1.0, 10); let array2 = Array::linspace(10.0, 1.0, 5); let array3 = Array::linspace(10.0, 1.0, 3);
S výsledky:
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1] [10, 7.75, 5.5, 3.25, 1] [10, 5.5, 1]
9. Specifikace tvaru pole při jeho konstrukci z vektoru
Při vytváření pole z vektoru (ve smyslu programovacího jazyka Rust) je možné specifikovat tvar výsledného pole. Je ovšem nutné namísto funkce from_vec() použít funkci from_shape_vec(), které se navíc předá n-tice s požadovaným tvarem pole:
let array = Array::from_shape_vec((6), vec![1,2,3,4,5,6]).unwrap();
Tímto konstruktorem získáme jednorozměrné pole se šesti prvky:
[1, 2, 3, 4, 5, 6]
let array_b = Array::from_shape_vec((2,3), vec![1,2,3,4,5,6]).unwrap();
Nyní jsme získali dvourozměrné pole, opět se šesti prvky:
[[1, 2, 3], [4, 5, 6]]
let array_c = Array::from_shape_vec((3,2), vec![1,2,3,4,5,6]).unwrap();
Další pole, tentokrát se třemi řádky a jen dvěma sloupci:
[[1, 2], [3, 4], [5, 6]]
let array_d = Array::from_shape_vec((1,6), vec![1,2,3,4,5,6]).unwrap();
Nyní jsme požadovali pole s jedním řádkem a šesti sloupci – nejedná se však o 1D vektor:
[[1, 2, 3, 4, 5, 6]]
let array_e = Array::from_shape_vec((2,2,2), vec![1,2,3,4,5,6,7,8]).unwrap();
Trojrozměrné pole 2×2×2 prvky:
[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
10. Použití makra array!
Další možností, jak vytvořit pole libovolného rozměru (a typu), představuje použití makra array!, je však nutné toto makro povolit následující deklarací:
#[macro_use(array)]
Jakým způsobem se makro array! používá, je patrné z následujícího úryvku zdrojového kódu, v němž se postupně vytvoří jednorozměrné pole, dvourozměrné pole a nakonec i pole trojrozměrné:
let array_a = array![1, 2, 3, 4]; let array_b = array![[1, 2], [3, 4]]; let array_c = array![[[1, 2], [3, 4]], [[5, 6], [7, 8]]];
Výsledkem by měla být následující trojice polí:
[1, 2, 3, 4] [[1, 2], [3, 4]] [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
11. Změna tvaru při konverzi polí
Tvar pole je možné změnit i jeho konverzí, konkrétně funkcí into_shape(). Výsledkem je typ Result, takže musíme zavolat funkci unwrap() pro získání výsledku (důvod je jednoduchý – počet prvků zdrojového a cílového pole musí odpovídat novému tvaru). Nejprve si vytvořme zdrojové jednorozměrné pole – vektor:
let array = Array::from_iter(0..12);
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
Konverzí vytvoříme dvourozměrné pole o třech řádcích a čtyřech sloupcích:
let array_b = Array::from_iter(0..12).into_shape((3,4)).unwrap();
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
Další konverzí vytvoříme pole a čtyřech řádcích a třech sloupcích, stále s dvanácti prvky:
let array_c = Array::from_iter(0..12).into_shape((4,3)).unwrap();
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]
A další varianta, tentokrát s polem o dvanácti řádcích, ovšem s jediným sloupcem:
let array_d = Array::from_iter(0..12).into_shape((12,1)).unwrap();
[[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11]]
Různé varianty trojrozměrných polí, vždy o dvanácti prvcích:
let array_e = Array::from_iter(0..12).into_shape((2,2,3)).unwrap();
[[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]]]
let array_f = Array::from_iter(0..12).into_shape((2,3,2)).unwrap();
[[[0, 1], [2, 3], [4, 5]], [[6, 7], [8, 9], [10, 11]]]
let array_g = Array::from_iter(0..12).into_shape((3,2,2)).unwrap();
[[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]]
Čtyřrozměrné pole 2×2×2×2 prvky:
let array_h = Array::from_iter(0..16).into_shape((2, 2, 2, 2)).unwrap();
[[[[0, 1], [2, 3]], [[4, 5], [6, 7]]], [[[8, 9], [10, 11]], [[12, 13], [14, 15]]]]
12. Zjištění délky, dimenze, tvaru a kroku mezi jednotlivými prvky pole
O již existujících polích je možné získat poměrně mnoho užitečných informací – celkový počet prvků, počet dimenzí, počet prvků v osách jednotlivých dimenzí, samozřejmě tvar pole a offsety mezi jednotlivými prvky (opět s ohledem na osy).
Příkladem může být jednorozměrné pole:
let array = Array::from_iter(0..12); println!("length: {}", array.len()); println!("dimensions: {}", array.ndim()); println!("dimension: {:?}", array.dim()); println!("shape: {:?}", array.shape()); println!("strides: {:?}\n", array.strides());
Počet prvků je zde pochopitelně dvanáct, pole má jedinou dimenzi, počet prvků v ose této dimenze je taktéž dvanáct a offset mezi prvky je roven jedné:
length: 12 dimensions: 1 dimension: 12 shape: [12] strides: [1]
Pro dvourozměrné pole s dvanácti řádky získáme odlišné informace:
let array_b = Array::from_iter(0..12).into_shape((1,12)).unwrap(); println!("length: {}", array_b.len()); println!("dimensions: {}", array_b.ndim()); println!("dimension: {:?}", array_b.dim()); println!("shape: {:?}", array_b.shape()); println!("strides: {:?}\n", array_b.strides());
length: 12 dimensions: 2 dimension: (1, 12) shape: [1, 12] strides: [12, 1]
Další dvourozměrné pole:
let array_c = Array::from_iter(0..12).into_shape((4,3)).unwrap(); println!("length: {}", array_c.len()); println!("dimensions: {}", array_c.ndim()); println!("dimension: {:?}", array_c.dim()); println!("shape: {:?}", array_c.shape()); println!("strides: {:?}\n", array_c.strides());
Povšimněte si zde zejména hodnoty strides, která zhruba říká, že mezi dvěma prvky ve stejném sloupci, ale na jiném řádku, je offset roven třem:
length: 12 dimensions: 2 dimension: (4, 3) shape: [4, 3] strides: [3, 1]
Trojrozměrné pole s dvanácti prvky:
let array_d = Array::from_iter(0..12).into_shape((2,3,2)).unwrap(); println!("length: {}", array_d.len()); println!("dimensions: {}", array_d.ndim()); println!("dimension: {:?}", array_d.dim()); println!("shape: {:?}", array_d.shape()); println!("strides: {:?}\n", array_d.strides());
length: 12 dimensions: 3 dimension: (2, 3, 2) shape: [2, 3, 2] strides: [6, 2, 1]
Čtyřrozměrné pole se šestnácti prvky:
let array_e = Array::from_iter(0..16).into_shape((2,2,2,2)).unwrap(); println!("length: {}", array_e.len()); println!("dimensions: {}", array_e.ndim()); println!("dimension: {:?}", array_e.dim()); println!("shape: {:?}", array_e.shape()); println!("strides: {:?}\n", array_e.strides());
Zde je asi nejlépe patrný význam hodnot strides, když si uvědomíme, jak je toto čtyřrozměrné pole zkonstruováno (stačí si představit hyperkostku, v jejíchž vrcholech jsou uloženy hodnoty prvků):
length: 16 dimensions: 4 dimension: (2, 2, 2, 2) shape: [2, 2, 2, 2] strides: [8, 4, 2, 1]
13. Repositář s demonstračními příklady
Všechny dnes popisované demonstrační příklady (Rustovské projekty) 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/presentations. Demonstrační příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář (ovšem u projektů je lepší mít celý repositář, abyste nemuseli pracně stahovat všechny potřebné soubory):
Příklad | Adresa |
---|---|
První projekt | ndarray-constructors |
Cargo.toml | https://github.com/tisnik/presentations/blob/master/rust/projects/ndarray-constructors/Cargo.toml |
main.rs | https://github.com/tisnik/presentations/blob/master/rust/projects/ndarray-constructors/src/main.rs |
Druhý projekt | ndarray-shape |
Cargo.toml | https://github.com/tisnik/presentations/blob/master/rust/projects/ndarray-shape/Cargo.toml |
main.rs | https://github.com/tisnik/presentations/blob/master/rust/projects/ndarray-shape/src/main.rs |
Třetí projekt | ndarray-info |
Cargo.toml | https://github.com/tisnik/presentations/blob/master/rust/projects/ndarray-info/Cargo.toml |
main.rs | https://github.com/tisnik/presentations/blob/master/rust/projects/ndarray-info/src/main.rs |
14. Odkazy na Internetu
- ndarray – dokumentace
https://bluss.github.io/rust-ndarray/master/ndarray/index.html - ndarray – Crate
https://crates.io/crates/ndarray - Array Programming
https://en.wikipedia.org/wiki/Array_programming - Discovering Array Languages
http://archive.vector.org.uk/art10008110 - no stinking loops – Kalothi
http://www.nsl.com/ - Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
http://www.vector.org.uk/ - rustup
https://www.rustup.rs/ - rustup: the Rust toolchain installer (Git repositář + dokumentace)
https://github.com/rust-lang-nursery/rustup.rs - The Rust FFI Omnibus
http://jakegoulding.com/rust-ffi-omnibus/ - Build Script Support
http://doc.crates.io/build-script.html - Calling Rust From Python
https://bheisler.github.io/post/calling-rust-in-python/ - Calling Rust in Python (komentáře k předchozímu článku)
https://www.reddit.com/r/rust/comments/63iy5a/calling_rust_in_python/ - CFFI Documentation
https://cffi.readthedocs.io/en/latest/ - Build Script Support
http://doc.crates.io/build-script.html - Creating a shared and static library with the gnu compiler [gcc]
http://www.adp-gmbh.ch/cpp/gcc/create_lib.html - ctypes — A foreign function library for Python
https://docs.python.org/2/library/ctypes.html - FFI: Foreign Function Interface
https://doc.rust-lang.org/book/ffi.html - Primitive Type pointer
https://doc.rust-lang.org/std/primitive.pointer.html - Cargo: správce projektů a balíčků pro programovací jazyk Rust
https://mojefedora.cz/cargo-spravce-projektu-a-balicku-pro-programovaci-jazyk-rust/ - Network Communication and Serialization in Rust
https://www.safaribooksonline.com/blog/2014/01/28/network-communication-serialization-rust/ - Crate bincode
http://tyoverby.com/bincode/bincode/index.html - Struct std::fs::File
https://doc.rust-lang.org/std/fs/struct.File.html - Trait std::io::Seek
https://doc.rust-lang.org/std/io/trait.Seek.html - Trait std::io::Read
https://doc.rust-lang.org/std/io/trait.Read.html - Trait std::io::Write
https://doc.rust-lang.org/std/io/trait.Write.html - Trait std::io::BufRead
https://doc.rust-lang.org/std/io/trait.BufRead.html - Module std::io::prelude
https://doc.rust-lang.org/std/io/prelude/index.html - std::net::IpAddr
https://doc.rust-lang.org/std/net/enum.IpAddr.html - std::net::Ipv4Addr
https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html - std::net::Ipv6Addr
https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html - TcpListener
https://doc.rust-lang.org/std/net/struct.TcpListener.html - TcpStream
https://doc.rust-lang.org/std/net/struct.TcpStream.html - Binary heap (Wikipedia)
https://en.wikipedia.org/wiki/Binary_heap - Binární halda (Wikipedia)
https://cs.wikipedia.org/wiki/Bin%C3%A1rn%C3%AD_halda - Halda (datová struktura)
https://cs.wikipedia.org/wiki/Halda_%28datov%C3%A1_struktura%29 - Struct std::collections::HashSet
https://doc.rust-lang.org/std/collections/struct.HashSet.html - Struct std::collections::BTreeSet
https://doc.rust-lang.org/std/collections/struct.BTreeSet.html - Struct std::collections::BinaryHeap
https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html - Set (abstract data type)
https://en.wikipedia.org/wiki/Set_%28abstract_data_type%29#Language_support - Associative array
https://en.wikipedia.org/wiki/Associative_array - Hash Table
https://en.wikipedia.org/wiki/Hash_table - B-tree
https://en.wikipedia.org/wiki/B-tree - Pedro Celis: Robin Hood Hashing (naskenované PDF!)
https://cs.uwaterloo.ca/research/tr/1986/CS-86–14.pdf - Robin Hood hashing
http://codecapsule.com/2013/11/11/robin-hood-hashing/ - Robin Hood hashing: backward shift deletion
http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/ - Module std::collections
https://doc.rust-lang.org/std/collections/ - Module std::vec
https://doc.rust-lang.org/nightly/std/vec/index.html - Struct std::collections::VecDeque
https://doc.rust-lang.org/std/collections/struct.VecDeque.html - Struct std::collections::LinkedList
https://doc.rust-lang.org/std/collections/struct.LinkedList.html - Module std::fmt
https://doc.rust-lang.org/std/fmt/ - Macro std::println
https://doc.rust-lang.org/std/macro.println.html - Enum std::result::Result
https://doc.rust-lang.org/std/result/enum.Result.html - Module std::result
https://doc.rust-lang.org/std/result/ - Result
http://rustbyexample.com/std/result.html - Rust stdlib: Option
https://doc.rust-lang.org/std/option/enum.Option.html - Module std::option
https://doc.rust-lang.org/std/option/index.html - Rust by example: option
http://rustbyexample.com/std/option.html - Rust by example: if-let
http://rustbyexample.com/flow_control/if_let.html - Rust by example: while let
http://rustbyexample.com/flow_control/while_let.html - Rust by example: Option<i32>
http://rustbyexample.com/std/option.html - An Overview of Macros in Rust
http://words.steveklabnik.com/an-overview-of-macros-in-rust - A Practical Intro to Macros in Rust 1.0
https://danielkeep.github.io/practical-intro-to-macros.html - The Rust Programming Language: macros
https://doc.rust-lang.org/beta/book/macros.html - Rust by example: 15 macro_rules!
http://rustbyexample.com/macros.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