- Rust осигурава безбедност меморије приликом компајлирања кроз власништво, позајмљивање и животне векове, без коришћења сакупљања смећа.
- Систем типова и правила алијасинга омогућавају конкурентност без трка података коришћењем мутекса, канала и паметних показивача.
- Cargo, crates.io и активни екосистем поједностављују управљање зависностима, компајлирање, тестирање и имплементацију.
- Разумевање структура, набрајања, опција и резултата је кључно за руковање грешкама и моделирање безбедних података у истовременим апликацијама.
Руст је постао један од оних језика који Сваки системски програмер то чује изнова и изнова.Брз је као C и C++, али са готово опсесивним фокусом на безбедност меморије и добро извршену конкурентност. Ово није само празан маркетинг: његов дизајн се врти око тога да компајлер детектује грешке током компајлирања – грешке које у другим језицима видите само када је систем већ у продукцији... или када се сруши.
Ако вас занима разумевање Како Руст постиже безбедну меморију без сакупљања смећа и конкурентност без страха од покретања податакаОвај туторијал је за вас. Обрадићемо све, од основа језика и његовог екосистема до кључних концепата као што су власништво, позајмљивање, сложени типови, алати попут Cargo-а, па чак и погледаћемо атомске типове и закључавање из приступачније перспективе за оне који су нови у конкурентности, све са фокусом на безбедност и перформансе.
Руст туторијал: Перформансе, безбедност меморије и конкурентност
Rust је програмски језик програмирање опште намене и вишеструке парадигме, дизајниране за системско програмирање ниског нивоа, као и за пројекте високог нивоа, фром ОСОд гејм енџина и прегледача до високоперформансних веб сервиса, настао је у Мозили са циљем побољшања безбедности софтвера, посебно у осетљивим компонентама попут прегледача.
Његова карактеристична одлика је да гарантује безбедност меморије током компајлирања без коришћења сакупљача смећа. Уместо тога, Rust користи систем власништва и проверу позајмљивања која прати животни век сваке вредности и њених референци. Ово избегава класичне проблеме попут висећих показивача, преливања бафера или цурења меморије без потребе за аутоматским бројањем референци или сакупљањем смећа.
Штавише, Rust је дизајниран да олакша безбедно присуствоЊегов модел типа и власништва спречава трке података између нити, барем док остаје безбедан у Rust коду. То значи да се многе опасне ситуације откривају током компајлирања, пре него што се изврши и једна линија.
Због свих ових разлога, велике компаније воле Дропбокс, Мајкрософт, Амазон или гоогле Усвојили су Rust у критичним деловима своје инфраструктуре. И није случајно што је годинама на врху анкета Stack Overflow-а као један од „најомиљенијих“ језика међу програмерима: комбинује перформансе у C++ стилу са модерним скупом алата (Cargo, crates.io) и веома активном заједницом, такозваним Rustaceans.
Основни појмови: програмски језик, типови и меморија
Пре него што се удубимо у специфичности безбедности меморије и конкурентности, вреди разјаснити неке опште концепте који се појављују свуда ел тиемпо Приликом рада са Рустом, посебно ако долазите из других језика или тек почињете да програмирате.
Програмски језик је, на крају крајева, скуп правила и структура који вам омогућава да опишете алгоритме и трансформисати их у извршне програме. Rust компајлира у изворни машински код користећи свој компајлер rustcСтога, перформансе које добијате су обично упоредиве са C и C++.
Управљање меморијом је процес којим програм резервише и ослобађа блокове меморије током радаГрешке у овој области су често фаталне: цурење меморије (неуспех у ослобађању неискоришћене меморије), оштећење података услед писања ван граница или коришћење меморије након што је ослобођена. Rust ово решава веома јаким системом типова и формалним правилима за власништво, позајмљивање и животне векове.
Рђа такође садржи термине као што су паметни типови и показивачиТип описује какве податке променљива чува (целе бројеве, бројеве са покретним дејлом, стрингове, структуре итд.) и како се њима може манипулисати. Паметни показивачи (на пример, Box, Rc y Arc) су структуре које капсулирају меморијске адресе и додају додатну логику за безбедно управљање ресурсима, као што је бројање дељених референци или премештање вредности на хип.
У области конкуренције, концепти као што су услови трке, мутекси и канали Они постају неопходни: услов трке се јавља када више нити истовремено приступа и мења дељени ресурс без одговарајуће координације; mutex (узајамно искључивање) осигурава да само једна нит улази у критичну секцију у датом тренутку; а канали омогућавају слање порука између нити без директног дељења меморије.
Зашто учити Rust: Безбедност меморије и бесстрашна конкурентност
Рђа је заслужила своју славу јер нуди Три веома вредна стуба за модерно програмирањеПерформансе, безбедност и актуелни алати. Хајде да видимо зашто су ове тачке толико релевантне.
Што се тиче перформанси, Руст компајлира директно у изворне бинарне датотеке без потребе за виртуелном машином или интерпретером. Модел апстракција са нултим трошковима има за циљ да осигура да апстракције високог нивоа не додају оптерећење током извршавања. Стога је идеалан за развој система. игра, компоненте прегледача или микросервисе са малом латенцијом.
Безбедност меморије заснива се на њеном систем власништва и кредитаНе постоји сакупљач смећа, али компајлер тачно зна ко је власник сваког ресурса, када више није потребан и када може бити ослобођен. Ово спречава цурење, висеће показиваче и многе грешке које су традиционално чиниле C и C++ програмирање тако опасним.
У области конкуренције, Руст тежи ономе што се обично назива „Истовременост без страха“Сам систем типова спречава постојање корена података у безбедном коду. Ако желите да делите променљиве податке између нити, мораћете да користите одговарајуће примитиве као што су Mutex, RwLock o Arc, а компајлер ће осигурати да се поштују правила алијасинга и променљивости.
Искуство развоја је побољшано модерним алатима као што су КаргоСадржи интегрисани менаџер пакета и инфраструктуру за изградњу, као и широк екосистем библиотека (crates) које покривају све, од асинхроног умрежавања (Tokyo) до веб фрејмворка (Actix, Rocket, Axum). Све ово подржава отворена, плодна и прилично стрпљива заједница, посебно за почетнике.
Инсталација и неопходни алати: Rustup, Rustc и Cargo
Да бисте написали и покренули своје прве програме у Русту, уобичајени начин за почетак је инсталирање званичног скупа алата користећи руступ (видети Комплетан увод у Руст), једноставан инсталер и менаџер верзија који ради на свим главним оперативним системима.
са руступ Можете инсталирати, ажурирати и прелазити између различитих верзија Руста (стабилна, бета, ноћна) без икаквог оштећења. Једноставно идите на званичну страницу Руст алата и пратите кораке за ваш систем. Након инсталације, компајлер ће бити доступан. rustc, руководилац пројекта cargo и своје rustup у свом терминал.
компајлер rustc То је оно што трансформише ваш изворни код у извршне бинарне датотеке или библиотеке. Иако бисте га могли директно позвати помоћу команде као rustc main.rsУ пракси, скоро увек ћете радити преко Cargo-а, који обрађује позиве ка rustc са правим опцијама.
Централни алат тока посла је КаргоСа само неколико команди, можете креирати нове пројекте, управљати зависностима, компајлирати, покретати, тестирати и објављивати пакете на crates.io. Неке често коришћене основне команде су: cargo new, cargo build, cargo run, cargo test y cargo check, који проверава код без креирања коначне извршне датотеке, идеално за брзо откривање грешака.
Ако желите да се позабавите без инсталирања било чега, Руст Плаигроунд (званични онлајн извршилац) и платформе попут Replit-а вам омогућавају да пишете и покрећете мале делове кода из прегледача, што је савршено за експериментисање са примерима меморије и конкурентности без потребе за подешавањем целог окружења.
Ваш први програм: Здраво, Руст и основни ток
Класичан начин за започињање разговора на било ком језику је чувена фраза „Здраво, свете“. У Русту, датотека main.rs барем би могла да садржи нешто једноставно као што је функција main који исписује стринг на екрану.
Кључна реч fn означава да дефинишемо функцију, и main Ово је улазна тачка програма. Блок кода функције се налази унутар витичастих заграда. Да бисте писали у конзолу, користите макро println!, који прихвата стринг литерал (или шаблон са обележивачима) и шаље га на стандардни излаз, завршавајући се карактером за нови ред.
Ако компајлирате директно са rustc main.rs, добићете извршну бинарну датотеку (на пример, main o main.exe (у зависности од система). Када га покренете, видећете поруку у терминалу. Али идиоматски начин рада са Рустом је да се Карго-у дозволи да преузме вођство над пројектом.
са cargo new nombre_proyecto Структура фасцикли се аутоматски креира са src/main.rs већ припремљено са „Здраво, свете“ и датотеком Cargo.toml који садржи метаподатке и будуће зависности. Одатле, cargo run компајлирајте и покрените бинарни фајли поново се компајлира само када детектује промене.
Овакав начин рада није само згодан, већ вас од самог почетка навикава на коришћење стандардног Rust екосистема, што је веома корисно када почнете да додајете crate-ове за конкурентност, умрежавање, тестирање или шта год вам је потребно.
// Декларишемо главну функцију: тачка уласка у програм fn main() { // Користимо макро println! за испис текста у конзолу println!("Здраво, свете!"); }
Променљиве, променљивост и основни типови података
У Русту, променљиве се декларишу кључном речи letи подразумевано су непроменљивиДругим речима, када им доделите вредност, не можете је мењати осим ако је експлицитно не декларишете као променљиву помоћу mut.
Непроменљивост по подразумеваним подешавањима помаже у избегавању суптилних логичких грешака, посебно у истовременим програмима где више нити може желети да промени исту вредност. Ако је потребно да је промените, напишете нешто попут let mut contador = 0;Одатле можете поново доделити нове вредности contador.
Рђа такође омогућава тзв. сјенчањеМожете декларисати нову променљиву са истим именом унутар истог опсега, сакривајући претходну. Ово није исто што и мутирање, јер креирате нову вредност (која чак може бити и другачијег типа). На пример, можете конвертовати из стринга у цео број користећи исто име, све док је то нова декларација са let.
Рустов систем типова је статичан, што значи да Тип сваке променљиве је познат при компајлацијиМеђутим, закључивање о типу је прилично моћно: ако напишете let x = 5;Компилатор претпоставља да је у питању i32 Осим ако не наведете другачије. Можете додати напомене као што су let x: i64 = 5; када желите да будете експлицитни.
Међу доступним скаларним типовима су означени и неозначени цели бројеви (i8, u8, i32, итд.), плутајући (f32, f64), Булове функције (bool) и Unicode знакове (char). Ови једноставни типови су обично јефтини за копирање и многи имплементирају ту особину Copyшто значи да када их доделите или проследите функцији, они се копирају уместо да се премештају.
Стрингови у Русту: &str и Стринг
Обрада текста у Русту може бити мало збуњујућа у почетку јер јасно прави разлику између „кришке“ ланца и власнички ланциДва кључна дела су &str y String.
Un &str је део непроменљивог ланцаПриказ UTF-8 бајт секвенце сачуване негде. Типични примери укључују литерале као што су "Hola"које су типа &'static str (Они постоје током целог трајања програма и уграђени су у бинарни фајл.) Сегменти не поседују податке; они само указују на њих.
String, с друге стране, јесте сопствени стринг, променљив и смештен у хипуМоже му се мењати величина, спајати, преносити између функција померањем његовог својства итд. Често се користи када желите да направите динамички текст или га дугорочно сачувате унутар структура.
У многим сценаријима ћете се трансформисати између једног и другог: на пример, креираћете String::from("hola") са парчетаили ћете позајмити &str по String прослеђивањем референци функцијама које треба само да читају.
Ово раздвајање између поседованих и позајмљених података је кључно за управљање меморијом и протеже се на остатак језика: колекције, структуре и набрајања прате исте идеје о томе ко је власник, а ко само гледа.
Функције, ток контроле и коментари
Функције у Русту су дефинисане са fn и омогућавају организовање програма у логичке јединице које се могу поново користити. Свака функција одређује тип његових параметара и тип његовог повратка пратећи стрелицу ->Ако не врати ништа смислено, претпоставља се унитарни тип. ().
Важан детаљ је да се последњи израз у функцији (или било ком блоку) без тачке-зареза узима као имплицитна повратна вредност. Можете користити return за ране повраћајеАли у идиоматском коду, често једноставно остављате последњи израз без њега. ;.
Контролни ток се обрађује класичним методама if/elseпетље loop, while y forУ Русту, if То је израз који враћа вредносттако да га можете директно користити у letпод условом да гране враћају исти тип. Петље for Они обично итерирају кроз опсеге или итераторе колекција и препоручена су опција уместо ручних индекса.
Да бисте документовали код и олакшали живот свакоме ко дође после (укључујући и вас за месец дана), можете користити коментари у линији са // или блокирати са /* ... */Поред тога, Rust нуди коментаре на документацију са /// који постају генерисани документи, мада се то више уклапа у велике пројекте.
Власништво, позајмљивање и животни век: темељ безбедности меморије
Овде долазимо до сржи Рустовог модела меморије: система власништво, задуживање и животни векОва правила осигуравају да су референце увек валидне и да се меморија безбедно ослобађа без нагомиланог смећа.
Основна правила власништва су једноставна за навођење, иако их у почетку може бити тешко интернализовати: Свака вредност има једног власника.Може постојати само један власник у датом тренутку; и када власник напусти свој опсег, вредност се уништава и њена меморија се ослобађа. Ово се односи, на пример, на String: након завршетка блока где је декларисан, аутоматски се позива drop што ослобађа хип меморију.
Када доделите одговарајућу вредност другој променљивој или је проследите функцији по вредности, својство се премешта. То значи да оригинална променљива престаје да важи након померањаОва семантика кретања избегава двострука објављивања, јер никада не постоје два власника која покушавају да објаве исти ресурс.
Да би омогућио вишеструким деловима програма приступ истој вредности без промене власништва, Rust уводи референце и позајмљивање. Када позајмљујете, креирате референцу. &T (непроменљиво) или &mut T (променљива) на вредност без преноса власништва. Зајам је ограничен правилима верификатора зајма., који проверава да ли референце наџиве податке на које указују и да ли се променљиви и дељени приступи опасно мешају.
Правила кредита могу се сумирати на следећи начин: у било ком тренутку можете имати више непроменљивих референци до вредности, или једна променљива референцаАли не оба истовремено. Ово елиминише услове трке у дељеној меморији: или постоји много читача, или постоји изоловани писац; никада истовремени читачи и писци на истим подацима у истом тренутку.
Композитни типови: структуре, набрајања и паметни показивачи
Rust пружа неколико начина за груписање повезаних података у богатије структуре, почевши од структуреСтруктура вам омогућава да дефинишете прилагођени тип са именованим пољима, на пример корисника са имејлом, именом, статусом активности и бројачем пријава.
Да бисте креирали инстанцу структуре, попуните сва њена поља и можете означити променљиву која је садржи као променљиву да бисте касније изменили њене вредности. Постоји и синтакса ажурирања структуре, која вам омогућава да направите нову инстанцу поновним коришћењем неких поља из постојеће. ..otro_struct.
Л набрајања Они су још један суштински стуб: омогућавају вам да дефинишете тип који може бити једна од неколико могућих варијанти, свака са својим придруженим подацима или без њих. Класичан пример је набрајање за IP адресе, са једном варијантом V4 који чува четири октета и још један V6 који чува стринг са IPv6 нотацијом.
Рустова стандардна библиотека укључује два веома важна набрајања: Option<T> y Result<T, E>Први представља присуство или одсуство вредности (нешто или ништа) и користи се да би се избегли нулти показивачи; други моделира операције које могу вратити тачан резултат или грешку, захтевајући да обрада грешака буде експлицитна и безбедна.
Да би управљао динамичком меморијом и дељивао податке, Rust има паметни показивачи као Box<T>, који премешта вредност на хип и одржава јединствено власништво; Rc<T>, дељени број референци за окружења са једним нитом; и Arc<T>, слично Rc али безбедно за више нити. Њихово правилно коришћење је кључно при комбиновању динамичке меморије са конкурентношћу.
Терет и екосистем сандука
Карго је лепак који држи Руст екосистем заједно: управља компајлацијом, зависностима и животним циклусом пројектаСваки пројекат има датотеку Cargo.toml који делује као манифест, декларишући име, верзију, језичко издање и спољне зависности.
Одељак Ова датотека вам омогућава да наведете сандуке трећих страна са њиховим верзијама. Када покренете cargo build o cargo runКарго аутоматски преузима ове сандуке са crates.io, компајлира их и повезује са вашим пројектом. Тако је лако додати, на пример, генераторе случајних бројева, веб фрејмворке или криптографске библиотеке.
Међу најчешћим командама су cargo new да покренете бинарне пројекте o cargo new --lib за библиотеке; cargo build компајлирати у режиму за дебаговање; cargo build --release да се добије оптимизована, производно оријентисана верзија; и cargo test да покрене низ тестова.
cargo check Заслужује посебан помен: компајлира код до међутачке без генерисања бинарне датотеке, што га чини бити веома брз у откривању грешака у компајлацијиСавршено је за брзо понављање док провера позајмљивања указује на проблеме са својствима, референцама и животним вековима.
Захваљујући овом екосистему, уобичајено је да структурирате своје пројекте као мале, добро дефинисане „кревете“, делећи код између њих и поново користећи решења која је креирала заједница. За напредну конкурентност, на пример, имаћете „кревете“ попут Tokio-а за асинхроно програмирање или crossbeam-а за конкурентне структуре података високих перформанси.
Конкурентност у Русту: нити, мутекси, канали и атомици
Конкурентност је један од разлога зашто Rust изазива толико интересовања: омогућава вам да искористите предности вишејезгарних процесора. без упадања у типичне грешке нити и дељене меморијеАко се први пут бавите овим темама, корисно је разликовати неколико концепата.
Конкуренција подразумева извршавање више задатака који се временски преклапају, било на једном или више језгара. У Русту можете креирати системске нити за паралелно обављање посла, а језик вас води како бисте осигурали да је дељење података између њих безбедно. Класична грешка је услов трке, где две нити истовремено приступају и мењају податке, а резултат зависи од редоследа извршавања – нешто што је веома тешко отклонити грешке.
Да би координирао приступ дељеним подацима, Rust се ослања на примитиве као што су мутекшто гарантује међусобно искључивање: само једна нит може ући у критичну секцију у датом тренутку. У комбинацији са Arc<T> Да би се власништво делило између нити, могуће је изградити заједничке структуре података које су у складу са правилима власништва и позајмљивања.
Још један уобичајени облик међунитне комуникације, који се снажно подстиче у Русту, јесте преношење порука помоћу каналиКанал има страну за слање и страну за пријем; нити преносе поруке (вредности) кроз њега, што смањује употребу променљиве дељене меморије и поједностављује расуђивање о стању система.
Када се дубље зарони у конкурентност ниског нивоа, појављује се следеће: атомски типовиАтомским променљивим се приступа кроз операције које су недељиве из перспективе нити. Ово омогућава имплементацију дељених бројача, заставица стања, редова без закључавања и још много тога. Савладавање атомских променљивих захтева разумевање модела меморије и команди приступа, тако да многи програмери више воле да почну са мутексима и каналима пре него што се удубе у ове детаље.
Први кораци и ресурси за учење конкурентности и атомског
Ако улазите у арену без претходног искуства, најмудрији начин деловања је изградити чврст темељ општих концепата пре него што се позабавимо напредним алатима попут атомских типова у Русту. Књиге попут „Програмирање Рустом“ нуде постепен увод, али је нормално да радови усмерени на атомске типове и браве у почетку делују згуснуто.
Ради веће једноставности, препоручљиво је да се прво упознате са Традиционалне нити, међусобно искључивање и преношење порука у Русту. Играјте се са примерима std::thread, std::sync::Mutex, std::sync::Arc и канали std::sync::mpsc Помаже вам да разумете како вас компајлер води и које грешке избегава.
Паралелно, топло се препоручује преглед уводних ресурса о конкурентности уопште, чак и ако нису фокусирани на Rust: разумевање шта су услови трке, шта значи блокирање, шта подразумева дељена меморија у односу на пренос порука и како се користе закључавања. Када вам ти концепти постану природни, атомска физика престаје да буде „црна магија“. и постају само још једно оруђе, само веома деликатно.
Када се вратите на напредније текстове о атомским структурама и бравама у Русту, биће вам много лакше да пратите образложење ако већ разумете који проблем свака конструкција покушава да реши: од једноставног бројача безбедног за више нити до структура без брава које минимизирају сукоб.
На крају крајева, Rust нуди и примитиве високог нивоа и алате веома ниског нивоа, а кључ је у томе да увек изаберете најбезбеднији ниво апстракције који решава ваш проблем, прибегавајући атомском коду. unsafe само када заиста додаје вредност и када у потпуности разумете његове импликације.
Читав овај екосистем типова, власништва, позајмљивања, сандука, алата и примитивних елемената конкурентности комбинује се да би понудио језик за писање брз, робустан и одржавајући софтверОво минимизира многе врсте грешака које су историјски мучиле системско програмирање. Како вежбате са малим пројектима, вежбама попут Rustlings-а и званичном документацијом, ови концепти ће прећи из строгих правила у савезника који вас упозорава пре него што проблем стигне до продукције.
Страствени писац о свету бајтова и технологије уопште. Волим да делим своје знање кроз писање, и то је оно што ћу радити на овом блогу, показивати вам све најзанимљивије ствари о гаџетима, софтверу, хардверу, технолошким трендовима и још много тога. Мој циљ је да вам помогнем да се крећете у дигиталном свету на једноставан и забаван начин.