Obsah
1. Práce s řetězci v programovacím jazyku Rust
2. Statický řetězec a jeho tisk
3. Předání statického řetězce do funkce
4. Úplná deklarace statického řetězce
5. Modifikace proměnné typu &str
6. Statický řetězec jako návratový typ funkce
7. Typ String: řetězec umístěný na haldě
8. Problematika vlastnictví proměnné typu String
9. Korektní řešení – dereference proměnné typu String
11. Jak spojit dva řetězce typu String
12. Převod řetězce na sekvenci bajtů a znaků
13. Získání podřetězce „krájením“
14. Repositář s demonstračními příklady
1. Práce s řetězci v programovacím jazyku Rust
Pozorný čtenář si možná všiml, že jsme se prozatím v seriálu o programovacím jazyku Rust nezabývali způsobem práce s řetězci. To sice může být poněkud překvapivé, protože se jedná o základní součást prakticky všech programovacích jazyků, ale ve skutečnosti má v Rustu význam se prací s řetězci začít zabývat až ve chvíli, kdy rozumíme dalším problematikám, především použitím referencí, použitím měnitelných a neměnitelných proměnných, vlastnictvím objektů a taktéž způsobem alokace objektů na haldě. V této chvíli jsme se již všemi zmíněnými problematikami „prokousali“, takže známe většinu informací nutných pro efektivní práci s řetězci.
V programovacím jazyku Rust jsou řetězce interně ukládány s využitím kódování UTF-8, což sice může znít překvapivě, ovšem přináší to i některé výhody. Autoři tohoto jazyka správně poukazují na to, že v současnosti prakticky všechny webové služby, XML soubory, velká část HTML stránek atd. stejně kódování UTF-8 používají, takže nemá význam neustále provádět konverzi mezi tímto kódováním a například UCS-4 (UTF-32). Navíc je při zpracování rozsáhlých XML souborů formát UTF-8 výhodnější z hlediska spotřeby operační paměti. Největší nevýhodou použití UTF-8 je nemožnost získat a vrátit n-tý znak v řetězci v konstantním čase. Pokud by se tato operace prováděla velmi často, lze samozřejmě použít vhodný objekt, který například „obaluje“ pole čtyřbajtových širokých znaků v UCS-4/UTF-32.
Mimochodem: řešení založené na formátu UTF-16, které částečně používá například Java, je vlastně polovičaté a přináší ty horší vlastnosti z obou světů – znaky jsou stále ukládány v proměnném počtu bajtů, ale spotřeba paměti je u běžných řetězců (konfigurační soubory, angličtina…) v porovnání s UTF-8 dvojnásobná.
V programovacím jazyku Rust existuje hned několik datových typů určených pro úschovu řetězců. Obecně se tyto typy rozdělují do dvou skupin podle toho, zda se jedná o takzvanou „slice“ variantu (sem spadají řetězce umístěné v kódovém segmentu) a o řetězce obalené vhodným kontejnerem a typicky umístěné na haldě. V každé skupině nalezneme čtyři typy: řetězce s kódováním UTF-8, řetězce kompatibilní s céčkem (nutno použít při volání céčkových knihoven), řetězce kompatibilní s operačním systémem (může se jednat o typ shodný s předchozím) a konečně řetězce, které mohou uchovávat cestu k souborům a adresářům (opět – nemusí se nutně jednat o zcela odlišný datový typ). V dalším textu nás budou zajímat především typy str a String:
Vlastnost | Varianta „slice“ | Varianta „Owned“ |
---|---|---|
UTF-8 string | str | String |
Kompatibilní s C | CStr | CString |
Kompatibilní s OS | OsStr | OsString |
Cesta (v OS) | Path | PathBuf |
2. Statický řetězec a jeho tisk
Popis práce s řetězci v programovacím jazyku Rust začneme zcela jednoduchým příkladem, v němž je deklarována proměnná nazvaná message, do které se uloží reference na konstantní řetězec. Obsah této proměnné je následně vypsán na standardní výstup:
fn main() { let message = "Hello world!"; println!("{}", message); }
Překlad a spuštění prvního demonstračního příkladu:
rustc 117_str.rs ./117_str Hello world!
V tomto případě se do proměnné message ve skutečnosti uloží reference na statický řetězec, který je neměnitelný a který je součástí výsledného spustitelného binárního souboru. Konkrétně se tento řetězec nachází v sekci nazvané .rodata, která má nastavená práva Exec a Read, nikoli však Write (ostatně i proto se jedná o neměnitelný řetězec). Jen malý důkaz, že tomu tak skutečně je:
rustc 117_str.rs objdump -S -j .rodata 117_str | grep Hello 468c0: 48 65 6c 6c 6f 20 77 6f 72 6c 64 21 Hello world!
Kód se tedy podobá céčkové deklaraci:
char *str = "Hello world!";
3. Předání statického řetězce do funkce
Vzhledem k tomu, že proměnná message obsahuje „pouze“ referenci na řetězec, můžeme jí předat do nějaké funkce, a to dokonce tolikrát, kolikrát potřebujeme. Jinými slovy – v tomto případě díky předávání referencí nedochází ke změně vlastníka objektu, takže překladač předání povolí. Povšimněte si, že typem parametru není str, ale skutečně &str:
fn print_str(message: &str) { println!("{}", message); } fn main() { let message = "Hello world!"; print_str(message); print_str(message); print_str(message); }
Překlad a spuštění druhého demonstračního příkladu:
rustc 118_str_pass_to_function.rs ./118_str_pass_to_function Hello world! Hello world! Hello world!
Poznámka: toto je zdaleka nejčastější způsob předávání řetězců do funkcí a setkáme se s ním v prakticky všech skutečných aplikacích naprogramovaných v Rustu. Existují i další způsoby (použití String atd.), ale ty již nejsou tak časté.
4. Úplná deklarace statického řetězce
Ve skutečnosti vypadá přesná deklarace datového typu statického řetězce (interně uloženého do sekce .rodata) následovně:
&'static str
a nikoli pouze:
&str
Můžeme se o tom snadno přesvědčit překladem následujícího příkladu:
fn print_str(message: &'static str) { println!("{}", message); } fn main() { let message : &'static str = "Hello world!"; print_str(message); print_str(message); print_str(message); }
Rozdíly jsou z hlediska programátora minimální (ve druhém případě se může jednat o řetězec alokovaný kdekoli jinde), ovšem jak uvidíme v dalších kapitolách, někdy jsme nuceni do deklarace přidat modifikátor 'static, proto se s tímto modifikátorem v některých zdrojových kódech potkáme.
Překlad a spuštění třetího demonstračního příkladu:
rustc 119_str_full_declarations.rs ./119_str_full_declarations Hello world! Hello world! Hello world!
Poznámka: řetězcový literál „Hello world!“ je sice vždy statickým řetězcem, ovšem ne všechny řetězce jsou statické, tj. existující po celou dobu běhu programu už do jeho začátku. Tyto „nestatické“ řetězce vznikají například konverzí z objektu String popsaného níže.
5. Modifikace proměnné typu &str
Pokusme se zjistit, co se stane ve chvíli, kdy se pokusíme do proměnné přiřadit jednu referenci na řetězec a po určité době referenci druhou. U proměnné prozatím neuvedeme žádné modifikátory, tj. necháme překladač, aby sám odvodil, jakého je proměnná typu:
fn print_str(message: &str) { println!("{}", message); } fn main() { let message = "Hello world!"; print_str(message); message = "Something else"; print_str(message); print_str(message); }
Překlad čtvrtého demonstračního příkladu nedopadne dobře, protože překladač ohlásí chybu ve chvíli, kdy se do stejné proměnné pokusíme přiřadit jinou referenci:
rustc 120_str_attempt_to_modify.rs error[E0384]: re-assignment of immutable variable `message` --> 120_str_attempt_to_modify.rs:8:5 | 6 | let message = "Hello world!"; | ------- first assignment to `message` 7 | print_str(message); 8 | message = "Something else"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ re-assignment of immutable variable error: aborting due to previous error
Náprava je snadná; stačí si vzpomenout, že jsme podobnou problematiku řešili již v úvodním článku:
// nekorektní fn main() { let i = 0; while i<10 { println!("pocitadlo: {}", i); i = i + 1; } } // korektní fn main() { let mut i = 0; while i<10 { println!("pocitadlo: {}", i); i = i + 1; } }
Pokusme se tedy použít modifikátor mut:
fn print_str(message: &str) { println!("{}", message); } fn main() { let mut message = "Hello world!"; print_str(message); message = "Something else"; print_str(message); print_str(message); }
Překlad i spuštění pátého demonstračního příkladu již proběhne v pořádku:
rustc 121_str_mutable.rs ./121_str_mutable Hello world! Something else Something else
6. Statický řetězec jako návratový typ funkce
Práce s řetězci pravděpodobně až do této chvíle není nijak překvapivá, pouze si stačí uvědomit, že pracujeme s referencemi na neměnitelné řetězce představované typem &str. Zajímavější problém nastane ve chvíli, kdy budeme potřebovat z nějaké funkce vrátit řetězec. Zkusme nejdříve aplikovat až doposud získané znalosti a vytvořit funkci vracející &str:
fn print_str(message: &str) { println!("{}", message); } fn return_str() -> &str { "Hello world!" } fn main() { let message = return_str(); print_str(message); }
V tomto případě se překlad nezdaří, i když z první části chybového hlášení nemusí být zcela zřejmé, proč tomu tak je. Problém spočívá v tom, že řetězec vrácený z funkce nemá zajištěnu životnost mimo oblast platnosti této funkce (obecně jsou totiž všechny hodnoty vytvářeny na zásobníku, i když v případě řetězců je to poněkud složitější):
error[E0106]: missing lifetime specifier --> 122_str_return_error.rs:5:20 | 5 | fn return_str() -> &str { | ^ expected lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from = help: consider giving it a 'static lifetime error: aborting due to previous error
Druhá část chybového hlášení je již z uživatelského hlediska mnohem přívětivější, protože nám přímo radí, co musíme udělat. Je nutné uvést nám již známý modifikátor 'static označující takovou hodnotu, která sice existuje po celou dobu běhu programu, ovšem nejedná se o globální proměnnou (ostatně stačí si vzpomenout na statické proměnné v céčku s velmi podobným významem. Druhá varianta příkladu bude vypadat takto:
fn print_str(message: &str) { println!("{}", message); } fn return_str() -> &'static str { "Hello world!" } fn main() { let message = return_str(); print_str(message); }
Nyní již překlad proběhne v pořádku.
Poznámka: jedná se o jednu z mála situací, kdy budete muset explicitně použít modifikátor 'static.
7. Typ String: řetězec umístěný na haldě
Zopakujme si, že datový typ str, s nímž se v naprosté většině případů pracuje pouze přes referenci typu &str, představuje z pohledu programátora neměnitelný (immutable) řetězec existující v původní podobě buď po celou dobu běhu programu, nebo od svého explicitního vytvoření. V praxi si však s takto se chovajícími řetězci mnohdy nevystačíme, protože budeme potřebovat vytvářet nové řetězce, spojovat je, měnit jejich obsah atd. V takovém případě je nutné použít odlišný typ objektu, který je v v programovacím jazyku Rust představován typem String. Tento typ objektu obaluje řetězec alokovaný na haldě.
Takový řetězec může měnit svůj obsah, může se zvětšovat, můžeme použít přetížený operátor + atd. Samozřejmě za tyto vlastnosti musíme zaplatit, a to konkrétně nutností alokací popř. realokací řetězců. Z tohoto důvodu je vždy nutné se rozmyslet, zda si v dané části aplikace nevystačíme s neměnitelnými řetězci. V případě potřeby je samozřejmě možné provést konverzi mezi &str a String či naopak, převod String→&str se dokonce obejde bez alokací paměti či přesunu znaků a proto je velmi rychlý.
8. Problematika vlastnictví proměnné typu String
Objekt typu String lze vytvořit několika způsoby. Můžeme například použít konverzi z konstantního řetězce s využitím metody to_string(). Výsledkem bude skutečně objekt typu String, který lze předat do proměnné, obsah této proměnné předat do volané funkce atd.:
fn print_str(message: String) { println!("{}", message); } fn main() { let message = "Hello world!".to_string(); print_str(message); }
Objekt typu String se při předávání do proměnné či do volané funkce chová naprosto stejným způsobem, jako jakýkoli jiný objekt (vzpomeňme například na naše komplexní čísla Complex). To mj. znamená, že se předáním mění i vlastnictví objektu (ownership), takže po prvním zavolání funkce print_str() již proměnná message daný řetězec nevlastní! Můžeme se o tom snadno přesvědčit pokusem o překlad následujícího demonstračního příkladu:
fn print_str(message: String) { println!("{}", message); } fn main() { let message = "Hello world!".to_string(); print_str(message); print_str(message); print_str(message); }
Překladač oznámí chybu u druhého a třetího volání funkce print_str. Navíc nám naznačuje, že objekty typu String neimplementují trait Copy, což sice může vypadat neprakticky, ale opak je pravdou, protože většinou nepotřebujeme, aby nám překladač automaticky klonoval potenciálně obrovské bloky paměti:
error[E0382]: use of moved value: `message` --> 124_String_not_working.rs:8:15 | 7 | print_str(message); | ------- value moved here 8 | print_str(message); | ^^^^^^^ value used here after move | = note: move occurs because `message` has type `std::string::String`, which does not implement the `Copy` trait error[E0382]: use of moved value: `message` --> 124_String_not_working.rs:9:15 | 7 | print_str(message); | ------- value moved here 8 | print_str(message); 9 | print_str(message); | ^^^^^^^ value used here after move | = note: move occurs because `message` has type `std::string::String`, which does not implement the `Copy` trait error: aborting due to 2 previous errors
Poznámka: nejedná se o nám neznámý rys jazyka, protože jsme se s ním již několikrát setkali, například zde:
struct Complex { real: f32, imag: f32, } fn print_complex(c:Complex) { println!("complex number: {}+{}i", c.real, c.imag); } fn main() { let c1 = Complex{real:1.0, imag:2.0}; println!("complex number: {}+{}i", c1.real, c1.imag); print_complex(c1); println!("complex number: {}+{}i", c1.real, c1.imag); }
9. Korektní řešení – dereference proměnné typu String
Výše zmíněný problém má ve skutečnosti velmi snadné řešení, resp. přesněji řečeno dokonce dvě řešení. První řešení spočívá ve vytvoření kopie řetězce, což však většinou nechceme a ani nepotřebujeme. Druhé řešení spočívá v předání reference na objekt typu String, takže se vlastnictví nezmění. Referenci umíme získat – použije se zápis &proměnná. Výsledkem je nám již známý typ &str (nejedná se přitom o žádnou magii, ale o explicitní implementaci traitu Deref. Vzhledem k tomu, že konverze String→&str je velmi rychlá (prakticky zadarmo), používá se velmi často, což je ostatně důvod platnosti výše uvedeného tvrzení, že se prakticky v každé aplikaci setkáme s funkcemi akceptujícími parametr/parametry typu &str.
Upravený příklad vypadá takto:
fn print_str(message: &str) { println!("{}", message); } fn main() { let message = "Hello world!".to_string(); print_str(&message); print_str(&message); print_str(&message); }
Překlad a spuštění:
rustc 125_String_to_str_coercion.rs ./125_String_to_str_coercion Hello world! Hello world! Hello world!
10. Spojování řetězců
Vzhledem k tomu, že objekty typu String obsahují měnitelné řetězce, nebude velkým překvapením, že existuje několik pomocných metod, například insert_str(), push_str(), trim(), trim_left() či trim_right() určených pro modifikaci řetězců. Navíc je pro objekty typu String přetížen operátor +, který dovoluje připojit další řetězec (typu str resp. &str). Podívejme se na jednoduchý příklad:
fn print_str(message: &str) { println!("{}", message); } fn main() { let mut message = "Hello world!".to_string(); print_str(&message); message.push_str("\n42"); print_str(&message); message = message + "\n***"; print_str(&message); }
Překlad a spuštění tohoto příkladu dopadne podle očekávání:
rustc 126_String_concatenation.rs ./126_String_concatenation Hello world! Hello world! 42 Hello world! 42 ***
Poznámka: každá z výše zmíněných metod končících na _str existuje i ve variantě bez této přípony. Ovšem v tomto případě se k řetězci připojuje jediný znak typu char. Příkladem mohou být metody insert() a insert_str(), přičemž první metoda slouží k přidání znaku na určenou pozici, zatímco metoda druhá slouží k přidání řetězce (typu &str).
11. Jak spojit dva řetězce typu String
Z předchozí kapitoly již víme, že pomocí operátoru + můžeme k řetězci obaleném objektem typu String přidat řetězec typu &str;. Na druhou stranu ovšem není možné + použít pro spojení dvou Stringů, o čemž se ostatně můžeme snadno přesvědčit:
fn print_str(message: &str) { println!("{}", message); } fn main() { let message1 : String = "Hello".to_string(); let message2 : String = "world".to_string(); print_str(&message1); print_str(&message2); let message = message1 + " " + message2 + "!"; print_str(&message);
Překladač ohlásí chybu při pokusu o připojení druhého Stringu:
error[E0308]: mismatched types --> 127_String_concatenation_2.rs:12:36 | 12 | let message = message1 + " " + message2 + "!"; | ^^^^^^^^ expected &str, found struct `std::string::String` | = note: expected type `&str` = note: found type `std::string::String` error: aborting due to previous error
Řešení je velmi snadné – musíme použít referenci na objekt typu String pomocí operátoru &:
fn print_str(message: &str) { println!("{}", message); } fn main() { let message1 : String = "Hello".to_string(); let message2 : String = "world".to_string(); print_str(&message1); print_str(&message2); let message = message1 + " " + &message2 + "!"; print_str(&message); }
12. Převod řetězce na sekvenci bajtů a znaků
Vzhledem k tomu, že řetězce jsou interně ukládány v kódování UTF-8, můžeme se na ně dívat dvěma pohledy. Buď se jedná o sekvenci bajtů nebo o sekvenci znaků, přičemž obecně může být znaků méně než bajtů (všechny znaky kromě základních znaků ASCII jsou reprezentovány větším množstvím bajtů). Opět si to můžeme snadno vyzkoušet, protože pro objekt typu String existují metody vracející iterátory umožňující procházet řetězcem po bajtech i po znacích:
fn print_str(message: &str) { println!("{}", message); } fn main() { let message = "Hello world!"; for byte in message.as_bytes() { println!("{}", byte); } for char in message.chars() { println!("{}", char); } print_str(message); }
Po spuštění získáme následující výstup naznačující, že počet ASCII znaků se v tomto případě rovná počtu bajtů, kterými jsou znaky reprezentovány:
72 101 108 108 111 32 119 111 114 108 100 33 H e l l o w o r l d ! Hello world!
Zkusme nyní tuzemská nabodeníčka:
fn print_str(message: &str) { println!("{}", message); } fn main() { let message = "ěščř"; for byte in message.as_bytes() { println!("{}", byte); } for char in message.chars() { println!("{}", char); } print_str(message); }
Zde je již patrné, že řetězec je uložen v osmi bajtech a přitom představuje čtyři znaky:
196 155 197 161 196 141 197 153 ě š č ř ěščř
13. Získání podřetězce „krájením“
Vzhledem k výše uvedenému rozdílu při chápání řetězců jako sekvence bajtů či znaků jazyk Rust nepodporuje přímé indexování znaků v řetězci (typu &str). Ovšem, což je poměrně zajímavé, je podporováno získání podřetězce zápisem proměnná[from..to], přičemž from a to jsou indexy bajtů nikoli znaků. To může být dosti matoucí a může dokonce docházet k běhovým chybám, když se „trefíme“ do bajtu uprostřed znaku. Ukažme si způsob použití:
fn print_str(message: &str) { println!("'{}'", message); } fn main() { let message = "Hello world!"; let part1 = &message[0..5]; // pet znaku 0,1,2,3 a 4 let part2 = &message[5..6]; // jeden znak, to je "krome" let part3 = &message[6..12]; print_str(part1); print_str(part2); print_str(part3); }
Po spuštění se vypíše:
'Hello' ' ' 'world!'
Výsledkem „krájení“ je opět řetězec typu str, takže lze napsat i tento kód:
fn print_str(message: &str) { println!("'{}'", message); } fn main() { let message = "Hello world!"; let part = &message[0..10][2..5]; print_str(part); }
S výsledkem „llo“.
14. 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/presentations. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář:
15. Odkazy na Internetu
- 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