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
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
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:
- Vytvoříme si pomocnou proměnnou – řetězec s měnitelnou délkou.
- Získáme standardní výstup procesu voláním Child.stdout (je typu Option, proto je nutné použít unwrap)
- 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.
- 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/presentations. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář:
14. Odkazy na Internetu
- 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