Hlavní navigace

Programovací jazyk Rust: metody a traity

8. 12. 2016
Doba čtení: 19 minut

Sdílet

 Autor: Rust project
V páté části seriálu o programovacím jazyce Rust se nejprve budeme zabývat způsobem deklarace funkcí a metod pro zvolenou datovou strukturu a posléze pak použitím takzvaných traitů (rysů).

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

5. Metody s více parametry

6. Funkce deklarovaná v kontextu vybrané struktury

7. Konstruktory

8. Traity

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

12. Odkazy na Internetu

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:

root_podpora

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/pre­sentations. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý (dnes již objemný) repositář:

12. Odkazy na Internetu

  1. Struct std::boxed::Box
    https://doc.rust-lang.org/std/boxed/struct.Box.html
  2. Explore the ownership system in Rust
    https://nercury.github.io/rus­t/guide/2015/01/19/ownership­.html
  3. Rust's ownership and move semantic
    http://www.slideshare.net/sa­neyuki/rusts-ownership-and-move-semantics
  4. Trait std::marker::Copy
    https://doc.rust-lang.org/stable/std/marker/tra­it.Copy.html
  5. Trait std::clone::Clone
    https://doc.rust-lang.org/stable/std/clone/tra­it.Clone.html
  6. The Stack and the Heap
    https://doc.rust-lang.org/book/the-stack-and-the-heap.html
  7. Rust Compare: Pointers & References
    http://www.rust-compare.com/site/pointers.html
  8. Rust Compare: Parameters
    http://www.rust-compare.com/site/params.html
  9. Why does this compile? Automatic dereferencing?
    https://users.rust-lang.org/t/why-does-this-compile-automatic-dereferencing/2183
  10. Understanding Pointers, Ownership, and Lifetimes in Rust
    http://koerbitz.me/posts/Understanding-Pointers-Ownership-and-Lifetimes-in-Rust.html
  11. Rust lang series episode #25 — pointers (#rust-series)
    https://steemit.com/rust-series/@jimmco/rust-lang-series-episode-25-pointers-rust-series
  12. Rust – home page
    https://www.rust-lang.org/en-US/
  13. Rust – Frequently Asked Questions
    https://www.rust-lang.org/en-US/faq.html
  14. Destructuring and Pattern Matching
    https://pzol.github.io/get­ting_rusty/posts/20140417_des­tructuring_in_rust/
  15. The Rust Programming Language
    https://doc.rust-lang.org/book/
  16. Rust (programming language)
    https://en.wikipedia.org/wi­ki/Rust_%28programming_lan­guage%29
  17. Go – home page
    https://golang.org/
  18. Stack Overflow – Most Loved, Dreaded, and Wanted language
    https://stackoverflow.com/re­search/developer-survey-2016#technology-most-loved-dreaded-and-wanted
  19. 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/
  20. Rust vs Go: My experience
    https://www.reddit.com/r/go­lang/comments/21m6jq/rust_vs_go_my_ex­perience/
  21. Friends of Rust (Organizations running Rust in production)
    https://www.rust-lang.org/en-US/friends.html
  22. Rust programs versus C++ g++
    https://benchmarksgame.ali­oth.debian.org/u64q/compa­re.php?lang=rust&lang2=gpp
  23. Další benchmarky (nejedná se o reálné příklady „ze života“)
    https://github.com/kostya/benchmarks
  24. Go na Redditu
    https://www.reddit.com/r/golang/
  25. Rust vs. Go
    http://vschart.com/compare/rust/vs/go-language
  26. Abstraction without overhead: traits in Rust
    https://blog.rust-lang.org/2015/05/11/traits.html
  27. Method Syntax
    https://doc.rust-lang.org/book/method-syntax.html
  28. Traits in Rust
    https://doc.rust-lang.org/book/traits.html
  29. Functional Programming in Rust – Part 1 : Function Abstraction
    http://blog.madhukaraphatak­.com/functional-programming-in-rust-part-1/
  30. 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
  31. Chytré ukazatele (moderní verze jazyka C++) [MSDN]
    https://msdn.microsoft.com/cs-cz/library/hh279674.aspx
  32. UTF-8 Everywhere
    http://utf8everywhere.org/
  33. Rust by Example
    http://rustbyexample.com/
  34. Rust oficiálně ve Fedoře
    https://mojefedora.cz/rust-oficialne-ve-fedore/
  35. Resource acquisition is initialization
    https://en.wikipedia.org/wi­ki/Resource_acquisition_is_i­nitialization
  36. TIOBE index (October 2016)
    http://www.tiobe.com/tiobe-index/
  37. 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
  38. String Types in Rust
    http://www.suspectsemantic­s.com/blog/2016/03/27/str­ing-types-in-rust/
  39. Trait (computer programming)
    https://en.wikipedia.org/wi­ki/Trait_%28computer_program­ming%29
  40. Type inference
    https://en.wikipedia.org/wi­ki/Type_inference

Byl pro vás článek přínosný?