Výukový program Rust: Bezpečnost paměti a souběžnost

Poslední aktualizace: 04/12/2025
Autor: Isaac
  • Rust zajišťuje bezpečnost paměti při kompilaci prostřednictvím vlastnictví, výpůjček a životů, bez použití garbage collection.
  • Systém typů a pravidla aliasů umožňují souběžnost bez závodů v datech pomocí mutexů, kanálů a inteligentních ukazatelů.
  • Cargo, crates.io a aktivní ekosystém zjednodušují správu závislostí, kompilaci, testování a nasazení.
  • Pochopení struktur, výčtů, Option a Result je klíčem k řešení chyb a modelování bezpečných dat v souběžných aplikacích.

Programovací jazyk C vs. Rust: výhody a nevýhody

Rust se stal jedním z těch jazyků, které Každý vývojář systémů to slyší znovu a znovu.Je stejně rychlý jako C a C++, ale s téměř posedlým zaměřením na bezpečnost paměti a dobře provedenou souběžnost. Není to jen planý marketing: jeho design se točí kolem toho, že kompilátor detekuje chyby v době kompilace – chyby, které v jiných jazycích vidíte pouze tehdy, když je systém již v produkci… nebo když se zhroutí.

Máte-li zájem o porozumění Jak Rust dosahuje bezpečné paměti bez garbage collection a souběžnosti bez obav z běhu datTento tutoriál je určen právě vám. Probereme vše od základů jazyka a jeho ekosystému až po klíčové koncepty, jako je vlastnictví, výpůjčky, složené typy, nástroje jako Cargo, a dokonce se podíváme na atomické typy a zamykání z přístupnější perspektivy pro ty, kteří s souběžností teprve začínají, a to vše se zaměřením na bezpečnost a výkon.

Výukový program Rust: Výkon, bezpečnost paměti a souběžnost

Rust je programovací jazyk programování univerzální a multiparadigmatický, určený pro nízkoúrovňové systémové programování i pro projekty na vysoké úrovni, od OSOd herních enginů a prohlížečů až po vysoce výkonné webové služby, vznikl v Mozille s cílem zlepšit zabezpečení softwaru, zejména v citlivých komponentách, jako je prohlížečový engine.

Jeho určujícím rysem je, že zaručuje bezpečnost paměti během kompilace bez použití garbage collectoru. Místo toho Rust využívá systém vlastnictví a kontrolu vypůjčených hodnot, která sleduje dobu životnosti každé hodnoty a jejích referencí. Tím se zabrání klasickým problémům, jako jsou volné ukazatele, přetečení vyrovnávací paměti nebo úniky paměti, aniž by bylo nutné automatické počítání referencí nebo garbage collector.

Rust je navíc navržen tak, aby to usnadnil bezpečná souběžnostJeho model typů a vlastnictví zabraňuje datovým závodům mezi vlákny, alespoň při zachování bezpečnosti kódu v Rustu. To znamená, že mnoho nebezpečných situací je detekováno již během kompilace, ještě před provedením jediného řádku.

Z těchto důvodů mají velké společnosti rády Dropbox, Microsoft, Amazon nebo Google Zavedli Rust v kritických částech své infrastruktury. A není náhoda, že se již léta umístil na vrcholu anket Stack Overflow jako jeden z „nejoblíbenějších“ jazyků vývojářů: kombinuje výkon ve stylu C++ s moderní sadou nástrojů (Cargo, crates.io) a velmi aktivní komunitou, tzv. Rustaceans.

Základní pojmy: programovací jazyk, typy a paměť

Než se ponoříme do specifik zabezpečení paměti a souběžnosti, je vhodné objasnit některé obecné pojmy, které se objevují v celém textu. čas Při práci s Rustem, zvláště pokud pocházíte z jiných jazyků nebo s programováním teprve začínáte.

Programovací jazyk je v konečném důsledku sada pravidel a struktur, která umožňuje popisovat algoritmy a transformovat je do spustitelných programů. Rust se kompiluje do nativního strojového kódu pomocí svého kompilátoru rustcVýkon, kterého dosáhnete, je proto obvykle srovnatelný s C a C++.

Správa paměti je proces, kterým program rezervuje a uvolňuje bloky paměti za běhuChyby v této oblasti jsou často fatální: úniky paměti (neuvolnění nevyužité paměti), poškození dat v důsledku zápisu mimo povolené meze nebo použití paměti po jejím uvolnění. Rust to řeší velmi silným typovým systémem a formálními pravidly pro vlastnictví, výpůjčky a životnost paměti.

Rust také obsahuje termíny jako inteligentní typy a ukazateleTyp popisuje, jaký druh dat proměnná ukládá (celá čísla, čísla s plovoucí čárkou, řetězce, struktury atd.) a jak s nimi lze manipulovat. Inteligentní ukazatele (například Box, Rc y Arc) jsou struktury, které zapouzdřují paměťové adresy a přidávají další logiku pro bezpečnou správu zdrojů, jako je počítání sdílených odkazů nebo přesun hodnot do haldy.

V oblasti hospodářské soutěže se používají pojmy jako např. podmínky závodění, mutexy a kanály Stávají se nepostradatelnými: k souboji dochází, když více vláken současně přistupuje ke sdílenému zdroji a upravuje ho bez řádné koordinace; mutex (vzájemné vyloučení) zajišťuje, že do kritické sekce v daném okamžiku vstupuje pouze jedno vlákno; a kanály umožňují odesílání zpráv mezi vlákny bez přímého sdílení paměti.

Proč se učit Rust: Bezpečnost paměti a bezohledná souběžnost

Rust si vysloužil svou slávu, protože nabízí tři velmi cenné pilíře moderního programováníVýkon, zabezpečení a aktuální nástroje. Pojďme se podívat, proč jsou tyto body tak relevantní.

Co se týče výkonu, Rust kompiluje se přímo do nativních binárních souborů bez nutnosti virtuálního stroje nebo interpretu. Model abstrakcí s nulovými náklady si klade za cíl zajistit, aby abstrakce na vysoké úrovni nezvyšovaly režijní náklady za běhu. Proto je ideální pro vývoj systémů. hra, komponenty prohlížeče nebo mikroslužby s nízkou latencí.

Zabezpečení paměti je založeno na jejím systém vlastnictví a půjčekNeexistuje žádný garbage collector, ale kompilátor přesně ví, kdo vlastní jednotlivé zdroje, kdy již nejsou potřeba a kdy mohou být uvolněny. Tím se zabrání únikům dat, visícím ukazatelům a mnoha chybám, které tradičně dělaly programování v C a C++ tak nebezpečným.

V oblasti konkurence se Rust zabývá tím, co se obvykle nazývá „Souběžnost bez obav“Samotný typový systém brání existenci kořenových dat v zabezpečeném kódu. Pokud chcete sdílet proměnlivá data mezi vlákny, budete muset použít vhodné primitivy, jako například Mutex, RwLock o Arca kompilátor zajistí, aby byla dodržena pravidla pro aliasování a proměnlivost.

  Jak krok za krokem dezinfikovat Windows pomocí Malwarebytes

Vývojářský zážitek je vylepšen moderními nástroji, jako je např. NákladObsahuje integrovaného správce balíčků a infrastrukturu pro sestavení a široký ekosystém knihoven (cratů) pokrývajících vše od asynchronních sítí (Tokyo) až po webové frameworky (Actix, Rocket, Axum). To vše je podporováno otevřenou, plodnou a poměrně trpělivou komunitou, zejména pro začátečníky.

Instalace a nezbytné nástroje: rustup, rustc a Cargo

Pro psaní a spouštění prvních programů v Rustu je obvyklé začít instalací oficiální sady nástrojů pomocí rezavění (viz Kompletní úvod do Rustu), jednoduchý instalační program a správce verzí, který funguje na všech hlavních operačních systémech.

s rezavění Můžete instalovat, aktualizovat a přepínat mezi různými verzemi Rustu (stabilní, beta, noční) bez jakýchkoli problémů. Jednoduše přejděte na oficiální stránku nástrojů Rustu a postupujte podle kroků pro váš systém. Po instalaci bude kompilátor k dispozici. rustc, projektový manažer cargo a jeho vlastní rustup ve tvém terminál.

kompilátor rustc Je to to, co transformuje váš zdrojový kód do spustitelných binárních souborů nebo knihoven. I když ho můžete volat přímo pomocí příkazy jak rustc main.rsV praxi budete téměř vždy pracovat přes Cargo, které zpracovává volání do rustc se správnými možnostmi.

Ústředním nástrojem pracovního postupu je NákladPomocí několika příkazů můžete na crates.io vytvářet nové projekty, spravovat závislosti, kompilovat, spouštět, testovat a publikovat balíčky. Mezi běžně používané základní příkazy patří: cargo new, cargo build, cargo run, cargo test y cargo check, který kontroluje kód bez vytvoření finálního spustitelného souboru, což je ideální pro rychlou detekci chyb.

Pokud si chcete pohrát, aniž byste cokoli instalovali, Rust hřiště (oficiální online vykonavatel) a platformy jako Replit vám umožňují psát a spouštět malé kousky kódu z prohlížeče, což je ideální pro experimentování s pamětí a příklady souběžnosti, aniž byste museli nastavovat celé prostředí.

Váš první program: Hello, Rust a základní postup

Klasický způsob, jak začít konverzaci v jakémkoli jazyce, je slavným „Ahoj světe“. V Rustu soubor main.rs alespoň by mohlo obsahovat něco tak jednoduchého jako funkci main který vypíše řetězec na obrazovku.

Klíčové slovo fn znamená, že definujeme funkci a main Toto je vstupní bod programu. Blok kódu funkce se nachází uvnitř složených závorek. Pro zápis do konzole použijte makro println!, který přijímá řetězcový literál (nebo šablonu se záložkami) a odesílá ho na standardní výstup končící znakem nového řádku.

Pokud kompilujete přímo s rustc main.rs, získáte spustitelný binární soubor (například main o main.exe (v závislosti na systému). Po spuštění se v terminálu zobrazí zpráva. Ale idiomatický způsob práce s Rustem je nechat Cargo převzít vedení projektu.

s cargo new nombre_proyecto Struktura složek se automaticky vytvoří s src/main.rs již připravený s textem „Ahoj světe“ a souborem Cargo.toml který obsahuje metadata a budoucí závislosti. Odtud, cargo run zkompilovat a spustit binární soubora znovu se kompiluje pouze tehdy, když detekuje změny.

Tento způsob práce je nejen pohodlný, ale také vás od začátku zvykne na používání standardního ekosystému Rust, což se velmi hodí, když začnete přidávat balíčky pro souběžné práce, networking, testování nebo cokoli jiného, ​​co potřebujete.

// Deklarujeme hlavní funkci: vstupní bod programu fn main() { // Makro println! použijeme k výpisu textu do konzole println!("Ahoj světe!"); }

Proměnné, proměnlivost a základní datové typy

V Rustu se proměnné deklarují klíčovým slovem leta ve výchozím nastavení jsou neměnnéJinými slovy, jakmile jim přiřadíte hodnotu, nemůžete ji změnit, pokud ji explicitně nedeklarujete jako proměnlivou pomocí mut.

Neměnnost ve výchozím nastavení pomáhá vyhnout se jemným logickým chybám, zejména v souběžných programech, kde více vláken může chtít změnit stejnou hodnotu. Pokud ji potřebujete změnit, napíšete něco jako let mut contador = 0;Odtud můžete znovu přiřadit nové hodnoty contador.

Rust také umožňuje tzv. stínováníMůžete deklarovat novou proměnnou se stejným názvem ve stejném oboru platnosti a skrýt tak předchozí. To není totéž jako mutace, protože vytváříte novou hodnotu (která může být i jiného typu). Například můžete převést řetězec na celé číslo se stejným názvem, pokud se jedná o novou deklaraci s let.

Typový systém v Rustu je statický, což znamená, že Typ každé proměnné je znám při kompilaci.Odvozování typů je však poměrně účinné: pokud napíšete let x = 5;Kompilátor předpokládá, že se jedná o i32 Pokud neurčíte jinak. Můžete přidat poznámky, například let x: i64 = 5; když chcete být explicitní.

Mezi dostupné skalární typy patří celá čísla se znaménkem a bez znaménka (i8, u8, i32atd.), ty plovoucí (f32, f64), booleovské funkce (bool) a znaky Unicode (char). Tyto jednoduché typy se obvykle levně kopírují a mnoho z nich tuto vlastnost implementuje. Copycož znamená, že když je přiřadíte nebo předáte funkci, zkopírují se místo přesunou.

Řetězce v Rustu: &str a String

Práce s textem v Rustu může být zpočátku trochu matoucí, protože jasně rozlišuje mezi „dílce“ řetězce a proprietární řetězceDva klíčové kusy jsou &str y String.

Un &str je úsek neměnného řetězcePohled na bajtovou sekvenci UTF-8 uloženou někde. Typické příklady zahrnují literály jako "Hola"které jsou typu &'static str (Existují po celou dobu existence programu a jsou vloženy do binárního souboru.) Řezy nevlastní data; pouze na ně ukazují.

  Jak důkladně přizpůsobit hlavní panel ve Windows 11: Kompletní průvodce a pokročilé tipy

String, na druhou stranu, je vlastní řetězec, měnitelný a hostovaný v halděLze jej zvětšovat, zřetězovat, předávat mezi funkcemi přesunutím jeho vlastnosti atd. Často se používá, když chcete vytvářet dynamický text nebo jej dlouhodobě ukládat ve strukturách.

V mnoha scénářích budete přecházet mezi jedním a druhým: například vytvoříte String::from("hola") z kouskunebo si půjčíte &str ale tzv. String předáváním odkazů funkcím, které potřebují pouze číst.

Toto oddělení vlastněných a vypůjčených dat je klíčové pro správu paměti a rozšiřuje se i na zbytek jazyka: kolekce, struktury a výčty se řídí stejnými myšlenkami, kdo vlastní a kdo pouze prohlíží data.

Funkce, tok řízení a komentáře

Funkce v Rustu jsou definovány pomocí fn a umožňují organizaci programu do opakovaně použitelných logických jednotek. Každá funkce specifikuje typ jeho parametrů a jeho návratový typ po šípu ->Pokud nevrací nic smysluplného, ​​předpokládá se unitární typ. ().

Důležitým detailem je, že poslední výraz ve funkci (nebo libovolném bloku) bez středníku se bere jako implicitní návratová hodnota. Můžete použít return pro předčasné výnosyAle v idiomatickém kódu často jednoduše necháte poslední výraz bez něj. ;.

Řídicí tok je řešen klasicky if/elsesmyčky loop, while y forV Rustu, if Je to výraz, který vrací hodnotutakže ho můžete použít přímo v letza předpokladu, že větve vracejí stejný typ. Cykly for Obvykle iterují přes rozsahy nebo iterátory kolekcí a jsou doporučenou volbou místo ručních indexů.

Pro zdokumentování kódu a usnadnění života těm, kteří přijdou po něm (včetně vás za měsíc), můžete použít řádkové komentáře s // nebo blok s /* ... */Rust navíc nabízí komentáře k dokumentaci s /// které se stanou generovanými dokumenty, i když to se spíše hodí do velkých projektů.

Vlastnictví, půjčování a životnost: základ zabezpečení paměti

Zde se dostáváme k jádru paměťového modelu v Rustu: k systému vlastnictví, půjčky a životyTato pravidla zajišťují, že odkazy jsou vždy platné a že paměť je bezpečně uvolněna bez nahromaděného odpadu.

Základní pravidla vlastnictví se dají snadno stanovit, i když zpočátku může být obtížné je internalizovat: Každá hodnota má jednoho vlastníka.V daném okamžiku může být pouze jeden vlastník; a když vlastník opustí svůj rozsah, hodnota je zničena a její paměť je uvolněna. To platí například pro String: po dokončení bloku, kde byl deklarován, je automaticky vyvolán drop což uvolní paměť haldy.

Když přiřadíte správnou hodnotu jiné proměnné nebo ji předáte funkcí jako hodnotu, vlastnost se přesune. To znamená, že původní proměnná po přesunu přestane být platnáTato sémantika pohybu se vyhýbá dvojímu vydání, protože se nikdy neexistují dva vlastníci, kteří by se pokoušeli uvolnit stejný zdroj.

Aby bylo možné více částí programu přistupovat ke stejné hodnotě bez změny vlastnictví, Rust zavádí reference a půjčování. Při půjčování vytváříte referenci. &T (neměnný) nebo &mut T (měnnou) na hodnotu bez přenosu vlastnictví. Půjčka je omezena pravidly ověřovatele půjček., který kontroluje, zda reference nepřežijí data, na která odkazují, a zda nedochází k nebezpečnému smíchání proměnných a sdílených přístupů.

Pravidla půjčky lze shrnout následovně: kdykoli můžete mít buď více neměnných odkazů na hodnotu, nebo jeden proměnlivý odkazAle ne obojí současně. Tím se eliminují podmínky závodění ve sdílené paměti: buď existuje mnoho čtenářů, nebo izolovaný zapisovač; nikdy se nejedná o simultánní čtenáře a zapisovače na stejných datech ve stejném okamžiku.

Kompozitní typy: struktury, výčty a inteligentní ukazatele

Rust nabízí několik způsobů, jak seskupovat související data do bohatších struktur, počínaje strukturyStruktura umožňuje definovat vlastní typ s pojmenovanými poli, například uživatele s e-mailem, jménem, ​​stavem aktivity a počítadlem přihlášení.

Chcete-li vytvořit instanci struktury, vyplňte všechna její pole a proměnnou, která ji obsahuje, můžete označit jako proměnlivou, abyste mohli později upravit její hodnoty. Existuje také syntaxe aktualizace struktury, která umožňuje vytvořit novou instanci opětovným použitím některých polí z existující instance. ..otro_struct.

L výčty Jsou dalším zásadním pilířem: umožňují definovat typ, který může být jednou z několika možných variant, každá s vlastními přidruženými daty nebo bez nich. Klasickým příkladem je výčet IP adres s jednou variantou V4 který ukládá čtyři oktety a další V6 který ukládá řetězec s notací IPv6.

Standardní knihovna Rustu obsahuje dva velmi důležité výčty: Option<T> y Result<T, E>První představuje přítomnost nebo nepřítomnost hodnoty (něco nebo nic) a používá se k zamezení nulovým ukazatelům; druhý modeluje operace, které mohou vrátit správný výsledek nebo chybu, což vyžaduje, aby ošetření chyb bylo explicitní a bezpečné.

Pro správu dynamické paměti a sdílení dat má Rust chytré ukazatele jak Box<T>, který přesune hodnotu do haldy a zachová jedinečné vlastnictví; Rc<T>, sdílený počet referencí pro prostředí s jedním vláknem; a Arc<T>, podobně jako Rc ale bezpečné pro více vláken. Jejich správné použití je klíčové při kombinaci dynamické paměti se souběžností.

Náklad a ekosystém beden

Cargo je pojivo, které drží ekosystém Rustu pohromadě: spravuje kompilaci, závislosti a životní cyklus projektuKaždý projekt má soubor Cargo.toml který funguje jako manifest, deklarující název, verzi, jazykovou edici a externí závislosti.

  Opraveno: Windows 10 Interní chyba ovladače sběrnice PCI

Sekce Tento soubor umožňuje zobrazit seznam balíčků třetích stran s jejich verzemi. Po spuštění cargo build o cargo runCargo tyto balíčky automaticky stáhne z crates.io, zkompiluje je a propojí s vaším projektem. Stejně snadno lze například přidat generátory náhodných čísel, webové frameworky nebo kryptografické knihovny.

Mezi nejběžnější příkazy patří cargo new spustit binární projekty o cargo new --lib pro knihovny; cargo build kompilovat v ladicím režimu; cargo build --release získat optimalizovanou verzi orientovanou na produkci; a cargo test spustit řadu testů.

cargo check Zaslouží si zvláštní zmínku: zkompiluje kód do mezilehlého bodu bez generování binárního souboru, což z něj dělá být velmi rychlý v detekci chyb kompilaceJe to perfektní pro rychlé iterace, zatímco kontrola výpůjček upozorňuje na problémy s vlastnostmi, referencemi a dobami života.

Díky tomuto ekosystému je běžné strukturovat projekty jako malé, dobře definované balíčky (craty), sdílet mezi nimi kód a znovu používat řešení vytvořená komunitou. Pro pokročilou souběžnost budete mít například balíčky jako Tokio pro asynchronní programování nebo Crossbeam pro vysoce výkonné souběžné datové struktury.

Souběžnost v Rustu: vlákna, mutexy, kanály a atomické objekty

Souběžnost je jedním z důvodů, proč Rust vzbuzuje tolik zájmu: umožňuje využít výhod vícejádrových procesorů. aniž by upadal do typických chyb vláken a sdílené pamětiPokud se s těmito tématy zabýváte poprvé, je užitečné rozlišovat mezi několika pojmy.

Souběžné provádění zahrnuje provádění více úloh, které se časově překrývají, a to buď na jednom, nebo více jádrech. V Rustu můžete vytvářet systémová vlákna pro paralelní provádění práce a jazyk vás vede k zajištění bezpečného sdílení dat mezi nimi. Klasickou chybou je souboj, kdy dvě vlákna současně přistupují k datům a upravují je a výsledek závisí na pořadí provádění – což je velmi obtížné ladit.

Pro koordinaci přístupu ke sdíleným datům se Rust spoléhá na primitiva, jako například mutexkteré zaručují vzájemné vyloučení: do kritické sekce může v daném okamžiku vstoupit pouze jedno vlákno. V kombinaci s Arc<T> Pro sdílení vlastnictví mezi vlákny je možné vytvořit sdílené datové struktury, které splňují pravidla vlastnictví a výpůjček.

Další běžnou formou mezivláknové komunikace, v Rustu silně podporovanou, je předávání zpráv pomocí CanalesKanál má odesílací a přijímací stranu; vlákna jím předávají zprávy (hodnoty), což snižuje využití proměnlivé sdílené paměti a zjednodušuje uvažování o stavu systému.

Když se hlouběji ponoříte do nízkoúrovňové souběžnosti, objeví se následující: atomové typyK atomickým proměnným se přistupuje prostřednictvím operací, které jsou z pohledu vlákna nedělitelné. To umožňuje implementaci sdílených čítačů, stavových příznaků, front bez uzamčení a dalších. Zvládnutí atomických proměnných vyžaduje pochopení paměťových modelů a přístupových příkazů, takže mnoho vývojářů raději začíná s mutexy a kanály, než se ponoří do těchto detailů.

První kroky a zdroje pro učení se souběžnosti a atomických funkcí

Pokud vstupujete do arény bez předchozích zkušeností, nejmoudřejším postupem je vybudovat pevný základ obecných pojmů Než se pustíme do pokročilých nástrojů, jako jsou atomické typy v Rustu. Knihy jako „Programování v Rustu“ nabízejí postupný úvod, ale je normální, že práce zaměřené na atomické typy a zámky se zpočátku zdají být zbytečné.

Pro větší přehlednost je vhodné se nejprve seznámit s Tradiční vlákna, vzájemné vyloučení a předávání zpráv v Rustu. Pohrajte si s příklady std::thread, std::sync::Mutex, std::sync::Arc a kanály std::sync::mpsc Pomáhá vám pochopit, jak vás kompilátor vede a jakým chybám se vyhýbá.

Současně se důrazně doporučuje prostudovat si úvodní materiály o souběžnosti obecně, i když se nezaměřují na Rust: pochopení toho, co jsou závodní podmínky, co znamená blokování, co znamená sdílená paměť versus předávání zpráv a jak se používají zámky. Jakmile se vám tyto koncepty stanou přirozenými, atomová fyzika přestává být „černou magií“. a stanou se jen dalším nástrojem, jen velmi jemným.

Až se vrátíte k pokročilejším textům o atomických strukturách a zámcích v Rustu, bude mnohem snazší sledovat uvažování, pokud již chápete, jaký problém se každá konstrukce snaží vyřešit: od jednoduchého vláknově bezpečného čítače až po struktury bez zámků, které minimalizují konflikty.

Rust v konečném důsledku nabízí jak primitiva na vysoké úrovni, tak i nástroje na velmi nízké úrovni a klíčem je vždy zvolit nejbezpečnější úroveň abstrakce, která řeší váš problém, a uchýlit se k atomickému kódu. unsafe pouze tehdy, když to skutečně přidává hodnotu a vy plně chápete jeho důsledky.

Celý tento ekosystém typů, vlastnictví, výpůjček, beden, nástrojů a primitiv pro souběžnost se snoubí a nabízí jazyk, ve kterém lze psát. rychlý, robustní a snadno udržovatelný softwareTím se minimalizuje mnoho typů chyb, které historicky trápily systémové programování. Jak budete procvičovat malé projekty, cvičení jako Rustlings a oficiální dokumentaci, tyto koncepty se zdánlivě jako přísná pravidla stanou spojencem, který vás varuje dříve, než se problém dostane do produkčního prostředí.

Úvod do jazyka Rust s příklady-0
Související článek:
Kompletní úvod do Rustu: Praktický průvodce pro začátečníky s příklady