Hlavní navigace

Rust: knihovna ndarray pro práci s n-rozměrnými poli

Pavel Tišnovský

V dnešním článku o jazyku Rust a knihovnách, které pro tento jazyk vznikly, se budeme zabývat knihovnou určenou pro práci s n-rozměrnými poli, samozřejmě včetně běžných vektorů a matic. Tato knihovna se jmenuje příhodně ndarray.

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

3. Použití 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

10. Použití makra array!

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

14. Odkazy na Internetu

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/pre­sentations. 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):

14. Odkazy na Internetu

  1. ndarray – dokumentace
    https://bluss.github.io/rust-ndarray/master/ndarray/index.html
  2. ndarray – Crate
    https://crates.io/crates/ndarray
  3. Array Programming
    https://en.wikipedia.org/wi­ki/Array_programming
  4. Discovering Array Languages
    http://archive.vector.org­.uk/art10008110
  5. no stinking loops – Kalothi
    http://www.nsl.com/
  6. Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
    http://www.vector.org.uk/
  7. rustup
    https://www.rustup.rs/
  8. rustup: the Rust toolchain installer (Git repositář + dokumentace)
    https://github.com/rust-lang-nursery/rustup.rs
  9. The Rust FFI Omnibus
    http://jakegoulding.com/rust-ffi-omnibus/
  10. Build Script Support
    http://doc.crates.io/build-script.html
  11. Calling Rust From Python
    https://bheisler.github.i­o/post/calling-rust-in-python/
  12. Calling Rust in Python (komentáře k předchozímu článku)
    https://www.reddit.com/r/rus­t/comments/63iy5a/calling_rus­t_in_python/
  13. CFFI Documentation
    https://cffi.readthedocs.i­o/en/latest/
  14. Build Script Support
    http://doc.crates.io/build-script.html
  15. Creating a shared and static library with the gnu compiler [gcc]
    http://www.adp-gmbh.ch/cpp/gcc/create_lib.html
  16. ctypes — A foreign function library for Python
    https://docs.python.org/2/li­brary/ctypes.html
  17. FFI: Foreign Function Interface
    https://doc.rust-lang.org/book/ffi.html
  18. Primitive Type pointer
    https://doc.rust-lang.org/std/primitive.pointer.html
  19. Cargo: správce projektů a balíčků pro programovací jazyk Rust
    https://mojefedora.cz/cargo-spravce-projektu-a-balicku-pro-programovaci-jazyk-rust/
  20. Network Communication and Serialization in Rust
    https://www.safaribookson­line.com/blog/2014/01/28/net­work-communication-serialization-rust/
  21. Crate bincode
    http://tyoverby.com/binco­de/bincode/index.html
  22. Struct std::fs::File
    https://doc.rust-lang.org/std/fs/struct.File.html
  23. Trait std::io::Seek
    https://doc.rust-lang.org/std/io/trait.Seek.html
  24. Trait std::io::Read
    https://doc.rust-lang.org/std/io/trait.Read.html
  25. Trait std::io::Write
    https://doc.rust-lang.org/std/io/trait.Write.html
  26. Trait std::io::BufRead
    https://doc.rust-lang.org/std/io/trait.BufRead.html
  27. Module std::io::prelude
    https://doc.rust-lang.org/std/io/prelude/index.html
  28. std::net::IpAddr
    https://doc.rust-lang.org/std/net/enum.IpAddr.html
  29. std::net::Ipv4Addr
    https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html
  30. std::net::Ipv6Addr
    https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html
  31. TcpListener
    https://doc.rust-lang.org/std/net/struct.TcpLis­tener.html
  32. TcpStream
    https://doc.rust-lang.org/std/net/struct.TcpStream.html
  33. Binary heap (Wikipedia)
    https://en.wikipedia.org/wi­ki/Binary_heap
  34. Binární halda (Wikipedia)
    https://cs.wikipedia.org/wi­ki/Bin%C3%A1rn%C3%AD_halda
  35. Halda (datová struktura)
    https://cs.wikipedia.org/wi­ki/Halda_%28datov%C3%A1_struk­tura%29
  36. Struct std::collections::HashSet
    https://doc.rust-lang.org/std/collections/struc­t.HashSet.html
  37. Struct std::collections::BTreeSet
    https://doc.rust-lang.org/std/collections/struc­t.BTreeSet.html
  38. Struct std::collections::BinaryHeap
    https://doc.rust-lang.org/std/collections/struc­t.BinaryHeap.html
  39. Set (abstract data type)
    https://en.wikipedia.org/wi­ki/Set_%28abstract_data_ty­pe%29#Language_support
  40. Associative array
    https://en.wikipedia.org/wi­ki/Associative_array
  41. Hash Table
    https://en.wikipedia.org/wi­ki/Hash_table
  42. B-tree
    https://en.wikipedia.org/wiki/B-tree
  43. Pedro Celis: Robin Hood Hashing (naskenované PDF!)
    https://cs.uwaterloo.ca/re­search/tr/1986/CS-86–14.pdf
  44. Robin Hood hashing
    http://codecapsule.com/2013/11/11/ro­bin-hood-hashing/
  45. Robin Hood hashing: backward shift deletion
    http://codecapsule.com/2013/11/17/ro­bin-hood-hashing-backward-shift-deletion/
  46. Module std::collections
    https://doc.rust-lang.org/std/collections/
  47. Module std::vec
    https://doc.rust-lang.org/nightly/std/vec/index.html
  48. Struct std::collections::VecDeque
    https://doc.rust-lang.org/std/collections/struc­t.VecDeque.html
  49. Struct std::collections::LinkedList
    https://doc.rust-lang.org/std/collections/struc­t.LinkedList.html
  50. Module std::fmt
    https://doc.rust-lang.org/std/fmt/
  51. Macro std::println
    https://doc.rust-lang.org/std/macro.println.html
  52. Enum std::result::Result
    https://doc.rust-lang.org/std/result/enum.Result.html
  53. Module std::result
    https://doc.rust-lang.org/std/result/
  54. Result
    http://rustbyexample.com/std/re­sult.html
  55. Rust stdlib: Option
    https://doc.rust-lang.org/std/option/enum.Option.html
  56. Module std::option
    https://doc.rust-lang.org/std/option/index.html
  57. Rust by example: option
    http://rustbyexample.com/std/op­tion.html
  58. Rust by example: if-let
    http://rustbyexample.com/flow_con­trol/if_let.html
  59. Rust by example: while let
    http://rustbyexample.com/flow_con­trol/while_let.html
  60. Rust by example: Option<i32>
    http://rustbyexample.com/std/op­tion.html
  61. An Overview of Macros in Rust
    http://words.steveklabnik.com/an-overview-of-macros-in-rust
  62. A Practical Intro to Macros in Rust 1.0
    https://danielkeep.github.io/practical-intro-to-macros.html
  63. The Rust Programming Language: macros
    https://doc.rust-lang.org/beta/book/macros.html
  64. Rust by example: 15 macro_rules!
    http://rustbyexample.com/macros.html
  65. Primitive Type isize
    https://doc.rust-lang.org/nightly/std/primi­tive.isize.html
  66. Primitive Type usize
    https://doc.rust-lang.org/nightly/std/primi­tive.usize.html
  67. Primitive Type array
    https://doc.rust-lang.org/nightly/std/primi­tive.array.html
  68. Module std::slice
    https://doc.rust-lang.org/nightly/std/slice/
  69. Rust by Example: 2.3 Arrays and Slices
    http://rustbyexample.com/pri­mitives/array.html
  70. What is the difference between Slice and Array (stackoverflow)
    http://stackoverflow.com/qu­estions/30794235/what-is-the-difference-between-slice-and-array
  71. Learning Rust With Entirely Too Many Linked Lists
    http://cglab.ca/~abeinges/blah/too-many-lists/book/
  72. Testcase: linked list
    http://rustbyexample.com/cus­tom_types/enum/testcase_lin­ked_list.html
  73. Operators and Overloading
    https://doc.rust-lang.org/book/operators-and-overloading.html
  74. Module std::ops
    https://doc.rust-lang.org/std/ops/index.html
  75. Module std::cmp
    https://doc.rust-lang.org/std/cmp/index.html
  76. Trait std::ops::Add
    https://doc.rust-lang.org/stable/std/ops/trait.Add.html
  77. Trait std::ops::AddAssign
    https://doc.rust-lang.org/std/ops/trait.AddAssign.html
  78. Trait std::ops::Drop
    https://doc.rust-lang.org/std/ops/trait.Drop.html
  79. Trait std::cmp::Eq
    https://doc.rust-lang.org/std/cmp/trait.Eq.html
  80. Struct std::boxed::Box
    https://doc.rust-lang.org/std/boxed/struct.Box.html
  81. Explore the ownership system in Rust
    https://nercury.github.io/rus­t/guide/2015/01/19/ownership­.html
  82. Rust's ownership and move semantic
    http://www.slideshare.net/sa­neyuki/rusts-ownership-and-move-semantics
  83. Trait std::marker::Copy
    https://doc.rust-lang.org/stable/std/marker/tra­it.Copy.html
  84. Trait std::clone::Clone
    https://doc.rust-lang.org/stable/std/clone/tra­it.Clone.html
  85. The Stack and the Heap
    https://doc.rust-lang.org/book/the-stack-and-the-heap.html
  86. Rust Compare: Pointers & References
    http://www.rust-compare.com/site/pointers.html
  87. Rust Compare: Parameters
    http://www.rust-compare.com/site/params.html
  88. Why does this compile? Automatic dereferencing?
    https://users.rust-lang.org/t/why-does-this-compile-automatic-dereferencing/2183
  89. Understanding Pointers, Ownership, and Lifetimes in Rust
    http://koerbitz.me/posts/Understanding-Pointers-Ownership-and-Lifetimes-in-Rust.html
  90. Rust lang series episode #25 — pointers (#rust-series)
    https://steemit.com/rust-series/@jimmco/rust-lang-series-episode-25-pointers-rust-series
  91. Rust – home page
    https://www.rust-lang.org/en-US/
  92. Rust – Frequently Asked Questions
    https://www.rust-lang.org/en-US/faq.html
  93. Destructuring and Pattern Matching
    https://pzol.github.io/get­ting_rusty/posts/20140417_des­tructuring_in_rust/
  94. The Rust Programming Language
    https://doc.rust-lang.org/book/
  95. Rust (programming language)
    https://en.wikipedia.org/wi­ki/Rust_%28programming_lan­guage%29
  96. Go – home page
    https://golang.org/
  97. Stack Overflow – Most Loved, Dreaded, and Wanted language
    https://stackoverflow.com/re­search/developer-survey-2016#technology-most-loved-dreaded-and-wanted
  98. 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/
  99. Rust vs Go: My experience
    https://www.reddit.com/r/go­lang/comments/21m6jq/rust_vs_go_my_ex­perience/
  100. Friends of Rust (Organizations running Rust in production)
    https://www.rust-lang.org/en-US/friends.html
  101. Rust programs versus C++ g++
    https://benchmarksgame.ali­oth.debian.org/u64q/compa­re.php?lang=rust&lang2=gpp
  102. Další benchmarky (nejedná se o reálné příklady „ze života“)
    https://github.com/kostya/benchmarks
  103. Go na Redditu
    https://www.reddit.com/r/golang/
  104. Rust vs. Go
    http://vschart.com/compare/rust/vs/go-language
  105. Abstraction without overhead: traits in Rust
    https://blog.rust-lang.org/2015/05/11/traits.html
  106. Method Syntax
    https://doc.rust-lang.org/book/method-syntax.html
  107. Traits in Rust
    https://doc.rust-lang.org/book/traits.html
  108. Functional Programming in Rust – Part 1 : Function Abstraction
    http://blog.madhukaraphatak­.com/functional-programming-in-rust-part-1/
  109. 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
  110. Chytré ukazatele (moderní verze jazyka C++) [MSDN]
    https://msdn.microsoft.com/cs-cz/library/hh279674.aspx
  111. UTF-8 Everywhere
    http://utf8everywhere.org/
  112. Rust by Example
    http://rustbyexample.com/
  113. Rust oficiálně ve Fedoře
    https://mojefedora.cz/rust-oficialne-ve-fedore/
  114. Resource acquisition is initialization
    https://en.wikipedia.org/wi­ki/Resource_acquisition_is_i­nitialization
  115. TIOBE index (October 2016)
    http://www.tiobe.com/tiobe-index/
  116. 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
  117. String Types in Rust
    http://www.suspectsemantic­s.com/blog/2016/03/27/str­ing-types-in-rust/
  118. Trait (computer programming)
    https://en.wikipedia.org/wi­ki/Trait_%28computer_program­ming%29
  119. Type inference
    https://en.wikipedia.org/wi­ki/Type_inference
Našli jste v článku chybu?