Obsah
1. Programovací jazyk Rust: práce se soubory a se standardními proudy
2. Vytvoření nového souboru s provedením zápisu
3. Pokus o vytvoření souboru v adresáři, kam uživatel nemá právo zápisu
4. Návratové typy operací File::create() a File::write()
5. Kontrola všech I/O operací v Rustu
6. Ve které chvíli se soubor zavře?
7. Přečtení jednoho řádku ze standardního vstupu
8. Iterátor pro přečtení všech řádků ze standardního vstupu
9. Zpracování textových souborů
10. Repositář s demonstračními příklady
1. Práce se soubory a se standardními proudy
Dnes se budeme zabývat základními strukturami a traity, které slouží k práci se soubory (přesněji řečeno s obsahem souborů) a které můžeme najít ve standardní knihovně Rustu. Kromě toho se seznámíme i s možnostmi práce se standardním vstupním proudem (stdin), výstupním proudem (stdout) a proudem používaným pro výpis chybových hlášení (stderr). Podobně jako v dalších oblastech se i při návrhu I/O operací dbalo na bezpečnost, takže v základní knihovně Rustu nenajdeme například tak potenciálně nebezpečné funkce, jako je nechvalně známá gets() atd. V následující tabulce jsou vypsány základní struktury a traity, které postupně použijeme v demonstračních příkladech:
Struktura | Implementované traity | Stručný popis |
---|---|---|
std::fs::File | std::io::Read, std::io::Write, std::io::Seek | reprezentuje otevřený soubor (obdoba handle z céčka) |
std::io::Stdin | std::io::Read | standardní vstup |
std::io::Stdout | std::io::Write | standardní výstup |
std::io::Stderr | std::io::Write | chybový výstup |
std::io::BufReader | std::io::Read, std::io::BufRead, std::io::Seek | bufferovaný vstup, umožňuje například pracovat s celými textovými řádky |
std::io::BufWriter | std::io::Write, std::io::Seek | bufferovaný výstup |
std::io::Error | std::error::Error | reprezentuje nějakou formu chyby při vstupních a výstupních operacích |
Poznámka: použití traitu std::io::seek při práci s binárními soubory si ukážeme v navazující části tohoto seriálu.
2. Vytvoření nového souboru s provedením zápisu
První příklad bude velmi jednoduchý, protože v něm pouze vytvoříme nový soubor metodou File::create(). Tato metoda vrací hodnotu typu Result<File>, což konkrétně znamená, že se vrátí buď handle otevřeného souboru reprezentovaný strukturou std::fs::File nebo hodnotu typu std::io::Error. Následně provedeme zápis do souboru metodou File.write(), které se předá slice bajtů, tedy hodnot typu u8. Tato metoda vrátí hodnotu typu Result<usize>, tedy opět buď chybu nebo počet zapsaných bajtů:
use std::io::prelude::*; use std::fs::File; fn main() { let mut fout = File::create("test.txt").unwrap(); let written = fout.write(b"Hello, world!\n").unwrap(); println!("{} bytes written", written); }
Poznámka: soubor není zapotřebí zavírat, protože překladač ve správný okamžik (konkrétně na konci funkce main) zavolá destruktor struktury File, která uzavření provede automaticky.
3. Pokus o vytvoření souboru v adresáři, kam uživatel nemá právo zápisu
V předchozím demonstračním příkladu jsme se nesnažili o otestování, zda se soubor podařilo vytvořit a zda je do něj vůbec možné zapisovat – jen jsme z hodnoty typu Result získali příslušnou obalenou hodnotu metodou unwrap(). Toto ignorování potenciálních chyb se nám může vymstít, což si můžeme ukázat na jednoduchém příkladu, v němž se pokusíme zapisovat do adresáře „/bin“ (zde má právo zápisu pouze root):
use std::io::prelude::*; use std::fs::File; fn main() { let mut fout = File::create("/bin/test.txt").unwrap(); let written = fout.write(b"Hello, world!\n").unwrap(); println!("{} bytes written", written); }
Program by měl po svém spuštění napsat následující chybové hlášení (pokud ho samozřejmě nespouštíte s právy superuživatele):
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 13, message: "Permission denied" } }', ../src/ libcore/result.rs:788 note: Run with `RUST_BACKTRACE=1` for a backtrace.
Jinými slovy se v čase běhu programu (runtime) zjistilo, že se snažíme zavolat metodu Result.unwrap() ve chvíli, kdy je v této struktuře uložena struktura reprezentující chybu a nikoli handle otevřeného souboru.
4. Návratové typy operací File::create() a File::write()
Korektnější je samozřejmě důsledně testovat hodnoty vrácené operacemi File::create() a File::write() a samozřejmě i všech dalších I/O operací. To konkrétně znamená, že se namísto volání metody unwrap():
use std::io::prelude::*; use std::fs::File; fn main() { let mut fout = File::create("test.txt").unwrap(); let written = fout.write(b"Hello, world!\n").unwrap(); println!("{} bytes written", written); }
může metodami is_ok() a is_err() otestovat, jaká hodnota je obalena v typu Result. Mnohem lepší je však použití nám již dobře známého pattern matchingu, viz navazující kapitolu.
5. Kontrola všech I/O operací v Rustu
Další demonstrační příklad je již napsán mnohem lepším způsobem, protože se v něm důsledně používá pattern matching pro přístup do datové struktury Result. Díky pattern matchingu navíc ušetříme nepříjemné používání metody unwrap() atd.:
use std::io::prelude::*; use std::fs::File; fn write_message_to_file(mut fout: &File) { match fout.write(b"Hello, world!\n") { Ok(written) => { println!("{} bytes written", written); } Err(error) => { println!("write error: {}", error); } } } fn main() { match File::create("test.txt") { Ok(fout) => { write_message_to_file(&fout); } Err(error) => { println!("file create error: {}", error); } } }
Podívejme se nyní, co se stane ve chvíli, kdy se budeme snažit vytvořit soubor v adresáři, kde pro tuto operaci nemáme příslušná práva:
use std::io::prelude::*; use std::fs::File; fn write_message_to_file(mut fout: &File) { match fout.write(b"Hello, world!\n") { Ok(written) => { println!("{} bytes written", written); } Err(error) => { println!("write error: {}", error); } } } fn main() { match File::create("/bin/test.txt") { Ok(fout) => { write_message_to_file(&fout); } Err(error) => { println!("file create error: {}", error); } } }
file create error: Permission denied (os error 13)
6. Ve které chvíli se soubor zavře?
Ve druhé kapitole jsme si řekli, že se soubor automaticky zavře ve chvíli, kdy skončí viditelnost hodnoty typu File. V tento okamžik se zavolá destruktor, jehož úkolem je mj. i uzavření souboru. Ostatně se o tom můžeme relativně snadno přesvědčit. Upravíme si předchozí demonstrační příklad tak, aby se soubor vytvářel nikoli ve funkci main, ale ve funkci create_hello_world_file, která se z main volá. Na konci main navíc na standardní výstup vypíšeme nějaké hlášení. Upravený příklad vypadá následovně:
use std::io::prelude::*; use std::fs::File; fn write_message_to_file(mut fout: &File) { match fout.write(b"Hello, world!\n") { Ok(written) => { println!("{} bytes written", written); } Err(error) => { println!("write error: {}", error); } } } fn create_hello_world_file(file_name: &str) { match File::create(file_name) { Ok(fout) => { write_message_to_file(&fout); } Err(error) => { println!("file create error: {}", error); } } } fn main() { create_hello_world_file("test.txt"); // here the file should be closed println!("end of main"); }
Příklad přeložíme s využitím rustc a potom spustíme přes utilitu strace, která dokáže vypsat informace o systémových voláních. Výstup by měl být zhruba následující (nebojte se, hned si ho vysvětlíme):
execve("./test", ["./test"], [/* 53 vars */]) = 0 brk(0) = 0x7fa7a50df000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7a45c4000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=136983, ...}) = 0 mmap(NULL, 136983, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa7a45a2000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\16\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0644, st_size=14664, ...}) = 0 mmap(NULL, 2109744, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa7a41a0000 mprotect(0x7fa7a41a3000, 2093056, PROT_NONE) = 0 mmap(0x7fa7a43a2000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7fa7a43a2000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0po\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=141574, ...}) = 0 mmap(NULL, 2217264, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa7a3f82000 mprotect(0x7fa7a3f9b000, 2093056, PROT_NONE) = 0 mmap(0x7fa7a419a000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x18000) = 0x7fa7a419a000 mmap(0x7fa7a419c000, 13616, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fa7a419c000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260*\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0644, st_size=90160, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7a45a1000 mmap(NULL, 2186016, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa7a3d6c000 mprotect(0x7fa7a3d82000, 2093056, PROT_NONE) = 0 mmap(0x7fa7a3f81000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15000) = 0x7fa7a3f81000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P \2\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=1840928, ...}) = 0 mmap(NULL, 3949248, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa7a39a7000 mprotect(0x7fa7a3b61000, 2097152, PROT_NONE) = 0 mmap(0x7fa7a3d61000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ba000) = 0x7fa7a3d61000 mmap(0x7fa7a3d67000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fa7a3d67000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20V\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0644, st_size=1071552, ...}) = 0 mmap(NULL, 3166568, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa7a36a1000 mprotect(0x7fa7a37a6000, 2093056, PROT_NONE) = 0 mmap(0x7fa7a39a5000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x104000) = 0x7fa7a39a5000 close(3) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7a45a0000 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7a459e000 arch_prctl(ARCH_SET_FS, 0x7fa7a459e840) = 0 mprotect(0x7fa7a3d61000, 16384, PROT_READ) = 0 mprotect(0x7fa7a39a5000, 4096, PROT_READ) = 0 mprotect(0x7fa7a419a000, 4096, PROT_READ) = 0 mprotect(0x7fa7a43a2000, 4096, PROT_READ) = 0 mprotect(0x7fa7a4820000, 16384, PROT_READ) = 0 mprotect(0x7fa7a45c6000, 4096, PROT_READ) = 0 munmap(0x7fa7a45a2000, 136983) = 0 set_tid_address(0x7fa7a459eb10) = 4457 set_robust_list(0x7fa7a459eb20, 24) = 0 futex(0x7fff548a3e60, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1, NULL, 7fa7a459e840) = -1 EAGAIN (Resource temporarily unavailable) rt_sigaction(SIGRTMIN, {0x7fa7a3f889f0, [], SA_RESTORER|SA_SIGINFO, 0x7fa7a3f92330}, NULL, 8) = 0 rt_sigaction(SIGRT_1, {0x7fa7a3f88a80, [], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x7fa7a3f92330}, NULL, 8) = 0 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0 readlink("/etc/malloc.conf", 0x7fff548a2e10, 4096) = -1 ENOENT (No such file or directory) brk(0) = 0x7fa7a50df000 mmap(NULL, 2097152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7a34a1000 munmap(0x7fa7a34a1000, 2097152) = 0 mmap(NULL, 4190208, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7a32a2000 munmap(0x7fa7a32a2000, 1433600) = 0 munmap(0x7fa7a3600000, 659456) = 0 open("/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 3 read(3, "0-3\n", 8192) = 4 close(3) = 0 rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7fa7a39ddcb0}, {SIG_DFL, [], 0}, 8) = 0 mmap(NULL, 2097152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7a3200000 open("/proc/self/maps", O_RDONLY|O_CLOEXEC) = 3 getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0 fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7a45c3000 read(3, "7fa7a3200000-7fa7a3600000 rw-p 0"..., 1024) = 1024 read(3, " /lib/x86_64-linux-gnu"..., 1024) = 1024 read(3, "000 08:01 7341019 "..., 1024) = 1024 read(3, "26000 rw-p 00000000 00:00 0 \n7ff"..., 1024) = 274 close(3) = 0 munmap(0x7fa7a45c3000, 4096) = 0 sched_getaffinity(4457, 32, {f, 0, 0, 0}) = 32 mmap(0x7fff540a6000, 4096, PROT_NONE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fff540a6000 rt_sigaction(SIGSEGV, {0x7fa7a45d6960, [], SA_RESTORER|SA_STACK|SA_SIGINFO, 0x7fa7a3f92330}, NULL, 8) = 0 rt_sigaction(SIGBUS, {0x7fa7a45d6960, [], SA_RESTORER|SA_STACK|SA_SIGINFO, 0x7fa7a3f92330}, NULL, 8) = 0 sigaltstack(NULL, {ss_sp=0, ss_flags=SS_DISABLE, ss_size=0}) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7a45c2000 sigaltstack({ss_sp=0x7fa7a45c2000, ss_flags=0, ss_size=8192}, NULL) = 0 open("test.txt", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 3 ioctl(3, FIOCLEX) = 0 write(3, "Hello, world!\n", 14) = 14 write(1, "14 bytes written\n", 17) = 17 close(3) = 0 write(1, "end of main\n", 12) = 12 sigaltstack({ss_sp=0, ss_flags=SS_DISABLE, ss_size=8192}, NULL) = 0 munmap(0x7fa7a45c2000, 8192) = 0 exit_group(0) = ? +++ exited with 0 +++
Důležité jsou především tyto čtyři řádky:
open("test.txt", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 3 write(3, "Hello, world!\n", 14) = 14 close(3) = 0 write(1, "end of main\n", 12) = 12
Z nichž se dozvíme, že:
- Byl otevřen soubor s názvem „test.txt“ a byl mu přiřazen deskriptor 3.
- Do tohoto souboru byl zapsán řetězec o délce čtrnácti bajtů.
- Soubor byl zavřen.
- Teprve poté se vypsala zpráva na standardní výstup (do deskriptoru číslo 1).
7. Přečtení jednoho řádku ze standardního vstupu
Další užitečnou operací je přečtení jednoho textového řádku ze standardního vstupu. Zde je situace velmi jednoduchá, neboť je možné použít metodu read_line() struktury std::io::Stdin. Metodě read_line() se předává reference na String, který musí být pochopitelně měnitelný (mutable):
use std::io; fn main() { let stdin = io::stdin(); let mut line = String::new(); stdin.read_line(&mut line); println!("Echo: '{}' ({} characters)", line.trim(), line.len()); }
Poznámka: povšimněte si, že není nutné specifikovat maximální délku řetězce, předalokovávat String atd. Vše se děje automaticky a především bezpečně, na rozdíl od již zmíněné známé funkce gets().
8. Iterátor pro přečtení všech řádků ze standardního vstupu
Pokud je nutné přečíst větší množství řádků ze standardního vstupu, je většinou nejjednodušší s využitím metody lock() získat exkluzivní přístup ke standardnímu vstupu. Předností je, že vrácený typ implementuje trait BufRead a tím pádem i metodu lines() vracející iterátor pro jednotlivé řádky přečtené ze standardního vstupu. Řádky jsou vráceny bez \n na konci:
use std::io; use std::io::BufRead; fn main() { let stdin = io::stdin(); let stdin_lock = stdin.lock(); for line in stdin_lock.lines() { match line { Ok(content) => { println!("Echo: '{}' ({} characters)", content.trim(), content.len()); } Err(error) => { println!("stdin read error: {}", error); } } } }
9. Zpracování textových souborů
Prakticky stejným způsobem, jakým jsme četli jednotlivé textové řádky ze standardního vstupu, je možné číst textové řádky z libovolného otevřeného souboru. To je ukázáno v následujícím demonstračním příkladu, v němž nejdříve provedeme pokus o otevření souboru metodou File::open():
match File::open("/etc/passwd") { Ok(fin) => { read_content(&fin); } Err(error) => { println!("file open error: {}", error); } }
Struktura File implementuje trait Read, takže je možné provádět čtení po jednotlivých bajtech či po sekvenci bajtů, ovšem pokud potřebujeme pracovat s celými textovými řádky, je nutné použít bufferovaný vstup reprezentovaný strukturou typu BufReader. Její získání je snadné:
let reader = BufReader::new(struktura_typu_File);
Následně lze iteraci přes textové řádky provést následujícím způsobem:
for line in reader.lines() { match line { Ok(content) => { println!("{}", content); } Err(error) => { println!("stdin read error: {}", error); } } }
Iterátor v tomto případě korektně skončí ve chvíli, kdy je dosaženo konce souboru. Jinými slovy: neprovede se větev Err(error).
Celý zdrojový kód vypadá následovně:
use std::io::BufRead; use std::io::BufReader; use std::fs::File; fn read_content(fin: &File) { let reader = BufReader::new(fin); for line in reader.lines() { match line { Ok(content) => { println!("{}", content); } Err(error) => { println!("stdin read error: {}", error); } } } } fn main() { match File::open("/etc/passwd") { Ok(fin) => { read_content(&fin); } Err(error) => { println!("file open error: {}", error); } } }
10. Repositář s demonstračními příklady
Všechny dnes popisované demonstrační příklady byly, ostatně podobně jako ve všech předchozích částech tohoto seriálu, uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/presentations. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář:
Příklad | Adresa |
---|---|
298_file_create1.rs | https://github.com/tisnik/presentations/blob/master/rust/298_file_create1.rs |
299_file_create_error_panic.rs | https://github.com/tisnik/presentations/blob/master/rust/299_file_create_error_panic.rs |
300_file_create2.rs | https://github.com/tisnik/presentations/blob/master/rust/300_file_create2.rs |
301_file_create_error.rs | https://github.com/tisnik/presentations/blob/master/rust/301_file_create_error.rs |
302_when_file_is_closed.rs | https://github.com/tisnik/presentations/blob/master/rust/302_when_file_is_closed.rs |
303_stdin.rs | https://github.com/tisnik/presentations/blob/master/rust/303_stdin.rs |
304_stdin_lock.rs | https://github.com/tisnik/presentations/blob/master/rust/304_stdin_lock.rs |
305_file_open.rs | https://github.com/tisnik/presentations/blob/master/rust/305_file_open.rs |
Překlad se provede příkazem:
rustc jméno_zdrojového_souboru.rs
11. Odkazy na Internetu
- 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