Hlavní navigace

Programovací jazyk Rust: práce se soubory a se standardními proudy

Pavel Tišnovský

Většina běžných aplikací potřebuje pracovat se soubory popř. se standardními vstupními a výstupními proudy. Proto se dnes seznámíme s některými základními traity a funkcemi, které se pro vstupně-výstupní operace používají.

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

11. Odkazy na Internetu

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:

  1. Byl otevřen soubor s názvem „test.txt“ a byl mu přiřazen deskriptor 3.
  2. Do tohoto souboru byl zapsán řetězec o délce čtrnácti bajtů.
  3. Soubor byl zavřen.
  4. 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/pre­sentations. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář:

Překlad se provede příkazem:

rustc jméno_zdrojového_souboru.rs

11. Odkazy na Internetu

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