Obsah
1. Programovací jazyk Rust: rozhraní mezi Rustem a Pythonem (pokračování)
2. Rozhraní mezi Pythonem a Rustem při předávání řetězců
3. Kdo se postará o uvolnění řetězce z operační paměti?
4. Předání řetězce z Pythonu do Rustu
5. Část aplikace naprogramovaná v Rustu
6. Testovací skript určený pro Python 2.x
7. Testovací skript určený pro Python 3.x
8. Vytvoření řetězce v Rustu s jeho použitím v Pythonu
9. Část aplikace naprogramovaná v Rustu
10. Testovací skript určený pro Python
11. Předání „slice“ z Pythonu do Rustu
12. Část aplikace naprogramovaná v Rustu
13. Testovací skript určený pro Python
14. Vylepšení aplikace pro předání „slice“ z Pythonu do Rustu
15. Repositář s demonstračními příklady
1. Programovací jazyk Rust: rozhraní mezi Rustem a Pythonem (pokračování)
V minulé části seriálu o programovacím jazyku Rust jsme si vysvětlili, jakým způsobem je možné zajistit komunikaci mezi částí aplikace naprogramovanou v Rustu a částí naprogramovanou v Pythonu. Popsaný princip byl poměrně jednoduchý – část psaná v Rustu se musela přeložit do nativního (strojového) kódu takovým způsobem, aby nedocházelo k name manglingu jmen funkcí; překlad navíc musel být proveden do statické či ještě lépe dynamické knihovny. Na straně programovacího jazyka Python se použil modul ctypes popř. alternativně CFFI, který dynamickou knihovnu načetl, umožnil přesně specifikovat typy argumentů nativních funkcí i jejich návratové typy a nakonec umožnil zavolání nativních funkcí.
Připomeňme si, že u funkcí akceptujících argumenty primitivních datových typů bylo použití ctypes velmi jednoduché:
pub extern fn add_integers(x: i32, y: i32) -> i32 { x + y }
Skript napsaný v Pythonu mohl tuto nativní funkci volat následovně:
#!/usr/bin/env python3 import ctypes testlib1 = ctypes.CDLL("cesta/ke/knihovně/libtest1.so") result = testlib1.add_integers(1, 2) print("1 + 2 = {}".format(result))
Poněkud složitější je předávání struktur odkazem:
#[repr(C)] pub struct Complex { real: f32, imag: f32, } #[no_mangle] pub extern fn add_complex_mut(c1: &mut Complex, c2: Complex) -> () { c1.real += c2.real; c1.imag += c2.imag; }
Zde již skript psaný v Pythonu potřebuje explicitní informace o typech parametrů:
#!/usr/bin/env python3 import ctypes testlib4 = ctypes.CDLL("cesta/ke/knihovně/libtest4.so") class Complex(ctypes.Structure): _fields_ = [("real", ctypes.c_float), ("imag", ctypes.c_float)] def __str__(self): return "Complex: %f + i%f" % (self.real, self.imag) libtest4.add_complex_mut.argtypes = (ctypes.POINTER(Complex), Complex) libtest4.add_complex_mut.restype = None c1 = Complex(1.0, 2.0) c2 = Complex(3.0, 4.0) libtest4.add_complex_mut(ctypes.byref(c1), c2) print(c1)
2. Rozhraní mezi Pythonem a Rustem při předávání řetězců
Velmi často se setkáme s nutností předávání řetězců mezi Pythonem a Rustem. Může se jednat o předání řetězců z Pythonu do Rustu či naopak o získání řetězce z Rustu skriptem psaným v Pythonu. To, zda je řetězec vytvořen v Pythonu či v Rustu, má velký vliv na to, jak se k řetězci budeme chovat, protože oba programovací jazyky používají odlišný způsob alokace a dealokace objektů, takže může docházet k různým typům problémů, od memory leaků až po pády aplikace. Další potenciální problémy mohou být způsobeny tím, že rozhraní mezi Pythonem a Rustem je (nejenom) z historických důvodů založeno na typovém systému céčka, takže vlastně budeme pracovat s ukazateli na pole znaků. Naopak prakticky bezproblémové je řešení problematiky kódování znaků v řetězcích, protože jak programovací jazyk Rust, tak i Python (Python 3 navíc i implicitně) používají Unicode a kódování UTF-8.
3. Kdo se postará o uvolnění řetězce z operační paměti?
Programovací jazyk Rust používá pro určení, zda je nějaký objekt možné uvolnit z paměti, viditelnost objektu určovanou v době překladu. Python (přesněji řečeno v tomto kontextu CPython) naproti tomu používá klasický garbage collector. Pokud je řetězec vytvořen v Pythonu a předán do kódu psaného v Rustu, je předání typicky provedeno přes ukazatel a tudíž překladač Rustu ví, že řetězec (resp. přesněji řečeno libovolný objekt předaný přes ukazatel) nevlastní a tudíž nijak nehlídá jeho viditelnost/životnost. To je ve skutečnosti velmi dobré chování, neboť o odstranění řetězce se postará runtime Pythonu a tudíž nedojde k pokusu o dvojí dealokaci. Musíme ovšem sami zajistit, aby část programu naprogramovaná v Rustu k originálnímu řetězci již nepřistupovala, takže se typicky musí provést explicitní kopie (ve skutečnosti se ovšem většinou s řetězcem pracuje v jediné funkci, takže ani to není nutné). Pokud je naopak řetězec vytvořen v Rustu, musíme ho předat (vrátit) do Pythonu přes ukazatel a explicitně se postarat o jeho uvolnění!
4. Předání řetězce z Pythonu do Rustu
V dnešním prvním demonstračním příkladu se pokusíme vytvořit řetězec v Pythonu (což samozřejmě není nic složitého) a následně ho předat do funkce naprogramované v Rustu. Pro jednoduchost rustovská funkce řetězec pouze vytiskne a neprovede s ním žádné další operace. Předání bude vypadat zhruba následovně:
+-------------------------+ | řetězec v Pythonu | +-------------------------+ ⇓ +-------------------------+ | sekvence bajtů | +-------------------------+ ⇓ +-------------------------+ | char * | +-------------------------+ ⇓ +-------------------------+ | CStr | +-------------------------+ ⇓ +-------------------------+ | Result<&str, Utf8Error> | +-------------------------+ ⇓ +-------------------------+ | &str | +-------------------------+
To sice nevypadá příliš jednoduše, na druhou stranu jsou však jednotlivé konverze otázkou jediného řádku kódu.
5. Část aplikace naprogramovaná v Rustu
Podívejme se, jak vypadá rustovská část aplikace. V ní vytvoříme funkci nazvanou print_string(), která akceptuje jediný parametr typu *const c_char, což je nejbližší obdoba const char * v programovacím jazyku C. Nyní z tohoto ukazatele vytvoříme hodnotu typu CStr, která je chápána jako borrowed, tj. funkce ji nebude vlastnit a nedojde k pokusu o automatickou dealokaci. Následně tento typ převedeme na běžný slice &str, s nímž je již možné běžně pracovat. Povšimněte si volání unwrap(), které je zde nutné, protože ve skutečnosti metoda to_str() vrací typ Result<&str, Utf8Error>, jelikož při pokusu o konverzi libovolné sekvence bajtů do UTF-8 může dojít k chybám:
use std::ffi::CStr; use std::os::raw::c_char; #[no_mangle] pub extern fn print_string(what: *const c_char) -> () { unsafe { let c_string = CStr::from_ptr(what).to_str().unwrap(); println!("{:?}", c_string); } }
6. Testovací skript určený pro Python 2.x
Testovací skript nyní bude existovat ve dvou verzích, z nichž první je určena pro Python 2.x a druhá pro Python 3.x. V Pythonu 2.x je nejprve nutné specifikovat typ parametru funkce print_string, zde konkrétně použijeme typ c_char_p. Následně je již možné funkci zavolat a předat jí řetězec přetypovaný na c_char_p:
#!/usr/bin/env python2 # vim: set fileencoding=utf-8 import ctypes libtest5 = ctypes.CDLL("target/debug/libtest5.so") libtest5.print_string.argtypes = (ctypes.c_char_p,) libtest5.print_string(ctypes.c_char_p("Hello world!")) libtest5.print_string(ctypes.c_char_p("Příliš žluťoučký kůň")) libtest5.print_string(ctypes.c_char_p("Ну, погоди!"))
Ve skutečnosti můžeme v Pythonu 2 celý zápis ještě více zkrátit a volat nativní funkci print_string() bez explicitního přetypování:
#!/usr/bin/env python2 # vim: set fileencoding=utf-8 import ctypes libtest5 = ctypes.CDLL("target/debug/libtest5.so") libtest5.print_string.argtypes = (ctypes.c_char_p,) libtest5.print_string("Hello world!") libtest5.print_string("Příliš žluťoučký kůň") libtest5.print_string("Ну, погоди!")
Povšimněte si, že bez problémů používáme Unicode.
7. Testovací skript určený pro Python 3.x
V Pythonu 3 je nutné provést nepatrné úpravy, protože převod řetězce (zde Unicode řetězce) na sekvenci bajtů vyžaduje explicitní volání metody str.encode() s určením konkrétního kódování:
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import ctypes libtest5 = ctypes.CDLL("target/debug/libtest5.so") libtest5.print_string.argtypes = (ctypes.c_char_p,) libtest5.print_string("Hello world!".encode('utf-8')) libtest5.print_string("Příliš žluťoučký kůň".encode('utf-8')) libtest5.print_string("Ну, погоди!".encode('utf-8'))
Vzhledem k tomu, že pro encode() je kódování UTF-8 implicitní, lze skript ještě zjednodušit:
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import ctypes libtest5 = ctypes.CDLL("target/debug/libtest5.so") libtest5.print_string.argtypes = (ctypes.c_char_p,) libtest5.print_string("Hello world!".encode()) libtest5.print_string("Příliš žluťoučký kůň".encode()) libtest5.print_string("Ну, погоди!".encode())
8. Vytvoření řetězce v Rustu s jeho použitím v Pythonu
Předchozí příklad byl poměrně jednoduchý, protože řetězec byl vytvořen v Pythonu, jehož běhové prostředí se posléze automaticky postaralo o jeho uvolnění z operační paměti. Co se však stane v opačném případě, tj. ve chvíli, kdy řetězec vytvoříme v Rustu a předáme ho (jako návratovou hodnotu) do Pythonu? V takovém případě musíme sami (!) zajistit následující chování:
- Rust nesmí řetězec automaticky dealokovat při opuštění funkce či bloku.
- Python taktéž nesmí řetězec automaticky dealokovat (nepatří mu, navíc provádí alokace a dealokace jiným způsobem).
- Musíme vytvořit funkci pro dealokaci řetězce (v Rustu) a tu explicitně zavolat.
Řešením je použití takzvaných raw pointerů, kdy se při vytvoření raw pointeru z nějakého objektu explicitně vzdáváme vlastnictví (ownership).
9. Část aplikace naprogramovaná v Rustu
Část aplikace naprogramovaná v Rustu je nyní delší, protože obsahuje jak funkci pro vytvoření řetězce (zde pro ilustraci řetězce se sekvencí hvězdiček), tak i funkci, která řetězec bude dealokovat z operační paměti. Povšimněte si, že nyní z řetězce (typ String) vytváříme objekt CString a z něho získáme raw pointer. Raw pointer je současně návratovou hodnotou funkce a navíc se řetězec neodstraní z paměti před návratem z funkce (což je implicitní chování Rustu). Naopak funkce pro uvolnění řetězce dealokaci provádí, ale implicitně – z raw pointeru vytvoříme objekt CString (tím současně získáme i vlastnictví/ownership) a ten ihned zahodíme – a právě v této chvíli může Rust provést dealokaci:
use std::iter; use std::ffi::CString; use std::os::raw::c_char; #[no_mangle] pub extern fn generate_stars(count: u8) -> *mut c_char { let s: String = iter::repeat("*").take(count as usize).collect(); let c_string = CString::new(s).unwrap(); let raw = c_string.into_raw(); println!("output raw pointer: {:?}", raw); raw } #[no_mangle] pub extern fn free_string(raw: *mut c_char) { unsafe { if raw.is_null() { return } println!("raw pointer to free: {:?}", raw); CString::from_raw(raw) }; }
Poznámka: obecně platí, že funkce Objekt.into_raw() a from_raw() se musí vyskytovat ve dvojici. Pokud tomu tak není (volá se jen into_raw()), bude v aplikaci pravděpodobně docházet k memory leakům.
10. Testovací skript určený pro Python
I skript naprogramovaný v Pythonu je nepatrně delší, protože musíme zajistit volání funkce free_string(), jelikož jinak by řetězec nikdy nebyl uvolněn z paměti (což samozřejmě bude vadit ve chvíli, kdy funkci generate_stars() voláme častěji popř. se jedná o aplikaci běžící po dlouhou dobu). Uvolnění řetězce zajistíme jednoduše konstrukcí try-(return)-finally:
#!/usr/bin/env python2 # vim: set fileencoding=utf-8 import ctypes libtest6 = ctypes.CDLL("target/debug/libtest6.so") libtest6.generate_stars.argtypes = (ctypes.c_uint8, ) libtest6.generate_stars.restype = ctypes.c_void_p # pozor na nutnost uvedení čárky - máme n-tici s jediným prvkem libtest6.free_string.argtypes = (ctypes.c_void_p, ) def generate_stars(count): pointer = libtest6.generate_stars(count) try: return ctypes.cast(pointer, ctypes.c_char_p).value.decode('utf-8') finally: libtest6.free_string(pointer) print(generate_stars(42))
11. Předání „slice“ z Pythonu do Rustu
V závěrečné třetině článku si ukážeme, jakým způsobem je možné předat řez (slice) z Pythonu do Rustu. Řezy jsou velmi užitečnou datovou strukturou, protože nabízí stejně efektivní způsob uložení prvků i stejně efektivní přístup k prvkům jako pole a současně obsahují i počet prvků (resp. délku řezu, protože délka závisí jak na počtu prvků, tak i na jejich velikosti). To mj. znamená, že je možné řezy použít pro předávání n-tic nebo seznamů z Pythonu do Rustu. Ve skutečnosti však nebude řez předán jediným parametrem, ale parametry dvěma – ukazatelem na data (pole) a velikostí řezu. Z těchto dvou parametrů pak funkcí from_raw_parts(p: *const T, len: usize) → &'a [T] vytvoříme řez, s nímž je možné dále pracovat. O dealokaci se nemusíme starat, neboť tu zajistí běhové prostředí Pythonu; to však samozřejmě znamená, že rustovská část aplikace musí počítat s tím, že po opuštění volané funkce může řez přestat existovat (tudíž si na něj nesmí vytvářet ukazatele, předávat ownership atd.)
12. Část aplikace naprogramovaná v Rustu
V části aplikace naprogramované v Rustu je deklarována funkce, která očekává ukazatel na prvky typu i32 a taktéž počet prvků řezu. S těmito údaji je zavolána již výše zmíněná funkce from_raw_parts() (navíc se délka musí přetypovat). Získaný řez použijeme při výpočtu součtu všech prvků, které se v řezu nachází. Výsledný součet je současně i návratovou hodnotou funkce:
use std::slice; #[no_mangle] pub extern fn sum(items: *const i32, length: usize) -> i32 { let numbers = unsafe { slice::from_raw_parts(items, length as usize) }; let mut sum:i32 = 0; for number in numbers { sum += *number } sum }
Poznámka: length musí obsahovat počet prvků, nikoli délku řezu v bajtech. Převod na bajty si provede funkce from_raw_parts() sama.
13. Testovací skript určený pro Python
Testovací skript naprogramovaný v Pythonu obsahuje deklaraci pomocné funkce sum(), jejímž účelem je získat seznam či sekvenci a z ní vytvořit dvojici ukazatel_na_první_prvek+délka (počet prvků, ne počet bajtů). Tyto dva údaje jsou předány rustovské funkci:
#!/usr/bin/env python2 # vim: set fileencoding=utf-8 import ctypes libtest7 = ctypes.CDLL("target/debug/libtest7.so") libtest7.sum.argtypes = (ctypes.POINTER(ctypes.c_uint32), ctypes.c_size_t) libtest7.sum.restype = ctypes.c_int32 def sum(numbers): buf_type = ctypes.c_uint32 * len(numbers) buf = buf_type(*numbers) return libtest7.sum(buf, len(numbers)) print(sum([1,2,3,4])) print(sum(range(11)))
Všimněte si, že do funkce sum() můžeme předat jak seznam, tak i sekvenci (v Pythonu 3).
14. Vylepšení aplikace pro předání „slice“ z Pythonu do Rustu
Nativní část aplikace psanou v Rustu je možné vylepšit. Nejprve do bloku usafe přidáme aserci testující, zda se náhodou funkce nevolá s prvním parametrem nastaveným na NULL. To obecně v Rustu není možné, ovšem ukazatele získané z jiných jazyků jsou v tomto ohledu výjimečné. Mimochodem si povšimněte, že celý blok unsafe je ukončen výrazem (na jeho konci není středník), jehož výsledek se uloží do proměnné numbers. Druhá úprava spočívá ve výpočtu sumy napsaném na jediném řádku funkcionálním stylem, s nímž jsme se již v Rustu několikrát setkali. Opět si povšimněte, že celý řádek je výrazem, jehož výsledná hodnota je současně výsledkem celé funkce:
use std::slice; #[no_mangle] pub extern fn sum(items: *const i32, length: usize) -> i32 { let numbers = unsafe { assert!(!items.is_null()); slice::from_raw_parts(items, length as usize) }; numbers.iter().fold(0, |acc, v| acc + v) }
15. Repositář s demonstračními příklady
Všechny čtyři dnes popisované demonstrační příklady (projekty) 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. Demonstrační příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář (ovšem u projektů je lepší mít celý repositář, abyste nemuseli pracně stahovat všechny potřebné soubory):
16. Odkazy na Internetu
- Pragmatic Unicode
https://nedbatchelder.com/text/unipain.html - The Rust FFI Omnibus
http://jakegoulding.com/rust-ffi-omnibus/ - class str (Python)
https://docs.python.org/3/library/stdtypes.html#str - Build Script Support
http://doc.crates.io/build-script.html - Calling Rust From Python
https://bheisler.github.io/post/calling-rust-in-python/ - Calling Rust in Python (komentáře k předchozímu článku)
https://www.reddit.com/r/rust/comments/63iy5a/calling_rust_in_python/ - CFFI Documentation
https://cffi.readthedocs.io/en/latest/ - Build Script Support
http://doc.crates.io/build-script.html - Creating a shared and static library with the gnu compiler [gcc]
http://www.adp-gmbh.ch/cpp/gcc/create_lib.html - ctypes — A foreign function library for Python
https://docs.python.org/2/library/ctypes.html - FFI: Foreign Function Interface
https://doc.rust-lang.org/book/ffi.html - Primitive Type pointer
https://doc.rust-lang.org/std/primitive.pointer.html - Cargo: správce projektů a balíčků pro programovací jazyk Rust
https://mojefedora.cz/cargo-spravce-projektu-a-balicku-pro-programovaci-jazyk-rust/ - Network Communication and Serialization in Rust
https://www.safaribooksonline.com/blog/2014/01/28/network-communication-serialization-rust/ - Crate bincode
http://tyoverby.com/bincode/bincode/index.html - Struct std::fs::File
https://doc.rust-lang.org/std/fs/struct.File.html - Trait std::io::Seek
https://doc.rust-lang.org/std/io/trait.Seek.html - Trait std::io::Read
https://doc.rust-lang.org/std/io/trait.Read.html - Trait std::io::Write
https://doc.rust-lang.org/std/io/trait.Write.html - Trait std::io::BufRead
https://doc.rust-lang.org/std/io/trait.BufRead.html - Module std::io::prelude
https://doc.rust-lang.org/std/io/prelude/index.html - std::net::IpAddr
https://doc.rust-lang.org/std/net/enum.IpAddr.html - std::net::Ipv4Addr
https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html - std::net::Ipv6Addr
https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html - TcpListener
https://doc.rust-lang.org/std/net/struct.TcpListener.html - TcpStream
https://doc.rust-lang.org/std/net/struct.TcpStream.html - Binary heap (Wikipedia)
https://en.wikipedia.org/wiki/Binary_heap - Binární halda (Wikipedia)
https://cs.wikipedia.org/wiki/Bin%C3%A1rn%C3%AD_halda - Halda (datová struktura)
https://cs.wikipedia.org/wiki/Halda_%28datov%C3%A1_struktura%29 - Struct std::collections::HashSet
https://doc.rust-lang.org/std/collections/struct.HashSet.html - Struct std::collections::BTreeSet
https://doc.rust-lang.org/std/collections/struct.BTreeSet.html - Struct std::collections::BinaryHeap
https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html - Set (abstract data type)
https://en.wikipedia.org/wiki/Set_%28abstract_data_type%29#Language_support - Associative array
https://en.wikipedia.org/wiki/Associative_array - Hash Table
https://en.wikipedia.org/wiki/Hash_table - B-tree
https://en.wikipedia.org/wiki/B-tree - Pedro Celis: Robin Hood Hashing (naskenované PDF!)
https://cs.uwaterloo.ca/research/tr/1986/CS-86–14.pdf - Robin Hood hashing
http://codecapsule.com/2013/11/11/robin-hood-hashing/ - Robin Hood hashing: backward shift deletion
http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/ - Module std::collections
https://doc.rust-lang.org/std/collections/ - Module std::vec
https://doc.rust-lang.org/nightly/std/vec/index.html - Struct std::collections::VecDeque
https://doc.rust-lang.org/std/collections/struct.VecDeque.html - Struct std::collections::LinkedList
https://doc.rust-lang.org/std/collections/struct.LinkedList.html - Module std::fmt
https://doc.rust-lang.org/std/fmt/ - Macro std::println
https://doc.rust-lang.org/std/macro.println.html - Enum std::result::Result
https://doc.rust-lang.org/std/result/enum.Result.html - Module std::result
https://doc.rust-lang.org/std/result/ - Result
http://rustbyexample.com/std/result.html - Rust stdlib: Option
https://doc.rust-lang.org/std/option/enum.Option.html - Module std::option
https://doc.rust-lang.org/std/option/index.html - Rust by example: option
http://rustbyexample.com/std/option.html - Rust by example: if-let
http://rustbyexample.com/flow_control/if_let.html - Rust by example: while let
http://rustbyexample.com/flow_control/while_let.html - Rust by example: Option<i32>
http://rustbyexample.com/std/option.html - An Overview of Macros in Rust
http://words.steveklabnik.com/an-overview-of-macros-in-rust - A Practical Intro to Macros in Rust 1.0
https://danielkeep.github.io/practical-intro-to-macros.html - The Rust Programming Language: macros
https://doc.rust-lang.org/beta/book/macros.html - Rust by example: 15 macro_rules!
http://rustbyexample.com/macros.html - Primitive Type isize
https://doc.rust-lang.org/nightly/std/primitive.isize.html - Primitive Type usize
https://doc.rust-lang.org/nightly/std/primitive.usize.html - Primitive Type array
https://doc.rust-lang.org/nightly/std/primitive.array.html - Module std::slice
https://doc.rust-lang.org/nightly/std/slice/ - Rust by Example: 2.3 Arrays and Slices
http://rustbyexample.com/primitives/array.html - What is the difference between Slice and Array (stackoverflow)
http://stackoverflow.com/questions/30794235/what-is-the-difference-between-slice-and-array - Learning Rust With Entirely Too Many Linked Lists
http://cglab.ca/~abeinges/blah/too-many-lists/book/ - Testcase: linked list
http://rustbyexample.com/custom_types/enum/testcase_linked_list.html - Operators and Overloading
https://doc.rust-lang.org/book/operators-and-overloading.html - Module std::ops
https://doc.rust-lang.org/std/ops/index.html - Module std::cmp
https://doc.rust-lang.org/std/cmp/index.html - Trait std::ops::Add
https://doc.rust-lang.org/stable/std/ops/trait.Add.html - Trait std::ops::AddAssign
https://doc.rust-lang.org/std/ops/trait.AddAssign.html - Trait std::ops::Drop
https://doc.rust-lang.org/std/ops/trait.Drop.html - Trait std::cmp::Eq
https://doc.rust-lang.org/std/cmp/trait.Eq.html - Struct std::boxed::Box
https://doc.rust-lang.org/std/boxed/struct.Box.html - Explore the ownership system in Rust
https://nercury.github.io/rust/guide/2015/01/19/ownership.html - Rust's ownership and move semantic
http://www.slideshare.net/saneyuki/rusts-ownership-and-move-semantics - Trait std::marker::Copy
https://doc.rust-lang.org/stable/std/marker/trait.Copy.html - Trait std::clone::Clone
https://doc.rust-lang.org/stable/std/clone/trait.Clone.html - The Stack and the Heap
https://doc.rust-lang.org/book/the-stack-and-the-heap.html - Rust Compare: Pointers & References
http://www.rust-compare.com/site/pointers.html - Rust Compare: Parameters
http://www.rust-compare.com/site/params.html - Why does this compile? Automatic dereferencing?
https://users.rust-lang.org/t/why-does-this-compile-automatic-dereferencing/2183 - Understanding Pointers, Ownership, and Lifetimes in Rust
http://koerbitz.me/posts/Understanding-Pointers-Ownership-and-Lifetimes-in-Rust.html - Rust lang series episode #25 — pointers (#rust-series)
https://steemit.com/rust-series/@jimmco/rust-lang-series-episode-25-pointers-rust-series - Rust – home page
https://www.rust-lang.org/en-US/ - Rust – Frequently Asked Questions
https://www.rust-lang.org/en-US/faq.html - Destructuring and Pattern Matching
https://pzol.github.io/getting_rusty/posts/20140417_destructuring_in_rust/ - The Rust Programming Language
https://doc.rust-lang.org/book/ - Rust (programming language)
https://en.wikipedia.org/wiki/Rust_%28programming_language%29 - Go – home page
https://golang.org/ - Stack Overflow – Most Loved, Dreaded, and Wanted language
https://stackoverflow.com/research/developer-survey-2016#technology-most-loved-dreaded-and-wanted - Rust vs Go (dva roky staré hodnocení, od té doby došlo k posunům v obou jazycích)
http://jaredforsyth.com/2014/03/22/rust-vs-go/ - Rust vs Go: My experience
https://www.reddit.com/r/golang/comments/21m6jq/rust_vs_go_my_experience/ - Friends of Rust (Organizations running Rust in production)
https://www.rust-lang.org/en-US/friends.html - Rust programs versus C++ g++
https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=rust&lang2=gpp - Další benchmarky (nejedná se o reálné příklady „ze života“)
https://github.com/kostya/benchmarks - Go na Redditu
https://www.reddit.com/r/golang/ - Rust vs. Go
http://vschart.com/compare/rust/vs/go-language - Abstraction without overhead: traits in Rust
https://blog.rust-lang.org/2015/05/11/traits.html - Method Syntax
https://doc.rust-lang.org/book/method-syntax.html - Traits in Rust
https://doc.rust-lang.org/book/traits.html - Functional Programming in Rust – Part 1 : Function Abstraction
http://blog.madhukaraphatak.com/functional-programming-in-rust-part-1/ - Of the emerging systems languages Rust, D, Go and Nim, which is the strongest language and why?
https://www.quora.com/Of-the-emerging-systems-languages-Rust-D-Go-and-Nim-which-is-the-strongest-language-and-why - Chytré ukazatele (moderní verze jazyka C++) [MSDN]
https://msdn.microsoft.com/cs-cz/library/hh279674.aspx - UTF-8 Everywhere
http://utf8everywhere.org/ - Rust by Example
http://rustbyexample.com/ - Rust oficiálně ve Fedoře
https://mojefedora.cz/rust-oficialne-ve-fedore/ - Resource acquisition is initialization
https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization - TIOBE index (October 2016)
http://www.tiobe.com/tiobe-index/ - Porovnání Go, D a Rustu na OpenHubu:
https://www.openhub.net/languages/compare?language_name[]=-1&language_name[]=-1&language_name[]=dmd&language_name[]=golang&language_name[]=rust&language_name[]=-1&measure=commits - String Types in Rust
http://www.suspectsemantics.com/blog/2016/03/27/string-types-in-rust/ - Trait (computer programming)
https://en.wikipedia.org/wiki/Trait_%28computer_programming%29 - Type inference
https://en.wikipedia.org/wiki/Type_inference