Obsah
1. Programovací jazyk Rust: metody a traity
2. Implementace jedné metody pro zvolenou strukturu
3. Způsoby implementace většího množství metod pro zvolenou strukturu
4. Metoda vracející novou strukturu
6. Funkce deklarovaná v kontextu vybrané struktury
9. Implementace traitu pro strukturu představující komplexní číslo
10. Implementace většího množství traitů
11. Repositář s demonstračními příklady
1. Programovací jazyk Rust: metody a traity
Ve čtvrté části seriálu o programovacím jazyce Rust jsme si popsali dvě důležité a často používané datové struktury. Jednalo se o n-tice (tuple) a taktéž o struktury (struct). Následně jsme se zmínili o problematice vlastnictví objektů a o sémantikách „move“ a „copy“. Dnes na obě tato témata navážeme, protože si ukážeme, jak lze pro zvolenou strukturu deklarovat funkce a metody, samozřejmě včetně konstruktorů (resp. přesněji řečeno funkcí, které se jako konstruktory mohou chovat). Ve druhé části článku si popíšeme základní vlastnosti takzvaných traitů a způsob jejich použití pro „vynucení“ implementace funkcí a metod pro zvolenou strukturu (použití traitů však bude prozatím pouze omezené, protože nedokážeme pracovat s generickými datovými typy).
Všechny dále ukázané demonstrační příklady budou používat strukturu, s níž jsme se již seznámili minule. Jedná se o prozatím velmi jednoduchou a jednoúčelovou strukturu představující komplexní čísla:
struct Complex { real: f32, imag: f32, }
Ze sémantického hlediska se jedná o plnohodnotnou datovou strukturu, takže je možné deklarovat funkce, které budou akceptovat parametry tohoto datového typu, popř. reference na týž typ:
fn print_complex(c:&Complex) { println!("complex number: {}+{}i", c.real, c.imag); } fn abs(c:&Complex) -> f32 { (c.real * c.real + c.imag * c.imag).sqrt() }
Taktéž je možné vytvářet a vracet hodnoty nového datového typu:
fn new_complex(real: f32, imag: f32) -> Complex { Complex{real:real, imag:imag} }
Způsob použití výše deklarovaných funkcí:
fn main() { let c1 = new_complex(3.0, 4.0); print_complex(&c1); println!("absolute value: {}", abs(&c1)); }
2. Implementace jedné metody pro zvolenou strukturu
Způsob zápisu volání funkcí, které jako svůj první či dokonce jediný argument akceptují strukturu představující komplexní číslo, není příliš čitelný, především pro programátory navyklé na používání objektů a tříd v jazycích typu C++, Java či Python. Ovšem i v programovacím jazyce Rust je možné vytvářet metody. Ty nejsou vázány na konkrétní třídu (tento pojem se ostatně v Rustu už nepoužívá, i když se ve starších verzích třídy na chvíli objevily), ale mohou být vázány ke struktuře. Metody jsou deklarovány uvnitř bloku impl a jejich prvním argumentem je &self, tedy reference na konkrétní strukturu, s níž metoda pracuje. Podívejme se na jednoduchý příklad. Výše uvedenou funkci abs() převedeme na metodu se stejným jménem.
Původní tvar funkce:
fn abs(c:&Complex) -> f32 { (c.real * c.real + c.imag * c.imag).sqrt() }
Metoda platná pro komplexní čísla umístěná v bloku impl:
impl Complex { fn abs(&self) -> f32 { (self.real * self.real + self.imag * self.imag).sqrt() } }
Vidíme, že uvnitř metody můžeme přistupovat ke složkám struktury přes operátor tečky, tedy nezávisle na tom, že se metodě předala reference.
Volání funkce a metody se syntakticky liší. Předpokládejme, že v proměnné c1 je uloženo komplexní číslo. Volání funkce je provedeno na prvním řádku, volání metody na řádku druhém:
println!("absolute value: {}", abs(&c1)); println!("absolute value: {}", c1.abs());
Povšimněte si, že se při volání metody před názvem proměnné nepoužívá znak &, který slouží pro získání reference.
Následuje úplný tvar příkladu, v němž je deklarována a následně použita metoda abs platná pro komplexní čísla:
struct Complex { real: f32, imag: f32, } fn print_complex(c:&Complex) { println!("complex number: {}+{}i", c.real, c.imag); } impl Complex { fn abs(&self) -> f32 { (self.real * self.real + self.imag * self.imag).sqrt() } } fn main() { let c1 = Complex{real:3.0, imag:4.0}; print_complex(&c1); println!("absolute value: {}", c1.abs()); }
3. Způsoby implementace většího množství metod pro zvolenou strukturu
V případě, že pro jednu strukturu, tedy pro nový datový typ, potřebujeme deklarovat větší množství metod (což je zajisté v praxi velmi častý požadavek), lze postupovat dvěma způsoby. Každou metodu je možné uložit do vlastního bloku impl, takže výsledek může vypadat následovně:
struct Complex { real: f32, imag: f32, } impl Complex { fn abs(&self) -> f32 { (self.real * self.real + self.imag * self.imag).sqrt() } } impl Complex { fn print(&self) { println!("complex number: {}+{}i", self.real, self.imag); } } fn main() { let c1 = Complex{real:3.0, imag:4.0}; c1.print(); println!("absolute value: {}", c1.abs()); }
Většinou je však čitelnější všechny metody uvést v jediném bloku impl, což vede k následujícímu zápisu programu:
struct Complex { real: f32, imag: f32, } impl Complex { fn abs(&self) -> f32 { (self.real * self.real + self.imag * self.imag).sqrt() } fn print(&self) { println!("complex number: {}+{}i", self.real, self.imag); } } fn main() { let c1 = Complex{real:3.0, imag:4.0}; c1.print(); println!("absolute value: {}", c1.abs()); }
4. Metoda vracející novou strukturu
Velmi často se setkáme s požadavkem, aby metoda vrátila novou strukturu. Příkladem může být metoda nazvaná sqr, která vrátí nové komplexní číslo, konkrétně druhou mocninu svého argumentu. Připomeňme si, že vytvoření nového komplexního čísla vypadá takto:
Complex{real: výraz_typu_f32, imag: výraz_typu_f32}
Metoda sqr tedy vrací hodnotu typu Complex (jméno za šipkou) a uvnitř jejího těla je jediný výraz, jehož hodnota je po vyčíslení vrácena:
fn sqr(&self) -> Complex { Complex{real: self.real * self.real - self.imag * self.imag, imag: 2.0*self.real * self.imag} }
Alternativě (a zbytečně zdlouhavě) lze samozřejmě použít příkaz return:
fn sqr(&self) -> Complex { return Complex{real: self.real * self.real - self.imag * self.imag, imag: 2.0*self.real * self.imag}; }
Použití metody Complex.sqr() je jednoduché:
struct Complex { real: f32, imag: f32, } impl Complex { fn abs(&self) -> f32 { (self.real * self.real + self.imag * self.imag).sqrt() } fn sqr(&self) -> Complex { Complex{real: self.real * self.real - self.imag * self.imag, imag: 2.0*self.real * self.imag} } fn print(&self) { println!("complex number: {}+{}i", self.real, self.imag); } } fn main() { let c1 = Complex{real:1.0, imag:0.0}; let c2 = Complex{real:0.0, imag:2.0}; let c3 = Complex{real:2.0, imag:2.0}; let c4 = c1.sqr(); let c5 = c2.sqr(); let c6 = c3.sqr(); c1.print(); c2.print(); c3.print(); c4.print(); c5.print(); c6.print(); }
Volání metod je možné v případě potřeby „zřetězit“ bez explicitního uložení mezivýsledků do proměnných (ostatně právě zde je patrné, že volání metod může být přehlednější, než vnořené volání funkcí):
fn main() { let c1 = Complex{real:1.0, imag:0.001}; let c2 = c1.sqr().sqr().sqr().sqr(); c1.print(); c2.print(); }
Otázka: jak a kdy jsou mezivýsledky odstraněny z operační paměti?
5. Metody s více parametry
Pro úplnost si ukažme, jak by se implementovala metoda, která kromě parametru &self akceptuje i další parametry. Příkladem může být metoda nazvaná add, která jako svůj výsledek vrátí součet dvou komplexních čísel. Není to nic těžkého. Povšimněte si, že u druhého parametru explicitně zapisujeme jeho typ a samozřejmě jsme nuceni specifikovat i typ výsledku:
fn add(&self, c:&Complex) -> Complex { Complex{real: self.real + c.real, imag: self.imag + c.imag} }
Poznámka: povšimněte si, jak nás programovací jazyk Rust nenápadně vede k používání neměnných (immutable) struktur a funkcionálního stylu programování. Metoda add je vlastně zapsána funkcionálním stylem: ani jeden ze vstupních parametrů není měněn a toto chování je zaručeno již hlavičkou metody (vůbec nemusíme zkoumat její tělo), i implicitní return na konci těla metody je známé z mnoha FP jazyků.
Následuje úplný tvar příkladu, v němž je deklarována a následně použita metoda add platná pro komplexní čísla:
struct Complex { real: f32, imag: f32, } impl Complex { fn abs(&self) -> f32 { (self.real * self.real + self.imag * self.imag).sqrt() } fn sqr(&self) -> Complex { Complex{real: self.real * self.real - self.imag * self.imag, imag: 2.0*self.real * self.imag} } fn add(&self, c:&Complex) -> Complex { Complex{real: self.real + c.real, imag: self.imag + c.imag} } fn mul(&self, c:&Complex) -> Complex { Complex{real: self.real * c.real - self.imag * c.imag, imag: self.real * c.imag + self.imag * c.real} } fn print(&self) { println!("complex number: {}+{}i", self.real, self.imag); } } fn main() { let c1 = Complex{real:1.0, imag:2.0}; let c2 = Complex{real:3.0, imag:4.0}; let c3 = c1.add(&c2); let c4 = c1.mul(&c1); c1.print(); c2.print(); c3.print(); c4.print(); }
6. Funkce deklarovaná v kontextu vybrané struktury
Do bloku impl se nemusí vkládat pouze deklarace metod. Mohou se zde nacházet i běžné funkce. Příkladem mohou být funkce (vlastně primitivní konstruktory) nazvané zero a one. Tyto funkce neakceptují žádné parametry, tedy ani &self, čímž se odlišují od metod:
impl Complex { fn zero() -> Complex { Complex{real:0.0, imag:0.0} } fn one() -> Complex { Complex{real:1.0, imag:0.0} } }
Poznámka: samozřejmě je možné, aby takto deklarované funkce akceptovaly nějaký parametr. Příklad bude ukázán v následující kapitole.
Volání takto deklarovaných funkcí je provedeno následovně, s použitím rozlišovacího operátoru „čtyřtečka“:
let c1 = Complex::zero(); let c2 = Complex::one();
Opět se podívejme na rozsáhlejší demonstrační příklad, do něhož postupně vkládáme nové a nové funkce a metody:
struct Complex { real: f32, imag: f32, } impl Complex { fn zero() -> Complex { Complex{real:0.0, imag:0.0} } fn one() -> Complex { Complex{real:1.0, imag:0.0} } fn abs(&self) -> f32 { (self.real * self.real + self.imag * self.imag).sqrt() } fn sqr(&self) -> Complex { Complex{real: self.real * self.real - self.imag * self.imag, imag: 2.0*self.real * self.imag} } fn add(&self, c:&Complex) -> Complex { Complex{real: self.real + c.real, imag: self.imag + c.imag} } fn mul(&self, c:&Complex) -> Complex { Complex{real: self.real * c.real - self.imag * c.imag, imag: self.real * c.imag + self.imag * c.real} } fn print(&self) { println!("complex number: {}+{}i", self.real, self.imag); } } fn main() { let c1 = Complex::zero(); let c2 = Complex::one(); let c3 = c1.add(&c2); let c4 = c2.mul(&c2); c1.print(); c2.print(); c3.print(); c4.print(); }
7. Konstruktory
Konstrukce nového komplexního čísla zápisem Complex{real:real, imag:imag} je sice jednoznačná, ale přece jen možná poněkud neobvyklá. Proto se v některých zdrojových kódech setkáme s deklarací konstruktoru, což je vlastně funkce umístěná do bloku impl, která akceptuje obecně libovolné parametry a vrací strukturu zvoleného typu. Taková funkce je většinou pojmenována new a v našem příkladu s komplexními čísly může její deklarace vypadat například takto:
impl Complex { fn new(real: f32, imag: f32) -> Complex { Complex{real:real, imag:imag} } }
Volání konstruktoru pro komplexní čísla se vlastně nijak neliší od volání již dříve deklarovaných funkcí zero a one:
let c1 = Complex::new(1.0, 2.0); let c2 = Complex::new(3.0, 4.0);
Poznámka: programovací jazyk Rust nepodporuje přetěžování funkcí ani metod, takže není možné deklarovat dvě stejně pojmenované funkce new s rozdílným typem a/nebo počtem parametrů. Toto chování je sice možné obejít implementací několika traitů, nebývá to však obvyklé. Proto se někdy setkáme s větším množstvím konstruktorů pojmenovaných například new_t1, new_t2 atd. Důvodem pro nezařazení přetěžování metod jsou problémy související s typovou inferencí (příklady si pravděpodobně ukážeme příště).
Podívejme se nyní, jak byl konstruktor zařazen do našeho demonstračního příkladu:
struct Complex { real: f32, imag: f32, } impl Complex { fn new(real: f32, imag: f32) -> Complex { Complex{real:real, imag:imag} } fn zero() -> Complex { Complex{real:0.0, imag:0.0} } fn one() -> Complex { Complex{real:1.0, imag:0.0} } fn abs(&self) -> f32 { (self.real * self.real + self.imag * self.imag).sqrt() } fn sqr(&self) -> Complex { Complex{real: self.real * self.real - self.imag * self.imag, imag: 2.0*self.real * self.imag} } fn add(&self, c:&Complex) -> Complex { Complex{real: self.real + c.real, imag: self.imag + c.imag} } fn mul(&self, c:&Complex) -> Complex { Complex{real: self.real * c.real - self.imag * c.imag, imag: self.real * c.imag + self.imag * c.real} } fn print(&self) { println!("complex number: {}+{}i", self.real, self.imag); } } fn main() { let c1 = Complex::new(1.0, 2.0); let c2 = Complex::new(3.0, 4.0); let c3 = c1.add(&c2); let c4 = c1.mul(&c1); c1.print(); c2.print(); c3.print(); c4.print(); }
8. Traity
S termínem trait jsme se již setkali v předchozím článku, v němž jsme si mj. uvedli, že trait můžeme pokládat za rozšířené rozhraní, které kromě hlaviček funkcí a metod obsahuje (resp. může obsahovat) i jejich těla, ale už nikoli stavové informace. Je to vlastně podobné rozhraním (interface) v Javě 8, které ovšem nemají všechny vlastnosti traitů. To, že má nějaký typ či objekt určitý rys (trait) tedy není zajištěno přímým děděním, což vlastně poměrně dobře odpovídá objektovému systému programovacího jazyka Rust, který není primárně založen na třídách a dědičnosti, ale na strukturách a traitech.
Deklarace traitu s jedinou metodou (přesněji řečeno jen s hlavičkou metody) vypadá následovně. U metody musíme znát její jméno, parametry (popř. jejich typy) a návratový typ. V následujícím příkladu není návratový typ uveden:
trait Print { fn print(&self); }
Alternativně lze návratový typ uvést explicitně:
trait Print { fn print(&self) -> (); }
Trait samozřejmě může předepisovat větší množství metod či funkcí:
trait ComplexConstructors { fn new(real: f32, imag: f32) -> Complex; fn zero() -> Complex; fn one() -> Complex; }
Poznámka: povšimněte si, že zde neexistuje žádné podstatné rozlišení mezi funkcí a metodou. Odlišné je až volání funkce či metody.
9. Implementace traitu pro strukturu představující komplexní číslo
Trait, podobně jako rozhraní, můžeme implementovat. Následující blok impl obsahuje implementaci traitu Print, který byl uveden v předchozí kapitole:
impl Print for Complex { fn print(&self) { println!("complex number: {}+{}i", self.real, self.imag); } }
Poznámka: povšimněte si, že klíčové slovo for má v Rustu více významů.
Poznámka 2: všechny datové typy jsou si v Rustu rovnocenné, což znamená, že můžete implementovat trait například i pro typ i32 či f32. Tento styl není doporučován, ovšem ukazuje, že kombinace traitů a datového systému může být mocnější, než „klasické“ OOP postavené na hierarchii tříd.
V následujícím příkladu je definován trait Print, následně je implementován a po této implementaci následuje implementace dalších metod (už v jiném bloku):
trait Print { fn print(&self); } struct Complex { real: f32, imag: f32, } impl Print for Complex { fn print(&self) { println!("complex number: {}+{}i", self.real, self.imag); } } impl Complex { fn new(real: f32, imag: f32) -> Complex { Complex{real:real, imag:imag} } fn zero() -> Complex { Complex{real:0.0, imag:0.0} } fn one() -> Complex { Complex{real:1.0, imag:0.0} } fn abs(&self) -> f32 { (self.real * self.real + self.imag * self.imag).sqrt() } fn sqr(&self) -> Complex { Complex{real: self.real * self.real - self.imag * self.imag, imag: 2.0*self.real * self.imag} } fn add(&self, c:&Complex) -> Complex { Complex{real: self.real + c.real, imag: self.imag + c.imag} } fn mul(&self, c:&Complex) -> Complex { Complex{real: self.real * c.real - self.imag * c.imag, imag: self.real * c.imag + self.imag * c.real} } } fn main() { let c1 = Complex::new(1.0, 2.0); let c2 = Complex::new(3.0, 4.0); let c3 = c1.add(&c2); let c4 = c1.mul(&c1); c1.print(); c2.print(); c3.print(); c4.print(); }
Podívejme se, co se stane, když „zapomeneme“ implementovat metodu či funkci předepsanou traitem:
trait Print { fn print(&self); } struct Complex { real: f32, imag: f32, } impl Print for Complex { } impl Complex { fn new(real: f32, imag: f32) -> Complex { Complex{real:real, imag:imag} } fn zero() -> Complex { Complex{real:0.0, imag:0.0} } fn one() -> Complex { Complex{real:1.0, imag:0.0} } fn abs(&self) -> f32 { (self.real * self.real + self.imag * self.imag).sqrt() } fn sqr(&self) -> Complex { Complex{real: self.real * self.real - self.imag * self.imag, imag: 2.0*self.real * self.imag} } fn add(&self, c:&Complex) -> Complex { Complex{real: self.real + c.real, imag: self.imag + c.imag} } fn mul(&self, c:&Complex) -> Complex { Complex{real: self.real * c.real - self.imag * c.imag, imag: self.real * c.imag + self.imag * c.real} } } fn main() { let c1 = Complex::new(1.0, 2.0); let c2 = Complex::new(3.0, 4.0); let c3 = c1.add(&c2); let c4 = c1.mul(&c1); c1.print(); c2.print(); c3.print(); c4.print(); }
Překladač implementaci poměrně striktně vyžaduje:
error[E0046]: not all trait items implemented, missing: `print` --> test.rs:10:1 | 10 | impl Print for Complex { | ^ missing `print` in implementation error: aborting due to previous error
10. Implementace většího množství traitů
Pro zvolenou datovou strukturu je možné implementovat libovolné množství traitů. Prozatím neznáme použití generických datových typů, takže následující příklad bude trošku umělý. Deklarujeme dva traity:
trait Print { fn print(&self); }
a
trait ComplexConstructors { fn new(real: f32, imag: f32) -> Complex; fn zero() -> Complex; fn one() -> Complex; }
Tyto traity lze velmi snadno implementovat pro typ Complex:
trait Print { fn print(&self); } struct Complex { real: f32, imag: f32, } trait ComplexConstructors { fn new(real: f32, imag: f32) -> Complex; fn zero() -> Complex; fn one() -> Complex; } impl Print for Complex { fn print(&self) { println!("complex number: {}+{}i", self.real, self.imag); } } impl ComplexConstructors for Complex { fn new(real: f32, imag: f32) -> Complex { Complex{real:real, imag:imag} } fn zero() -> Complex { Complex{real:0.0, imag:0.0} } fn one() -> Complex { Complex{real:1.0, imag:0.0} } } impl Complex { fn abs(&self) -> f32 { (self.real * self.real + self.imag * self.imag).sqrt() } fn sqr(&self) -> Complex { Complex{real: self.real * self.real - self.imag * self.imag, imag: 2.0*self.real * self.imag} } fn add(&self, c:&Complex) -> Complex { Complex{real: self.real + c.real, imag: self.imag + c.imag} } fn mul(&self, c:&Complex) -> Complex { Complex{real: self.real * c.real - self.imag * c.imag, imag: self.real * c.imag + self.imag * c.real} } } fn main() { let c1 = Complex::new(1.0, 2.0); let c2 = Complex::new(3.0, 4.0); let c3 = c1.add(&c2); let c4 = c1.mul(&c1); c1.print(); c2.print(); c3.print(); c4.print(); }
Velký význam traitů v reálných aplikacích (celá standardní knihovna je na traitech postavena) doceníme až při použití generických datových typů, což bude poměrně obsáhlé téma, kterému se budeme věnovat příště.
11. Repositář s demonstračními příklady
Všechny dnes ukázané demonstrační příklady, resp. přesněji řečeno jejich bezchybné varianty, byly 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ý (dnes již objemný) repositář:
Příklad | Odkaz |
---|---|
69_methods0.rs | https://github.com/tisnik/presentations/blob/master/rust/69_methods0.rs |
70_one_method.rs | https://github.com/tisnik/presentations/blob/master/rust/70_one_method.rs |
71_two_methods.rs | https://github.com/tisnik/presentations/blob/master/rust/71_two_methods.rs |
72_two_methods.rs | https://github.com/tisnik/presentations/blob/master/rust/72_two_methods.rs |
73_methods4.rs | https://github.com/tisnik/presentations/blob/master/rust/73_methods4.rs |
74_methods5.rs | https://github.com/tisnik/presentations/blob/master/rust/74_methods5.rs |
75_struct_and_functions.rs | https://github.com/tisnik/presentations/blob/master/rust/75_struct_and_functions.rs |
76_constructor.rs | https://github.com/tisnik/presentations/blob/master/rust/76_constructor.rs |
77_trait.rs | https://github.com/tisnik/presentations/blob/master/rust/77_trait.rs |
78_traits.rs | https://github.com/tisnik/presentations/blob/master/rust/78_traits.rs |
12. Odkazy na Internetu
- 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