Obsah
1. Krátké zopakování z první části článku – speciální typy programových smyček
2. Smyčky konstruované pomocí ∃ a ∀
3. Získání přesnějších informací o výsledcích smyček: klauzule where, why a why not
4. Použití klauzule where u smyček min a max
5. Použití klauzulí why a why not u smyček ∃ a ∀
9. „Probublávání“ hodnot none() a err(x) při použití operátoru ?
10. Kontrola modifikátoru mut u parametrů a argumentů funkcí
11. Uživatelsky definované objekty
12. Uživatelsky definované ad-hoc typy
15. Repositář s demonstračními příklady
1. Krátké zopakování z první části článku – speciální typy programových smyček
Již minule jsme se seznámili s tím, že kromě dvou univerzálních smyček nazvaných loop (nekonečná smyčka) a for (několik forem počítané smyčky i smyčky typu for-each) existují v jazyku Dyon i další varianty programových smyček, které se typicky používají pro zpracování polí (ostatně práce s poli tvoří základ pro většinu skriptů, které jsou v Dyonu psány). Připomeňme si, že můžeme použít tyto smyčky:
Konstrukce | Alternativní zápis | Význam |
---|---|---|
sift | vytvoření pole z předávaných hodnot | |
sum | ∑ | suma prvků |
prod | ∏ | výsledek vynásobení všech prvků |
min | zjištění minima | |
max | zjištění maxima | |
any | ∃ | test, zda je výraz pravdivý alespoň pro jeden prvek |
all | ∀ | test, zda je výraz pravdivý pro všechny prvky |
Příklad použití:
a := [3,2,1,10,1] minimum := min i { a[i] } println(minimum) maximum := max i { a[i] } println(maximum) suma := sum i len(a) { a[i] } println(suma) product := prod i len(a) { a[i] } println(product)
S výsledky:
1 10 17 60
2. Smyčky konstruované pomocí ∃ a ∀
Ve skutečnosti je možné většinu těchto smyček chápat jako specializovanou formu reduce s počáteční hodnotou akumulátoru a funkcí aplikovanou postupně na prvky, kterými se iteruje. Viditelné je to zejména u těchto šesti smyček:
Smyčka | Prováděná operace | Počáteční hodnota |
---|---|---|
sum | + | 0 |
prod | * | 1 |
min | < acc | none() |
max | > acc | none() |
any | logický součet | false |
all | logický součin | true |
Podívejme se nyní na způsob použití programových smyček all a any pro zjištění, zda nějaké jednorozměrné pole obsahuje alespoň jednu zápornou hodnotu či zda jsou všechny hodnoty kladné. Můžeme použít obou typů smyček. Povšimněte si způsobu zápisu podmínky do složených závorek:
fn special_loops_all_any() { println("Special loops: all, any") a := [3,2,1,10,1] println(a) has_negative_values := any i { a[i] < 0 } println(has_negative_values) all_values_positive := all i { a[i] > 0 } println(all_values_positive) a := [3,2,-1,10,1] println(a) has_negative_values := any i { a[i] < 0 } println(has_negative_values) all_values_positive := all i { a[i] > 0 } println(all_values_positive) println("") }
Výsledek běhu této funkce:
Special loops: all, any [3, 2, 1, 10, 1] false true [3, 2, -1, 10, 1] true false
3. Získání přesnějších informací o výsledcích smyček: klauzule where, why a why not
Programovací jazyk Dyon dokáže k hodnotám typu bool a f64 (což jsou dva základní a vlastně i jediné primitivní datové typy) navázat nepovinné pole obsahující další metainformace o dané hodnotě. Toto nepovinné pole se jmenuje secrets a lze ho použít k zápisu uživatelských dat (pokud to má význam). U některých programových smyček se secrets používá pro uložení informace do výsledné hodnoty produkované programovou smyčkou:
Smyčka | Secrets | Získání secrets |
---|---|---|
min | index minimálního prvku | where() |
max | index maximálního prvku | where() |
any | index prvku, který první splnil podmínku | why() |
all | index prvku, který první nesplnil podmínku | why() |
Z předchozí tabulky je patrné, že u smyček min a max použijeme klauzuli where(). Tato klauzule se sice zapisuje jako funkce, ale jedná se o prvek jazyka. U smyčky any se pomocí why() získá index prvku, který první splnil podmínku – to ovšem platí jen u návratové hodnoty true. U smyčky all se naopak pomocí why not/(why(!…)) získá index prvního prvku, který podmínku nesplnil. Platné je to ovšem jen v případě, že smyčka all vrátila hodnotu false. To mj. znamená, že u těchto dvou smyček budeme zápis why(…) či why(!…) prakticky vždy používat v podmínce.
4. Použití klauzule where u smyček min a max
Klauzuli where použijeme především u programových smyček min a max, protože tak můžeme velmi snadno získat index prvku s minimální či naopak maximální hodnotou. Použití je velmi jednoduché, jak je to ostatně patrné z následující funkce, kde je where zvýrazněno:
fn special_loops_min_max_secrets() { println("Special loops: min max, secrets") a := [3,2,1,10,1] println(a) minimum := min i { a[i] } print("Min: ") print(minimum) print(" at index: ") println(where(minimum)) maximum := max i { a[i] } print("Max: ") print(maximum) print(" at index: ") println(where(maximum)) println("") }
Výsledek běhu této funkce:
Special loops: min max, secrets [3, 2, 1, 10, 1] Min: 1 at index: [2] Max: 10 at index: [3]
Poznámka: povšimněte si, že pokud vstupní pole obsahuje alespoň jeden prvek, je zajištěno, že where vrátí index prvku, na rozdíl od dále popsané klauzule why. To znamená, že v kódu nemusíme používat žádné podmínky a přímo přistupovat k výsledkům smyčky a metainformacím navázaným na tyto výsledky.
5. Použití klauzulí why a why not u smyček ∃ a ∀
Zatímco u klauze where jsme měli jistotu, že vrátí index prvku s minimální či maximální hodnotou, je tomu u klauzulí why a why not poněkud jinak, protože tyto klauzule jsou použity v kombinaci s programovými smyčkami ∃ a ∀. U smyčky any lze why() použít jen u návratové hodnoty true. U smyčky all se naopak používá why not (zapisované (why(!…)), ovšem jen v případě, že smyčka all vrátila hodnotu false. Opět se podívejme na příklady:
fn special_loops_any_secrets() { println("Special loops: any, secrets") a := [3,2,1,10,1] println(a) has_negative_values := any i { a[i] < 0 } print("Has negative values: ") if has_negative_values { print("Yes, at index: ") println(why(has_negative_values)) } else { println("No") } a := [3,2,-1,10,-1] println(a) has_negative_values := any i { a[i] < 0 } print("Has negative values: ") if has_negative_values { print("Yes, at index: ") println(why(has_negative_values)) } else { println("No") } println("") }
Výsledek běhu této funkce:
Special loops: any, secrets [3, 2, 1, 10, 1] Has negative values: No [3, 2, -1, 10, -1] Has negative values: Yes, at index: [2]
fn special_loops_all_secrets() { println("Special loops: all, secrets") a := [3,2,1,10,1] println(a) all_values_positive := all i { a[i] > 0 } print("All values are positive: ") if all_values_positive { println("Yes") } else { print("No, 1st non-positive value found at index: ") println(why(!all_values_positive)) } a := [3,2,-1,10,-1] println(a) all_values_positive := all i { a[i] > 0 } print("All values are positive: ") if all_values_positive { println("Yes") } else { print("No, 1st non-positive value found at index: ") println(why(!all_values_positive)) } println("") }
Výsledek běhu této funkce:
Special loops: all, secrets [3, 2, 1, 10, 1] All values are positive: Yes [3, 2, -1, 10, -1] All values are positive: No, 1st non-positive value found at index: [2]
6. Datový typ Option
S datovým typem Option jsme se již setkali při popisu vlastností programovacího jazyka Rust. Připomeňme si tedy, že díky existenci tohoto typu je možné elegantně obejít většinu nectností speciálních hodnot (někde ukazatelů, jinde zase pro změnu referencí) typu None, null či nil. Při použití typu Option je totiž explicitně specifikováno, že je nějaká hodnota nepovinná popř. volitelná (podle kontextu). Navíc jsme jako programátoři přinuceni se explicitně zpracováním nepovinné/volitelné hodnoty zabývat. Datový typ Option tvoří obálku nad samotnou reprezentovanou hodnotou popř. reprezentuje prázdnou obálku. S tímto typem jsou spojeny především tři funkce:
Funkce | Význam |
---|---|
some(any) | vytvoří obálku s hodnotou libovolného typu |
none() | vytvoří prázdnou obálku (jedná se o jedináčka) |
unwrap(option) | (rozbalení) vrátí hodnotu uloženou v obálce |
Podívejme se na použití těchto tří funkcí. Je to velmi snadné:
o := some(42) println(o) o = none() println(o) o = some(2) println(unwrap(o)) o = none() //println(unwrap(o)) if o != none() { println(unwrap(o)) }
Povšimněte si zejména testu, zda je obálka prázdná (zde se kód odlišuje od Rustu).
Výsledek běhu příkladu:
some(42) none() 2 false
unwrap() nelze volat pro hodnotu none():
--- ERROR --- main (src/main.dyon) test_option_type (src/main.dyon) unwrap Expected `some(_)` 12,20: println(unwrap(o)) 12,20: ^
Poznámka: prozatím nelze použít pattern matching, který by se zde hodil.
7. Datový typ Result
I další užitečný datový typ nazvaný Result jsme si již v tomto seriálu popsali, ovšem v kontextu Rustu a nikoli Dyonu. Připomeňme si tedy, že v mnoha případech nemusí být použití datového typu Option tím nejlepším řešením. Pro příklad nemusíme chodit daleko – předpokládejme, že budeme chtít, aby například funkce pro dělení celých čísel vracela v případě pokusu o dělení nulou chybové hlášení a nikoli nicneříkající hodnotu none(). K tomuto účelu se v programovacím jazyku Rust a nyní i Dyon používá datová struktura nazvaná příhodně Result. Tato datová struktura se podobá Option, ovšem s tím rozdílem, že obaluje buď výsledek (třeba návratovou hodnotu volané funkce) nebo informaci o chybě. K dispozici jsou následující pomocné funkce:
Funkce | Význam |
---|---|
ok(any) | vytvoří obálku s hodnotou libovolného typu |
err(any) | vytvoří obálku s hodnotou reprezentující chybu (například chybové hlášení) |
is_ok(result) | dotaz (predikát), zda pracujeme s bezchybnou hodnotou |
is_err(result) | dotaz (predikát), zda pracujeme s informací o chybě |
unwrap(result) | (rozbalení) vrátí hodnotu uloženou v obálce |
unwrap_err(result) | (rozbalení) vrátí hodnotu reprezentující chybu |
Opět se podívejme na jednoduchý příklad:
r := ok(42) println(r) println(is_ok(r)) println(is_err(r)) r = err("Very serious") println(r) println(is_ok(r)) println(is_err(r)) r = ok(2) println(unwrap(r)) //println(unwrap_err(r)) r = err("Very serious") //println(unwrap(r)) println(unwrap_err(r)) r = ok(42) if is_ok(r) { println(unwrap(r)) } else { println(unwrap_err(r)) }
S výsledky:
ok(42) true false err("Very serious") false true 2 Very serious 42
Poznámka: opět platí, že prozatím nelze použít pattern matching, který by se zde hodil.
8. Operátor ?
Pokud vytvoříme funkci div počítající podíl dvou čísel, která bude vracet typ Result, můžeme jednoduše zabezpečit, že nikdy nedojde k dělení nulou:
fn div(x,y) -> { if y == 0 { return err("Div by 0") } else { return ok(x/y) } }
Popř. můžeme použít idiomatičtější zápis:
fn div(x,y) -> { return if y == 0 { err("Div by 0") } else { ok(x/y) } }
Tuto funkci si můžeme snadno otestovat:
fn test_div() { d := div(10, 5) println(d) e := div(1, 0) println(e) }
S výsledky:
ok(2) err("Div by 0")
Co se ovšem stane v případě, že budeme mít několik vzájemně se volajících funkcí, které si budou výsledek div() předávat a používat ho? Nebylo by asi praktické stále volat is_ok(…) a is_err(…), navíc by se kvůli množství podmínek do zápisu algoritmu zbytečně vneslo mnoho kontrol speciálních (chybových) stavů. Řešení samozřejmě existuje a spočívá v použití operátoru ?. Tento operátor se zapisuje za jméno volané funkce a umožňuje provést kontrolu, zda je výsledek volání (typu Result) roven ok(hodnota). Pokud tomu tak není, je funkce ihned ukončena a návratovou hodnotou je err(zpráva). Operátor ? tedy slouží k tomu, aby se v kódu nemuselo explicitně zapisovat:
r := nějaká_funkce() if is_err(r) { return r } ... ... ...
9. „Probublávání“ hodnot none() a err(x) při použití operátoru ?
Podívejme se nyní na to, jak je možné elegantně vyřešit volání funkce div() uvnitř jiné funkce, která používá výsledek dělení a tudíž i potenciální chybový stav. Funkce div() je stále stejná:
fn div(x,y) -> { if y == 0 { return err("Div by 0") } else { return ok(x/y) } }
Další funkce je určena k přičtení nějakého offsetu k výsledku dělení. Ovšem ve chvíli, kdy by se mělo dělit nulou, budeme chtít výpočet ihned ukončit a vrátit původní chybu. Toho docílíme snadno právě díky použití operátoru ? (ten je zapsán za uzavírací kulatou závorku):
fn div_add(x, y, z) -> { r := div(x, y)? println(r) return ok(r + z) }
Poslední dva příkazy println+return se provedou jen ve chvíli, kdy se nedělilo nulou. Ostatně se o tom můžeme velmi snadno přesvědčit:
fn test_div_question_op() { r1 := div_add(10, 5, 100) println(r1) r2 := div_add(10, 0, 100) println(r2) }
S výsledky:
2 ok(102) err("Div by 0")
První dvojka vznikla byla vypsána ve funkci div_add.
Poznámka: operátor ? tedy nemá nic společného s ternárním céčkovým operátorem, který není nutné do jazyka Dyon implementovat, protože si if-else používá ve výrazech.
10. Kontrola modifikátoru mut u parametrů a argumentů funkcí
Již minule jsme se zmínili o tom, že pokud má funkce modifikovat hodnoty svých argumentů, musí se u těchto argumentů zapsat modifikátor mut. Stejný modifikátor je nutné použít i při volání funkce, čímž dává programátor najevo, že je srozuměn s tím, že se daný parametr může měnit. Kontrola přítomnosti tohoto modifikátoru ale ve skutečnosti probíhá v celém řetězci volání. Ostatně podívejme se na jednoduchý příklad, v němž se funkce inc volá z jiné funkce call_inc volané ze třetí funkce functions:
fn inc(mut x) { x += 1 } fn call_inc(mut x) { inc(mut x) } fn functions() { x := 1 println(x) call_inc(mut x) println(x) }
Modifikátor mut je skutečně nutné použít na všech čtyřech zvýrazněných místech, nemůžeme se ho tedy „zbavit“ například uvnitř call_inc:
fn inc(mut x) { x += 1 } fn call_inc(mut x) { inc(x) } fn functions() { x := 1 println(x) call_inc(mut x) println(x) }
--- ERROR --- In `src/main.dyon`: Could not find function `inc` Did you mean: - inc(mut) 6,5: inc(x) 6,5: ^
A už vůbec ne při volání call_inc:
fn inc(mut x) { x += 1 } fn call_inc(mut x) { inc(mut x) } fn functions() { x := 1 println(x) call_inc( x) println(x) }
--- ERROR --- In `src/main.dyon`: Could not find function `call_inc` Did you mean: - call_inc(mut) 12,5: call_inc(x) 12,5: ^
11. Uživatelsky definované objekty
Uživatelsky definované objekty jsou postavené na klasických asociativních polích (slovnících, hash mapách), takže se jedná o přístup, který můžeme znát z programovacího jazyka Lua. Pro přístup k atributům objektů se používá buď tečková notace či alternativně přístup přes klíč, jehož jméno je v uvozovkách (jde o řetězec). Opět se zde nabízí srovnání s programovacím jazykem Lua:
fn test_objects() { c := {real:10, imag:20} println(c) c.real = 1000 println(c) c["real"] = 0 println(c) }
S výsledky:
{imag: 20, real: 10} {imag: 20, real: 1000} {imag: 20, real: 0}
Podobně jako v případě běžných proměnných, i při modifikaci atributů se provádí kontrola, zda nedochází ke změně typu ukládané hodnoty:
fn test_objects() { c := {real:10, imag:20} println(c) c.real = 1000 println(c) c["real"] = "x" println(c) }
--- ERROR --- main (src/main.dyon) test_objects (src/main.dyon) Expected assigning to text 23,5: c["real"] = "x" 23,5: ^
Atributy lze k objektu přidávat za běhu, a to tečkovou notací a současně operátorem := (nikoli pouze =, což by nebylo konzistentní):
fn test_objects() { c := {real:10, imag:20} println(c) c.real = 1000 println(c) c["real"] = 0 println(c) c.name := "komplexni cislo" println(c) }
S výsledky:
{real: 10, imag: 20} {real: 1000, imag: 20} {real: 0, imag: 20} {real: 0, name: "komplexni cislo", imag: 20}
12. Uživatelsky definované ad-hoc typy
Programovací jazyk Dyon podporuje deklaraci takzvaných ad-hoc typů, díky nimž lze vytvářet struktury podobné třídám. Podívejme se na jednoduchý příklad, v němž nejdříve vytvoříme „konstruktor“ pro třídu Complex (musíme si však uvědomit, že termín „konstruktor“ a „třída“ je zde uveden pouze pro sémantickou podobnost s podobnými konstrukcemi známými z některých jiných jazyků):
fn new_complex(real, imag) -> Complex { return {real: clone(real), imag: clone(imag)} }
V tomto konstruktoru jsme pouze pojmenovali slovník, který je výsledkem volání funkce.
Ve skutečnosti můžeme nové pojmenování Complex použít ve chvíli, kdy je nutné určit typ parametrů funkce (někdy to nutné není a můžeme se spolehnout na dynamický typový systém):
fn print_complex(c: Complex) { print(c.real) print("+j") print(c.imag) }
Chování konstruktoru new_complex i funkce print_complex si můžeme snadno odzkoušet:
fn main() { cplx := new_complex(10, 20) print_complex(cplx) }
S výsledkem:
10+j20
Poznámka: žádnou další podporu pro práci s objekty v sémantice programovacího jazyka Dyon (prozatím) nenajdeme, dokonce ani nejsou přímo podporovány traity.
13. Životnost objektů
Jednou z velmi důležitých vlastností programovacího jazyka Dyon je kontrola životnosti (častěji se možná používá termín viditelnosti) objektů. Díky této kontrole je možné se obejít bez klasického garbage collectoru, protože objekt je možné z paměti odstranit ve chvíli, kdy je již zřejmé, že není viditelný (živý). Na druhou stranu to však klade poněkud větší nároky na programátora, který na některých místech programu musí explicitně určit, jaká je životnost proměnné či parametru funkce.
V následujícím programu je vše v pořádku, protože životnost parametrů funkcí je omezena jen na těla funkcí. Je tomu tak z toho důvodu, že vynásobením vzniká nová hodnota:
fn foo(a) -> { return a*2 } fn bar(a) -> { return 3*foo(a) } fn test_lifetimes() { x := bar(10) println(x) }
Co když však budeme chtít přímo vrátit parametr předaný do funkce? V tomto případě nevzniká nová hodnota a současně je životnost parametru delší než je oblast platnosti funkce:
fn foo(a) -> { return a } fn bar(a) -> { return 3*foo(a) } fn test_lifetimes() { x := bar(10) println(x) }
Program se tedy nepřeloží, ovšem z chybového hlášení je zřejmé, jak provést nápravu:
--- ERROR --- In `src/main.dyon`: Requires `a: 'return` 47,12: return a 47,12: ^
Úpravou a: 'return specifikujeme, že životnost parametru a má být větší – má se rozšířit i na volající funkci:
fn foo(a: 'return) -> { return a } fn bar(a) -> { return 3*foo(a) } fn test_lifetimes() { x := bar(10) println(x) }
Podobně můžeme zvětšovat životnost i přes funkci bar do funkce test_lifetimes:
fn foo(a: 'return) -> { return a } fn bar(a: 'return) -> { return foo(a) } fn test_lifetimes() { b := 10 x := bar(b) println(x) }
Ve skutečnosti se při deklaraci může použít zápis x: 'y, který znamená, že proměnná x má mít minimálně takovou životnost, jako proměnná y. Zápis s 'return je speciálním případem (ostatně žádná proměnná se return jmenovat nemůže :-)
14. Použití funkce clone
Většinou je explicitní deklarace životnosti objektů pro programátory zbytečně pracné a namísto rozšiřování životnosti použijí funkci clone(), která danou hodnotu naklonuje. Po naklonování nás již nemusí zajímat, jaká byla životnost původní hodnoty. Příklad jsme si vlastně již ukázali u konstruktoru komplexních čísel, kde jsme explicitně naklonovali parametry funkce a klony jsme použili v atributech nového objektu (slovníku):
fn new_complex(real, imag) -> Complex { return {real: clone(real), imag: clone(imag)} }
Pokud volání clone() vynecháme:
fn new_complex(real, imag) -> Complex { return {real: real, imag: imag} }
Dojde při překladu zdrojového kódu k chybě:
--- ERROR --- In `src/main.dyon`: Requires `real: 'return` 31,12: return {real: real, 31,12: ^ 32,1: imag: imag}
A právě v této kontrole podle mého názoru spočívá největší přednost celé technologie kontroly životnosti – programátor je překladačem umozorněn na potenciální problémy a může program adekvátně změnit, většinou defenzivní kopií. Pěkně to shrnuje tento komentář.
15. Repositář s demonstračními příklady
Většina ukázek z předchozích kapitol byla přidána do několika demonstračních příkladů, které byly 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):
16. Odkazy na Internetu
- Secrets design – optional information in
bool
andf64
https://github.com/PistonDevelopers/dyon/issues/266 - Option value design
https://github.com/PistonDevelopers/dyon/issues/172 - Result value design (
err(x)/ok(x)
)
https://github.com/PistonDevelopers/dyon/issues/82 - ∑/sum, ∏/prod, min, max, sift, ∃/any, ∀/all loops
https://github.com/PistonDevelopers/dyon/issues/119 - Dyon: tutoriál
http://www.piston.rs/dyon-tutorial/ - Repositář s programovacím jazykem Dyon
https://github.com/PistonDevelopers/dyon - Dyon: A rusty dynamically typed scripting language
https://rust.libhunt.com/project/dyon - Dyon snippets
https://github.com/PistonDevelopers/dyon_snippets - Scripting without garbage collector
http://blog.piston.rs/2016/02/21/scripting-without-garbage-collector/ - Podpora pro „matematické“ smyčky
https://github.com/PistonDevelopers/dyon/issues/119 - Rust-clippy Wiki
https://github.com/rust-lang-nursery/rust-clippy/wiki - Rust-clippy
https://rust.libhunt.com/project/rust-clippy - ndarray – dokumentace k modulu
https://bluss.github.io/rust-ndarray/master/ndarray/index.html - ndarray – Crate
https://crates.io/crates/ndarray - 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