Hlavní navigace

Datové kolekce v programovacím jazyku Rust: množiny

Pavel Tišnovský

Třetí skupinou datových kolekcí, které lze nalézt ve standardní knihovně jazyka Rust, jsou množiny (set). Podobně jako tomu bylo u map, jsou i množiny implementované dvěma způsoby – s použitím hešovacích tabulek a B-stromů.

Obsah

1. Datové kolekce v programovacím jazyku Rust: množiny

2. Základní operace, které lze provádět s množinami

3. Vytvoření množiny implementované hešovací tabulkou

4. Vytvoření množiny implementované B-stromem

5. Operace insert() a remove()

6. Množinové operace sjednocení, průniku, rozdílu a symetrické diference

7. Implementace pomocí hešovací tabulky

8. Implementace pomocí B-stromu

9. Vytvoření množiny z pole

10. Vytvoření množiny z vektoru

11. Funkce pro vytvoření množiny z vektoru

12. Použití generické formy funkce vec2set

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

14. Odkazy na Internetu

1. Datové kolekce v programovacím jazyku Rust: množiny

Třetí důležitou datovou strukturou patřící mezi standardní kolekce, se kterou se dříve či později musí seznámit prakticky jakýkoli vývojář používající programovací jazyk Rust, jsou množiny (sets). Ty jsou charakteristické tím, že každý prvek obsahují maximálně jednou (na rozdíl od seznamů, vektorů či hodnot uložených do map). Podobně jako mapy, i množiny existují ve dvou podobách: s nesetříděnými prvky (založeno na hešovacích tabulkách) a se setříděnými prvky (založeno na B-stromech). Pro vytvoření prvního typu množiny je nutno použít typ std::collections::HashSet. Pro vytvoření druhého typu množiny se používá datový typ std::collections::BTreeSet. V obou případech je samozřejmě nutné na začátku modulu použít příkaz use, tedy například:

use std::collections::HashSet;

či:

use std::collections::BTreeSet;

2. Základní operace, které lze provádět s množinami

Nejdůležitějšími množinovými operacemi je sjednocení, průnik, rozdíl (viz též navazující kapitoly) a test, zda je jedna množina podmnožinou (subset) či nadmnožinou jiné množiny. V programovacím jazyku Rust je ovšem množiny možné využít podobně jako další typy sekvencí, tj. získat iterátor atd. Proto se také v případě potřeby práce se setříděnou sekvencí většinou používají právě množiny a nikoli ručně tříděné vektory či pole.

Základní operace s prvky množin:

Operace Metoda
Vložení prvku insert()
Odstranění prvku remove()
Přečtení prvku get()
Kombinace odstranění a vložení replace()

Základní operace s celými množinami:

Operace Funkce či metoda Operátor
Vytvoření množiny HashSet::new(), BTreeSet::new()  
Získání iterátoru iter() &množina
Sjednocení množin union() |
Průnik množin intesection() &
Rozdíl množin difference()
Symetrická diference symmetric_difference() ^

Povšimněte si, že pro základní operace s celými množinami byly přetíženy i operátory &, |, – a ^. Podrobnosti si řekneme později.

3. Vytvoření množiny implementované hešovací tabulkou

V prvním demonstračním příkladu si ukážeme vytvoření množiny, která je interně implementována formou hešovací tabulky. Do množiny je vloženo sedm prvků, ovšem dva vkládané prvky mají stejnou hodnotu. Při vkládání prvků se pro otestování unikátnosti prvků v množině používá trait Eq, což mimochodem znamená, že tento trait musí být implementován i datovým typem prvků ukládaných do množiny. Vzhledem k tomu, že trait Eq je pro typ &str korektně implementován, bude ve skutečnosti do množiny vloženo jen šest prvků:

use std::collections::HashSet;
 
fn print_hashset(set: &HashSet<&str>) {
    for item in set {
        println!("{}", item);
    }
}
 
fn main() {
    let mut set = HashSet::new();
 
    set.insert("podporucik");
    set.insert("inspektor");
    set.insert("praktikant");
    set.insert("tovarnik");
    set.insert("tovarnik");
    set.insert("stevard");
    set.insert("podkoni");
 
    print_hashset(&set);
}

Povšimněte si že:

  1. Typ prvků množiny je odvozen překladačem automaticky.
  2. Proměnná set musí být měnitelná.
  3. Při výpisu všech prvků se iterátor získává unárním operátorem &
  4. Pokud budete chtít specifikovat typ množiny, stačí za jméno proměnné zapsat :HashSet<&str>

Po překladu a spuštění se na standardním výstupu objeví je šestice řádků:

stevard
inspektor
podkoni
praktikant
podporucik
tovarnik

4. Vytvoření množiny implementované B-stromem

Druhý příklad se prakticky neliší od příkladu prvního, pouze se použije odlišná implementace množiny. Ve chvíli, kdy je množina interně implementována B-stromem, budou prvky automaticky při vkládání do množiny zatříděny takovým způsobem, že standardní iterátor vrátí prvky setříděné. Při zatřiďování prvků se používá trait Ord, což opět znamená, že tento trait musí být implementován datovým typem prvků množiny (to je pochopitelně kontrolováno překladačem):

use std::collections::BTreeSet;
 
fn print_hashset(set: &BTreeSet<&str>) {
    for item in set {
        println!("{}", item);
    }
}
 
fn main() {
    let mut set = BTreeSet::new();
 
    set.insert("podporucik");
    set.insert("inspektor");
    set.insert("praktikant");
    set.insert("tovarnik");
    set.insert("tovarnik");
    set.insert("stevard");
    set.insert("podkoni");
 
    print_hashset(&set);
}

Po překladu a spuštění se na standardním výstupu objeví jen šestice řádků:

inspektor
podkoni
podporucik
praktikant
stevard
tovarnik

5. Operace insert() a remove()

Opakem operace insert, která vkládá nové prvky do množiny, je samozřejmě operace remove. Současně tato funkce vrací pravdivostní hodnotu true, pokud odstraňovaný prvek skutečně v množině existoval. Pokud neexistoval, vrátí se hodnota false, ale z pohledu operací prováděných nad množinami se nejedná o chybu:

use std::collections::HashSet;
 
fn print_hashset(set: &HashSet<&str>) {
    for item in set {
        println!("{}", item);
    }
}
 
fn main() {
    let mut set = HashSet::new();
 
    set.insert("podporucik");
    set.insert("inspektor");
    set.insert("praktikant");
    set.insert("tovarnik");
    set.insert("tovarnik");
    set.insert("stevard");
    set.insert("podkoni");
 
    print_hashset(&set);
 
    println!("-------------------------------");
 
    set.remove("tovarnik");
    set.remove("neco jineho");
 
    print_hashset(&set);
}

Příklad výstupu. Před oddělovačem je zobrazen původní obsah množiny, pod oddělovačem pak nový obsah po odstranění jednoho jejího prvku (druhé volání remove pouze vrátilo false):

stevard
tovarnik
praktikant
podkoni
inspektor
podporucik
-------------------------------
stevard
praktikant
podkoni
inspektor
podporucik

6. Množinové operace sjednocení, průniku, rozdílu a symetrické diference

Již ve druhé kapitole jsme si řekli, že množiny ze standardní knihovny programovacího jazyka Rust podporují čtyři základní množinové operace s výjimkou doplňku (ten není podporován, protože by v naprosté většině případů musel vygenerovat nekonečnou množinu). Podle očekávání jsou všechny operace reprezentovány metodami, jejichž parametrem je reference na druhou množinu a výsledkem iterátor pro prvky množiny nové. Kromě toho je ovšem možné použít i přetížené operátory, jejichž operandy jsou vždy reference na obě množiny. Použití přetížených operátorů je podle mého názoru v tomto případě mnohem čitelnější:

Operace Funkce či metoda Operátor
Sjednocení množin union() |
Průnik množin intesection() &
Rozdíl množin difference()
Symetrická diference symmetric_difference() ^

7. Implementace pomocí hešovací tabulky

V dalším příkladu jsou všechny čtyři podporované množinové operace volány formou metod:

use std::collections::HashSet;
 
fn print_hashset(set: &HashSet<&str>) {
    for item in set {
        println!("{}", item);
    }
}
 
fn main() {
    let mut set1 = HashSet::new();
    let mut set2 = HashSet::new();
 
    set1.insert("podporucik");
    set1.insert("inspektor");
    set1.insert("praktikant");
    set1.insert("tovarnik");
 
    set2.insert("tovarnik");
    set2.insert("stevard");
    set2.insert("podkoni");
    set2.insert("inspektor");
 
    println!("Set1");
    print_hashset(&set1);
 
    println!("\nSet2");
    print_hashset(&set2);
 
    println!("\nUnion");
    for item in set1.union(&set2) {
        println!("{}", item);
    }
 
    println!("\nIntersetion");
    for item in set1.intersection(&set2) {
        println!("{}", item);
    }
 
    println!("\nDifference set1-set2");
    for item in set1.difference(&set2) {
        println!("{}", item);
    }
 
    println!("\nDifference set2-set1");
    for item in set2.difference(&set1) {
        println!("{}", item);
    }
 
    println!("\nSymmetric difference");
    for item in set1.symmetric_difference(&set2) {
        println!("{}", item);
    }
}

Příklad výstupu:

Set1
inspektor
tovarnik
podporucik
praktikant
 
Set2
inspektor
podkoni
tovarnik
stevard
 
Union
inspektor
tovarnik
podporucik
praktikant
podkoni
stevard
 
Intersetion
inspektor
tovarnik
 
Difference set1-set2
podporucik
praktikant
 
Difference set2-set1
podkoni
stevard
 
Symmetric difference
podporucik
praktikant
podkoni
stevard

Přepišme si nyní příklad tak, aby se namísto metod použily přetížené operátory:

use std::collections::HashSet;
 
fn print_hashset(set: &HashSet<&str>) {
    for item in set {
        println!("{}", item);
    }
}
 
fn main() {
    let set1 = ["podporucik", "inspektor", "praktikant", "tovarnik"].iter().cloned().collect();
    let set2 = ["tovarnik", "stevard", "podkoni", "inspektor"].iter().cloned().collect();
 
    println!("Set1");
    print_hashset(&set1);
 
    println!("\nSet2");
    print_hashset(&set2);
 
    println!("\nUnion");
    for item in &set1 | &set2 {
        println!("{}", item);
    }
 
    println!("\nIntersetion");
    for item in &set1 & &set2 {
        println!("{}", item);
    }
 
    println!("\nDifference set1-set2");
    for item in &set1 - &set2 {
        println!("{}", item);
    }
 
    println!("\nDifference set2-set1");
    for item in &set2 - &set1 {
        println!("{}", item);
    }
 
    println!("\nSymmetric difference");
    for item in &set1 ^ &set2 {
        println!("{}", item);
    }
}

Příklad výstupu:

Set1
inspektor
praktikant
tovarnik
podporucik
 
Set2
stevard
inspektor
podkoni
tovarnik
 
Union
inspektor
stevard
podkoni
praktikant
tovarnik
podporucik
 
Intersetion
inspektor
tovarnik
 
Difference set1-set2
praktikant
podporucik
 
Difference set2-set1
stevard
podkoni
 
Symmetric difference
stevard
podkoni
praktikant
podporucik

8. Implementace pomocí B-stromu

Pokud kód z předchozího příkladu použijeme, ovšem pro množiny založené na B-stromech, měly by iterátory vrácené metodami union(), intersection(), difference() a symmetric_difference() vracet prvky v setříděném pořadí:

use std::collections::BTreeSet;
 
fn print_btree_set(set: &BTreeSet<&str>) {
    for item in set {
        println!("{}", item);
    }
}
 
fn main() {
    let mut set1 = BTreeSet::new();
    let mut set2 = BTreeSet::new();
 
    set1.insert("podporucik");
    set1.insert("inspektor");
    set1.insert("praktikant");
    set1.insert("tovarnik");
 
    set2.insert("tovarnik");
    set2.insert("stevard");
    set2.insert("podkoni");
    set2.insert("inspektor");
 
    println!("Set1");
    print_btree_set(&set1);
 
    println!("\nSet2");
    print_btree_set(&set2);
 
    println!("\nUnion");
    for item in set1.union(&set2) {
        println!("{}", item);
    }
 
    println!("\nIntersetion");
    for item in set1.intersection(&set2) {
        println!("{}", item);
    }
 
    println!("\nDifference set1-set2");
    for item in set1.difference(&set2) {
        println!("{}", item);
    }
 
    println!("\nDifference set2-set1");
    for item in set2.difference(&set1) {
        println!("{}", item);
    }
 
    println!("\nSymmetric difference");
    for item in set1.symmetric_difference(&set2) {
        println!("{}", item);
    }
}

Z výstupu je patrné, že skutečně došlo ke správnému zatřídění prvků:

Set1
inspektor
podporucik
praktikant
tovarnik
 
Set2
inspektor
podkoni
stevard
tovarnik
 
Union
inspektor
podkoni
podporucik
praktikant
stevard
tovarnik
 
Intersetion
inspektor
tovarnik
 
Difference set1-set2
podporucik
praktikant
 
Difference set2-set1
podkoni
stevard
 
Symmetric difference
podkoni
podporucik
praktikant
stevard

9. Vytvoření množiny z pole

Poměrně často se setkáme s potřebou vytvořit neměnitelnou množinu. Vzhledem k tomu, že pro množiny neexistuje vhodná syntaxe konstruktoru, musíme si vypomoci jiným způsobem, například využitím iterátoru vytvořeného pro všechny prvky pole. Následující kód získá iterátor pro dané pole, postupně vytvoří klony jeho prvků a následně z iterátoru vytvoří kolekci. Povšimněte si toho, že samotná proměnná držící množinu již nemusí být měnitelná:

let množina = [].iter().cloned().collect();

Vytvoření množiny z pole lze do zdrojového kódu zařadit velmi snadno:

use std::collections::HashSet;
 
fn print_hashset(set: &HashSet<&str>) {
    for item in set {
        println!("{}", item);
    }
}
 
fn main() {
    let set1 = ["podporucik", "inspektor", "praktikant", "tovarnik"].iter().cloned().collect();
    let set2 = ["tovarnik", "stevard", "podkoni", "inspektor"].iter().cloned().collect();
 
    println!("Set1");
    print_hashset(&set1);
 
    println!("\nSet2");
    print_hashset(&set2);
 
    println!("\nUnion");
    for item in set1.union(&set2) {
        println!("{}", item);
    }
 
    println!("\nIntersetion");
    for item in set1.intersection(&set2) {
        println!("{}", item);
    }
 
    println!("\nDifference set1-set2");
    for item in set1.difference(&set2) {
        println!("{}", item);
    }
 
    println!("\nDifference set2-set1");
    for item in set2.difference(&set1) {
        println!("{}", item);
    }
 
    println!("\nSymmetric difference");
    for item in set1.symmetric_difference(&set2) {
        println!("{}", item);
    }
}

Poznámka: vyzkoušejte si, co se stane, když bude pole obsahovat shodné prvky.

10. Vytvoření množiny z vektoru

Prakticky stejným způsobem se množina vytváří z vektoru, v tomto případě ale bude překladač vyžadovat přesné určení typu množiny:

use std::collections::HashSet;
 
fn print_hashset(set: &HashSet<&str>) {
    for item in set {
        println!("{}", item);
    }
}
 
fn main() {
    let set1: HashSet<&str> = vec!["podporucik", "inspektor", "praktikant", "tovarnik"].iter().cloned().collect();
    let set2: HashSet<&str> = vec!["tovarnik", "stevard", "podkoni", "inspektor"].iter().cloned().collect();
 
    println!("Set1");
    print_hashset(&set1);
 
    println!("\nSet2");
    print_hashset(&set2);
 
    println!("\nUnion");
    for item in set1.union(&set2) {
        println!("{}", item);
    }
 
    println!("\nIntersetion");
    for item in set1.intersection(&set2) {
        println!("{}", item);
    }
 
    println!("\nDifference set1-set2");
    for item in set1.difference(&set2) {
        println!("{}", item);
    }
 
    println!("\nDifference set2-set1");
    for item in set2.difference(&set1) {
        println!("{}", item);
    }
 
    println!("\nSymmetric difference");
    for item in set1.symmetric_difference(&set2) {
        println!("{}", item);
    }
}

Poznámka: opět si vyzkoušejte, co se stane, když bude vektor obsahovat shodné prvky.

11. Funkce pro vytvoření množiny z vektoru

V rámci tréningu si můžeme vyzkoušet vytvořit funkci, která převede prvky vektoru na množinu. Tato funkce bude obsahovat jediný výraz, jehož výsledek se bude vracet, takže existují dvě formy zápisu, přičemž je doporučeno použít druhý způsob (ten neobsahuje středník za výrazem):

fn vec2set(v: Vec<&str>) -> HashSet<&str> {
    return v.iter().cloned().collect();
}
fn vec2set(v: Vec<&str>) -> HashSet<&str> {
    v.iter().cloned().collect()
}

Zařazení této funkce do zdrojového kódu programu je snadné:

use std::collections::HashSet;
 
fn print_hashset(set: &HashSet<&str>) {
    for item in set {
        println!("{}", item);
    }
}
 
fn vec2set(v: Vec<&str>) -> HashSet<&str> {
    v.iter().cloned().collect()
}
 
fn main() {
    let set1 = vec2set(vec!["podporucik", "inspektor", "praktikant", "tovarnik"]);
    let set2 = vec2set(vec!["tovarnik", "stevard", "podkoni", "inspektor"]);
 
    println!("Set1");
    print_hashset(&set1);
 
    println!("\nSet2");
    print_hashset(&set2);
 
    println!("\nUnion");
    for item in set1.union(&set2) {
        println!("{}", item);
    }
 
    println!("\nIntersetion");
    for item in set1.intersection(&set2) {
        println!("{}", item);
    }
 
    println!("\nDifference set1-set2");
    for item in set1.difference(&set2) {
        println!("{}", item);
    }
 
    println!("\nDifference set2-set1");
    for item in set2.difference(&set1) {
        println!("{}", item);
    }
 
    println!("\nSymmetric difference");
    for item in set1.symmetric_difference(&set2) {
        println!("{}", item);
    }
}

12. Použití generické formy funkce vec2set

Ve skutečnosti není funkce vec2set popsaná v předchozí kapitole univerzální, protože bude pracovat pouze pro vektory obsahující řetězce. V případě, že budeme chtít vytvořit univerzální funkci, je nutné (asi podle očekávání) použít generické typy, v nichž překladači Rustu zaručíme, že se tato funkce bude volat pouze pro vektory, jejichž prvky implementují traity Copy, Eq a Hash. První z těchto traitů je nutný pro volání cloned(), další dva pro přidání prvků do množiny. Traity se v tomto případě oddělují znakem +:

fn vec2set<T: Copy + Eq + Hash>(v: Vec<T>) -> HashSet<T> {
    v.iter().cloned().collect()
}

Úplný zdrojový kód může vypadat následovně:

use std::collections::HashSet;
use std::hash::Hash;
 
fn print_hashset(set: &HashSet<&str>) {
    for item in set {
        println!("{}", item);
    }
}
 
fn vec2set<T: Copy + Eq + Hash>(v: Vec<T>) -> HashSet<T> {
    v.iter().cloned().collect()
}
 
fn main() {
    let set1 = vec2set(vec!["podporucik", "inspektor", "praktikant", "tovarnik"]);
    let set2 = vec2set(vec!["tovarnik", "stevard", "podkoni", "inspektor"]);
 
    println!("Set1");
    print_hashset(&set1);
 
    println!("\nSet2");
    print_hashset(&set2);
 
    println!("\nUnion");
    for item in set1.union(&set2) {
        println!("{}", item);
    }
 
    println!("\nIntersetion");
    for item in set1.intersection(&set2) {
        println!("{}", item);
    }
 
    println!("\nDifference set1-set2");
    for item in set1.difference(&set2) {
        println!("{}", item);
    }
 
    println!("\nDifference set2-set1");
    for item in set2.difference(&set1) {
        println!("{}", item);
    }
 
    println!("\nSymmetric difference");
    for item in set1.symmetric_difference(&set2) {
        println!("{}", item);
    }
}

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

Všechny dnes popisované demonstrační příklady byly, podobně jako ve všech předchozích částech tohoto seriálu, uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/pre­sentations. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář:

14. Odkazy na Internetu

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

Pro vytvoření množiny z vektoru je efektivnější použít iterátor drain pro přenesení vlastnictví prvků vektoru místo jejich kopírování:

let mut v = vec!["podporucik", "inspektor", "praktikant", "tovarnik"]; let set1: HashSet<&str> = v.drain(..).collect();

Pozn.: kvůli lifetime nelze zapsat na jeden řádek, ale to by v budoucnu mohly zlepšit non-lexical lifetimes.

30. 3. 2017 23:04
asdf (neregistrovaný)

Další možnost je into_iter() iterátor. Ten vezme vlastnictví celého vektoru.