Hlavní navigace

Programovací jazyk Rust: spouštění nových procesů a komunikace s nimi

Pavel Tišnovský

V další části seriálu o jazyku Rust si ukážeme, jak je možné spustit nový proces, předat mu argumenty, upravit proměnné prostředí a také to, jak lze s tímto procesem komunikovat přes vstupně/výstupní proudy (streamy).

Obsah

1. Programovací jazyk Rust: spouštění nových procesů a komunikace s nimi

2. Postup při spouštění nového procesu

3. Příklad: vytvoření nového procesu s čekáním na jeho dokončení

4. Reakce na chybu při pokusu o vytvoření nového procesu

5. Předání argumentu nově vytvářenému procesu

6. Předání více argumentů spouštěnému procesu

7. Návratová hodnota procesu

8. Argumenty procesu předané pomocí vektoru

9. Pokus o spuštění lokálního skriptu

10. Nastavení proměnných prostředí pro nově vznikající proces

11. Odstranění vybrané proměnné prostředí

12. Převzetí dat posílaných procesem na standardní výstup

13. Repositář s demonstračními příklady

14. Odkazy na Internetu

1. Programovací jazyk Rust: spouštění nových procesů a komunikace s nimi

Pro spouštění procesů a základní komunikaci s nimi se používá několik struktur:

Struktura Význam
std::process::Command reprezentuje příkaz sloužící pro spuštění procesu
std::process::Child reprezentuje spuštěný nebo již zastavený proces
std::process::ExitStatus výsledek po zastavení procesu (jakýmkoli způsobem)
std::process::ChildStdin vstupní proud spuštěného procesu
std::process::ChildStdout výstupní proud spuštěného procesu
std::process::ChildStderr chybový proud spuštěného procesu

2. Postup při spouštění nového procesu

Před vytvořením nového procesu je nutné získat strukturu typu Command, která reprezentuje příkaz, jenž se má spustit, dále pak argumenty tohoto příkazu a v neposlední řadě také proměnné prostředí. Tato struktura, resp. přesněji řečeno její základní podoba, se získá konstruktorem new, kterému se předá jméno spouštěného příkazu:

let command = Command::new("ls");

Samotný proces se spustí metodou spawn vracející typ Result<Child>. Většinou se vytvoření příkazu kombinuje s jeho spuštěním na jeden programový řádek:

let process = Command::new("ls").spawn();

Pokud je zapotřebí čekat na dokončení spuštěného procesu, použije se metoda Child.wait() vracející hodnotu typu Result<ExitStatus>. Samotná struktura ExitStatus obsahuje jak návratový kód, tak i další užitečné informace o ukončeném procesu.

3. Příklad: vytvoření nového procesu s čekáním na jeho dokončení

Podívejme se nyní na způsob použití výše popsaných metod Command.spawn() a Child.wait() v příkladu, který spustí externí příkaz ls a následně vypíše návratový kód i další informace o právě ukončeném příkazu. Pro reakci na všechny případné chyby a pro získání hodnot obalených do typu Result je použit oblíbený pattern matching. Navíc si povšimněte modifikátoru mut, který je kvůli volání child.wait() vyžadován:

use std::process::Command;
 
fn main() {
    let process = Command::new("ls").spawn();
 
    match process {
        Ok(mut child) => {
            println!("spawn ok");
            match child.wait() {
                Ok(code) => {
                    println!("process exited with code: {}", code);
                }
                Err(err) => {
                    println!("failed to wait on child: {}", err);
                }
            }
        }
        Err(err) => {
            println!("spawn error: {}", err);
        }
    }
 
}

Po překladu byl program spuštěn v adresáři se všemi dnešními demonstračními příklady, takže se po spuštění vypsaly následující informace (tučně jsou zvýrazněny informace psané našim programem, nikoli příkazem ls):

spawn ok
308_spawn_process            308_spawn_process.rs
308.txt                      309_spawn_error.rs
310_process_arg.rs           311_process_args.rs
312_bad_directory.rs         313_process_args_in_vector.rs
314_local_script_error.rs    315_process_env_vars.rs
316_process_env_remove.rs    317_process_output.rs
hello.sh
process exited with code: exit code: 0

4. Reakce na chybu při pokusu o vytvoření nového procesu

Zkusme si nyní demonstrační příklad nepatrně upravit, a to konkrétně takovým způsobem, aby se namísto externího příkazu ls spouštěl neznámý příkaz unknown. Zbytek zdrojového kódu zůstává stejný s předchozím příkladem:

use std::process::Command;
 
fn main() {
    let process = Command::new("unknown").spawn();
 
    match process {
        Ok(mut child) => {
            println!("spawn ok");
            match child.wait() {
                Ok(code) => {
                    println!("process exited with code: {}", code);
                }
                Err(err) => {
                    println!("failed to wait on child: {}", err);
                }
            }
        }
        Err(err) => {
            println!("spawn error: {}", err);
        }
    }
 
}

Z výpisu je patrné, že chyba byla zachycena, a to konkrétně ve vnějším bloku pro pattern matching. Chybové hlášení je převzato z operačního systému:

spawn error: No such file or directory (os error 2)

5. Předání argumentu nově vytvářenému procesu

O předání argumentu nově vytvářenému procesu se postará metoda arg() zavolaná pro strukturu typu Command. Tato metoda akceptuje řetězec (konkrétně typu OsStr, což můžeme v této chvíli považovat za běžný řetězec) a vrací novou strukturu typu Command:

fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command

Pokud například potřebujeme předat nově spuštěnému procesu ls argument -1 (jeden soubor na řádek), použijeme namísto:

let process = Command::new("unknown").spawn();

Nepatrně upravený zápis:

let process = Command::new("ls").arg("-1").spawn();

Otestujme si předání argumentů to v novém příkladu:

use std::process::Command;
 
fn main() {
    let process = Command::new("ls").arg("-1").spawn();
 
    match process {
        Ok(mut child) => {
            println!("spawn ok");
            match child.wait() {
                Ok(code) => {
                    println!("process exited with code: {}", code);
                }
                Err(err) => {
                    println!("failed to wait on child: {}", err);
                }
            }
        }
        Err(err) => {
            println!("spawn error: {}", err);
        }
    }
 
}

Výsledkem spuštění přeloženého programu by mohly být následující řádky (samozřejmě opět v závislosti na skutečném obsahu aktuálního adresáře):

spawn ok
308_spawn_process.rs
309_spawn_error.rs
310_process_arg
310_process_arg.rs
310.txt
311_process_args.rs
312_bad_directory.rs
313_process_args_in_vector.rs
314_local_script_error.rs
315_process_env_vars.rs
316_process_env_remove.rs
317_process_output.rs
hello.sh
process exited with code: exit code: 0

6. Předání více argumentů spouštěnému procesu

Vzhledem k tomu, že metoda Command.arg() vrací novou strukturu typu Command, není samozřejmě žádným větším problémem zřetězit volání těchto metod a zajistit tak, aby se příkazu předalo větší množství argumentů. Podívejme se, jak příkazu ls předáme argument „-1“ (jeden soubor na řádek) s argumentem „/“ (výpis obsahu kořenového adresáře):

let process = Command::new("ls").arg("-1").arg("/").spawn();

Zakomponujeme toto volání do zdrojového kódu našeho demonstračního příkladu:

use std::process::Command;
 
fn main() {
    let process = Command::new("ls").arg("-1").arg("/").spawn();
 
    match process {
        Ok(mut child) => {
            println!("spawn ok");
            match child.wait() {
                Ok(code) => {
                    println!("process exited with code: {}", code);
                }
                Err(err) => {
                    println!("failed to wait on child: {}", err);
                }
            }
        }
        Err(err) => {
            println!("spawn error: {}", err);
        }
    }
 
}

Ukázka spuštění tohoto příkladu na Linux Mintu:

spawn ok
bin
boot
cdrom
dev
etc
home
initrd.img
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
vmlinuz
process exited with code: exit code: 0

7. Návratová hodnota procesu

Zkusme nyní příklad upravit takovým způsobem, aby se příkaz „ls“ snažil vypsat neexistující adresář „/xyzzy“ (který je tedy umístěn přímo v kořenovém adresáři). V takovém případě proces „ls“ samozřejmě nastartuje korektně (není důvod, aby se nespustil) a teprve poté dojde k chybě. Tato chyba je pro náš program reprezentována návratovým kódem, který bude odlišný od nuly. Konkrétně v případě příkazu „ls“ návratové kódy snadno zjistíme z manuálové stránky:

man ls
...
...
...
 
   Exit status:
       0      if OK,
 
       1      if minor problems (e.g., cannot access subdirectory),
 
       2      if serious trouble (e.g., cannot access command-line argument).

Zdrojový kód upraveného příkladu vypadá následovně:

use std::process::Command;
 
fn main() {
    let process = Command::new("ls").arg("-1").arg("/xyzzy").spawn();
 
    match process {
        Ok(mut child) => {
            println!("spawn ok");
            match child.wait() {
                Ok(code) => {
                    println!("process exited with code: {}", code);
                }
                Err(err) => {
                    println!("failed to wait on child: {}", err);
                }
            }
        }
        Err(err) => {
            println!("spawn error: {}", err);
        }
    }
 
}

V tomto případě se uplatní první větev vnořené konstrukce match, která je na výpisu zvýrazněna tučně. Ostatně je to patrné i ze zpráv vypisovaných příkladem na standardní výstup:

spawn ok
process exited with code: exit code: 2

8. Argumenty procesu předané pomocí vektoru

Vzhledem k tomu, že předávání většího množství argumentů nově vytvářenému procesu je v praxi velmi časté, obsahuje standardní knihovna Rustu i užitečnou metodu Command.args(), které lze předat „slice“ na vektor řetězců, které představují jednotlivé argumenty. To například znamená, že namísto:

let process = Command::new("ls").arg("-1").arg("/bin").arg("-c").spawn();

je možné napsat jen:

let process = Command::new("ls").args(&["-1", "/bin", "-c"]).spawn();

(povšimněte si, že skutečně vytváříme „slice“ na vektor).

Chování Command.args() si můžeme snadno odzkoušet:

use std::process::Command;
 
fn main() {
    let process = Command::new("ls").args(&["-1", "/bin", "-c"]).spawn();
 
    match process {
        Ok(mut child) => {
            println!("spawn ok");
            match child.wait() {
                Ok(code) => {
                    println!("process exited with code: {}", code);
                }
                Err(err) => {
                    println!("failed to wait on child: {}", err);
                }
            }
        }
        Err(err) => {
            println!("spawn error: {}", err);
        }
    }
 
}

Výsledkem by měl být obsah všech souborů a případných podadresářů umístěných v „/bin“:

spawn ok
udevadm
dbus-cleanup-sockets
dbus-daemon
dbus-uuidgen
loginctl
dmesg
lsblk
more
tailf
tar
findmnt
mount
umount
cpio
mt-gnu
mountpoint
pidof
chgrp
chmod
chown
dd
df
dir
false
ls
mknod
pwd
touch
true
vdir
cat
cp
date
echo
ln
mkdir
mktemp
mv
readlink
rm
rmdir
sleep
stty
sync
uname
ip
ss
fusermount
ulockmgr_server
login
su
kill
ps
plymouth-upstart-bridge
plymouth
running-in-container
rbash
bash
netstat
ping
ping6
vmmouse_detect
which
whiptail
ypdomainname
zcat
zcmp
zdiff
zegrep
zfgrep
zforce
zgrep
zless
zmore
znew
uncompress
unicode_start
tempfile
static-sh
run-parts
sed
setfacl
setfont
setupcon
sh
sh.distrib
red
ntfsinfo
ntfsls
ntfsmftalloc
ntfsmove
ntfstruncate
ntfswipe
open
openvt
ntfs-3g.secaudit
ntfs-3g.usermap
ntfscat
ntfsck
ntfscluster
ntfscmp
ntfsdump_logfile
ntfsfix
nisdomainname
ntfs-3g
ntfs-3g.probe
mt
lowntfs-3g
lsmod
less
lessecho
lessfile
lesskey
lesspipe
loadkeys
kbd_mode
keyctl
kmod
getfacl
grep
gunzip
gzexe
gzip
hostname
fuser
fgconsole
fgrep
ed
egrep
dnsdomainname
domainname
dumpkeys
dash
chacl
chvt
busybox
bzcat
bzcmp
bzdiff
bzegrep
bzexe
bzfgrep
bzgrep
bzip2
bzip2recover
bzless
bzmore
bunzip2
process exited with code: exit code: 0

9. Pokus o spuštění lokálního skriptu

Pokusme se nyní z aplikace naprogramované v Rustu spustit tento jednoduchý lokální skript, tj. skript umístěný v aktuálním adresáři:

echo "Hello world"

Pokus o spuštění bude vypadat takto:

use std::process::Command;
 
fn main() {
    let process = Command::new("hello.sh").spawn();
 
    match process {
        Ok(mut child) => {
            println!("spawn ok");
            match child.wait() {
                Ok(code) => {
                    println!("process exited with code: {}", code);
                }
                Err(err) => {
                    println!("failed to wait on child: {}", err);
                }
            }
        }
        Err(err) => {
            println!("spawn error: {}", err);
        }
    }
 
}

S poměrně velkou pravděpodobností se však tento skript nepodaří spustit a dostaneme následující chybové hlášení:

spawn error: No such file or directory (os error 2)

Co to znamená? Skript nebyl nalezen, a to z toho prostého důvodu, že většina (?) uživatelů nemá do proměnné prostředí PATH přidán aktuální adresář, tedy „.“, což je samozřejmě z hlediska bezpečnosti velmi rozumné.

10. Nastavení proměnných prostředí pro nově vznikající proces

Před spuštěním nového procesu je ovšem možné mu proměnné prostředí nastavit. K tomu slouží metoda Command.env(), které se předá jméno proměnné a její hodnota (většinou se jedná o řetězce) a která vrátí novou strukturu typu Command:

fn env<K, V>(&mut self, key: K, val: V) -> &mut Command

Vzhledem k tomu, že se vrací nový Command, je možné volání env() zřetězit, a to stejným způsobem, jako u metody arg() či args().

Úprava programu, který má spustit lokální skript, bude vypadat takto:

use std::process::Command;
 
fn main() {
    let process = Command::new("hello.sh").env("PATH", ".").spawn();
 
    match process {
        Ok(mut child) => {
            println!("spawn ok");
            match child.wait() {
                Ok(code) => {
                    println!("process exited with code: {}", code);
                }
                Err(err) => {
                    println!("failed to wait on child: {}", err);
                }
            }
        }
        Err(err) => {
            println!("spawn error: {}", err);
        }
    }
 
}

Ze zpráv vypsaných na standardní výstup je patrné, že se tentokrát spuštění podařilo:

spawn ok
Hello world!
process exited with code: exit code: 0

11. Odstranění vybrané proměnné prostředí

Pokud potřebujeme nějakou proměnnou prostředí naopak odstranit, může se použít metoda Command.env_remove(), které se předá jméno proměnné (hodnota samozřejmě nikoli) a kterou lze opět zřetězit:

let process = Command::new("ls").env_remove("PATH").spawn();

V případě, že si naopak chceme být jistí, že procesu nepředáme žádnou proměnnou získanou z rodičovského procesu, můžeme využít metodu Command.env_clear(). Typické použití může vypadat takto:

let process = Command::new("ls").env_clear().env("foo", "bar").env("password", "this_one").spawn();

Můžeme si to snadno odzkoušet:

use std::process::Command;
 
fn main() {
    let process = Command::new("ls").env_remove("PATH").spawn();
 
    match process {
        Ok(mut child) => {
            println!("spawn ok");
            match child.wait() {
                Ok(code) => {
                    println!("process exited with code: {}", code);
                }
                Err(err) => {
                    println!("failed to wait on child: {}", err);
                }
            }
        }
        Err(err) => {
            println!("spawn error: {}", err);
        }
    }
 
}

Výsledek spuštění tohoto programu:

spawn ok
308_spawn_process.rs
309_spawn_error.rs
310_process_arg.rs
311_process_args.rs
312_bad_directory.rs
313_process_args_in_vector.rs
314_local_script_error.rs
315_process_env_vars.rs
316_process_env_remove
316_process_env_remove.rs
316.txt
317_process_output.rs
hello2.sh
hello.sh
process exited with code: exit code: 0

12. Převzetí dat posílaných procesem na standardní výstup

Nyní se dostáváme k důležitému tématu – proces sice umíme spustit, ovšem ještě by bylo dobré umět zpracovat jeho standardní a chybový výstup popř. procesu poslat nějaká data přes jeho standardní vstup. Ve chvíli, kdy je již proces vytvořen, tj. když vznikla struktura std::process::Child, můžeme mít k dispozici všechny tři vstupně/výstupní proudy procesu, protože tato struktura vypadá zhruba následovně:

pub struct Child {
    pub stdin: Option<ChildStdin>,
    pub stdout: Option<ChildStdout>,
    pub stderr: Option<ChildStderr>,
}

Pokud například budeme chtít zpracovat standardní výstup nového procesu, musíme ho nakonfigurovat ještě před jeho spuštěním:

let process = Command::new("ls").arg("-1").stdout(Stdio::piped()).spawn();

Takto nakonfigurovaný proces používá klasickou rouru (pipe) pro komunikaci s naším programem a je tedy možné provést čtení jeho výstupu, například takto:

  1. Vytvoříme si pomocnou proměnnou – řetězec s měnitelnou délkou.
  2. Získáme standardní výstup procesu voláním Child.stdout (je typu Option, proto je nutné použít unwrap)
  3. Přečteme výstup buď celý (v praxi poměrně nebezpečné ve chvíli, kdy si nejsme jisti množstvím dat) nebo po částech do bufferu a zpracujeme ho.
  4. Uzavření výstupu se provede automaticky při výskoku z bloku.

Výše uvedené kroky se realizují programově takto:

let mut buffer = String::new();
let stdout = child.stdout.as_mut().unwrap();
match stdout.read_to_string(&mut buffer) {
    Ok(read_bytes) => {
        println!("read {} bytes", read_bytes);
        println!("{}", buffer);
    }
    Err(err) => {
        println!("read error: {}", err);
    }
}

Tyto příkazy jsou umístěny do samostatného bloku, aby se přesně stanovila živost (viditelnost) všech objektů a tím se mj. zaručilo, že bude možné zavolat Child.wait().

Podívejme se nyní na celý příklad:

use std::process::Command;
use std::process::Stdio;
use std::io::Read;
 
fn main() {
    let process = Command::new("ls").arg("-1").stdout(Stdio::piped()).spawn();
 
    match process {
        Ok(mut child) => {
            println!("spawn ok");
            {
                let mut buffer = String::new();
                let stdout = child.stdout.as_mut().unwrap();
                match stdout.read_to_string(&mut buffer) {
                    Ok(read_bytes) => {
                        println!("read {} bytes", read_bytes);
                        println!("{}", buffer);
                    }
                    Err(err) => {
                        println!("read error: {}", err);
                    }
                }
            }
            match child.wait() {
                Ok(code) => {
                    println!("process exited with code: {}", code);
                }
                Err(err) => {
                    println!("failed to wait on child: {}", err);
                }
            }
        }
        Err(err) => {
            println!("spawn error: {}", err);
        }
    }
 
}

Spuštění tohoto příkladu by mělo dát stejné výsledky, jako tomu bylo v příkladu předchozím, ovšem s jedním důležitým rozdílem – tentokrát veškerý výstup zpracoval náš program a nikoli přímo příkaz ls:

spawn ok
read 297 bytes
308_spawn_process.rs
309_spawn_error.rs
310_process_arg.rs
311_process_args.rs
312_bad_directory.rs
313_process_args_in_vector.rs
314_local_script_error.rs
315_process_env_vars.rs
316_process_env_remove
316_process_env_remove.rs
317_process_output
317_process_output.rs
317.txt
hello2.sh
hello.sh

13. 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ář:

14. Odkazy na Internetu

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