Melyik évben jelent meg a rozsda programozási nyelv. Rozsda: új programozási nyelv használatának megkezdése a Mozilla szakembereitől. Egy egyszerű módja egy új Cargo projekt létrehozásának

  • Dátum: 14.05.2021

Rozsda egy új kísérleti programozási nyelv, amelyet a Mozilla fejlesztett ki. A nyelv összeállított és több paradigmát tartalmaz, a C / C ++ alternatívájaként helyezkedik el, ami önmagában is érdekes, mivel nincs olyan sok versenyző a versenyben. Gondoljunk csak Walter Bright D-jára vagy a Google Go-jára.
A Rust támogatja a funkcionális, párhuzamos, procedurális és objektumorientált programozást, pl. az alkalmazott programozásban ténylegesen használt paradigmák szinte teljes skálája.

A dokumentációt nem áll szándékomban lefordítani (ráadásul nagyon szűkös és folyamatosan változik, hiszen még nem készült hivatalos kiadás a nyelvről), ehelyett a nyelv legérdekesebb vonásait szeretném kiemelni. Az információkat mind a hivatalos dokumentációból, mind a nyelv interneten található nagyon kevés említéséből gyűjtöttük össze.

Első benyomás

A nyelv szintaxisa a hagyományos C-szerű stílusban épül fel (ami jó hír, hiszen ez már de facto szabvány). Természetesen figyelembe vették a jól ismert C / C ++ tervezési hibákat.
A hagyományos Hello World így néz ki:
std használata; fn main (args :) (std :: io :: println ("hello world from" + args + "!");)

Egy példa egy kicsit bonyolultabb - a faktoriális kiszámításának függvénye:

Fn fac (n: int) -> int (legyen eredmény = 1, i = 1; míg i<= n { result *= i; i += 1; } ret result; }

Amint a példából látható, a függvények "funkcionális" stílusban vannak deklarálva (ennek a stílusnak van néhány előnye a hagyományos "int fac (int n)"-hez képest). Látjuk automatikus típuskövetkeztetés(let kulcsszó), míg az argumentumnak nincs zárójele (hasonlóan a Go-hoz). A kulcsszavak tömörsége is azonnal szembeötlő. A Rust készítői valóban céltudatosan fogalmazták meg az összes kulcsszót a lehető legrövidebbre, és hogy őszinte legyek, én ezt szeretem.

Kicsi, de érdekes szintaktikai jellemzők

  • A numerikus konstansokban aláhúzásjeleket használhat. Egy praktikus dolog, hogy most ez a funkció sok új nyelven megjelenik.
    0xffff_ffff_ffff_ffff_ffff_ffff
  • Bináris állandók. Természetesen egy igazi programozónak fejben kell átalakítania a bin-t hatszögletűvé, de ez kényelmesebb! 0b1111_1111_1001_0000
  • Minden operátor testét (még az egyetlen kifejezésből állókat is) kapcsos zárójelek közé kell zárni. Például C-ben beírhatja, ha (x> 0) foo (); , Rozsdában feltétlenül göndör fogszabályzót kell tenni a foo () köré
  • De az if, while és hasonló operátorok érveit nem kell zárójelbe tenni.
  • sok esetben a kódblokkok kifejezésekként is felfoghatók. Ez különösen lehetséges például:
    legyen x = if the_stars_align () (4) else if something_else () (3) else (0);
  • szintaxis függvények deklarálásához - először az fn kulcsszó, majd az argumentumok listája, a név után az argumentum típusa, majd ha a függvény értéket ad vissza, a "->" nyíl és a visszatérési érték típusa
  • A változók deklarálása hasonló módon történik: a let kulcsszó, a változó neve, a változó után kettősponttal megadhatjuk a típust, majd adjunk hozzá egy kezdőértéket.
    számoljunk: int = 5;
  • alapértelmezés szerint minden változó megváltoztathatatlan; a mutable kulcsszó a változó változók deklarálására szolgál.
  • az alaptípusnevek a legkompaktabbak, amikkel találkoztam: i8, i16, i32, i64, u8, u16, u32, u64, f32, f64
  • mint fentebb említettük, az automatikus típuskövetés támogatott
A nyelv beépített eszközökkel rendelkezik a programok hibakereséséhez:
Kulcsszó nem sikerül befejezi az aktuális folyamatot
Kulcsszó log bármilyen nyelvi kifejezést ad ki a naplóba (például az stderr-be)
Kulcsszó állítja ellenőrzi a kifejezést, és ha hamis, kilép az aktuális folyamatból
Kulcsszó jegyzet lehetővé teszi további információk megjelenítését a folyamat rendellenes leállása esetén.

Adattípusok

A Rust, akárcsak a Go, támogatja szerkezeti tipizálás(bár a szerzők szerint a nyelvek egymástól függetlenül fejlődtek, így ez közös elődeik - Alef, Limbo stb. - hatása). Mi az a szerkezeti tipizálás? Például valamilyen fájlban deklarált struktúra (vagy Rust terminológiával "rekord")
típus pont = (x: lebegés, y: lebegés);
Egy csomó változót és függvényt deklarálhat "pont" argumentumtípusokkal. Aztán valahol máshol deklarálhatsz például valamilyen más szerkezetet
írja be a MySuperPoint = (x: lebegés, y: lebegés);
és az ilyen típusú változók teljes mértékben kompatibilisek lesznek a pont típusú változókkal.

Ezzel szemben a C, C ++, C # és Java nyelvekben használt névelő típusok nem teszik lehetővé az ilyen konstrukciókat. A névelő gépeléssel minden struktúra egyedi típus, alapértelmezés szerint nem kompatibilis más típusokkal.

A Rust struktúráit "rekordoknak" nevezik. Vannak sorok is – ezek ugyanazok a rekordok, de névtelen mezőkkel. A rekord elemeitől eltérően a sor elemei nem változtathatók.

Vannak olyan vektorok, amelyek bizonyos tekintetben hasonlítanak a közönséges tömbökhöz, és bizonyos szempontból az std :: vektor típusú stl-ből. A lista inicializálása szögletes zárójeleket használ, nem szögletes zárójeleket, mint a C / C ++-ban

Legyen myvec =;

A vektor azonban egy dinamikus adatstruktúra, különösen a vektorok támogatják az összefűzést.

Legyen v: változó =; v + =;

Vannak sablonok. A szintaxisuk teljesen logikus, a C ++ "sablon" rendetlensége nélkül. A funkciósablonok és adattípusok támogatottak.

Fn for_rev (v: [T], aktus: blokk (T)) (legyen i = std :: vec :: len (v); while i> 0u (i - = 1u; act (v [i]);)) típus circular_buf = (kezdete: uint, vége: uint, buf:);

A nyelv támogatja az ún címkéket... Ez nem más, mint egy unió a C-ből, egy további mezővel - a használt változat kódjával (vagyis valami közös az unió és a felsorolás között). Vagy elméletileg egy algebrai adattípus.

Címke alakja (kör (pont, lebegés); téglalap (pont, pont);)

A legegyszerűbb esetben a címke megegyezik a felsorolással:

Tag állat (kutya; macska;) legyen a: állat = kutya; a = macska;
Bonyolultabb esetekben a „felsorolás” minden eleme önálló szerkezet, saját „konstruktorral”.
Egy másik érdekes példa egy rekurzív struktúra, amely egy "lista" típusú objektumot határoz meg:
címke lista (nulla; hátrányok (T, @list ); ) legyen a: lista = cons (10, @cons (12, @nil));
A címkék részt vehetnek a mintaillesztési kifejezésekben, amelyek meglehetősen összetettek lehetnek.
alt x (cons (a, @cons (b, _)) (process_pair (a, b);) cons (10, _) (process_ten ();) _ (hiba;))

Mintaillesztés

Kezdetben az illesztési mintát egy továbbfejlesztett kapcsolónak tekintheti. Az alt kulcsszót használjuk, ezt követi az elemzett kifejezés, majd az operátor törzsében - minták és cselekvések, ha egybeesik a mintákkal.
alt my_number (0 (std :: io :: println ("nulla");) 1 | 2 (std :: io :: println ("egy vagy kettő");) 3-tól 10-ig (std :: io :: println ("háromtól tízig");) _ (std :: io :: println ("valami más");))
Mint "minta" nem csak konstansokat (mint a C-ben), hanem összetettebb kifejezéseket is használhat - változók, sorok, tartományok, típusok, helyőrzők ("_"). További feltételeket írhat a mintát közvetlenül követő when záradékkal. Az operátornak létezik egy speciális változata a típusillesztéshez. Ez azért lehetséges, mert a nyelvnek van egy univerzális változattípusa. Bármi amelynek objektumai bármilyen típusú értéket tartalmazhatnak.

Mutatók. Az általános mutatók mellett a Rust támogatja a speciális intelligens mutatókat beépített referenciaszámlálóval - Megosztott dobozok és egyedi dobozok. Némileg hasonlóak a C ++-ból származó shared_ptr és egyedi_ptr-hez. Saját szintaxisuk van: @ a megosztott és ~ az egyedi. Az egyedi mutatók esetében a másolás helyett egy speciális művelet van - mozgassa:
legyen x = ~ 10; hadd y<- x;
egy ilyen mozgás után az x mutató inicializálása megtörténik.

Lezárások, részleges alkalmazás, iterátorok

A funkcionális programozás ezen a ponton kezdődik. A Rust teljes mértékben támogatja a magasabb rendű függvények koncepcióját – vagyis azokat a függvényeket, amelyek argumentumként vehetnek fel, és más függvényeket is visszaadhatnak.

1. Kulcsszó lambda beágyazott függvény vagy funkcionális adattípus deklarálására szolgál.

Fn make_plus_function (x: int) -> lambda (int) -> int (lambda (y: int) -> int (x + y)) legyen plusz_two = make_plus_function (2); állítás plusz_kettő (3) == 5;

Ebben a példában van egy make_plus_függvény, amely egy int típusú "x" argumentumot vesz fel, és egy "int-> int" típusú függvényt ad vissza (ahol a lambda egy kulcsszó). A függvény törzse pontosan ezt a funkciót írja le. A "return" operátor hiánya kissé zavaró, azonban az FP-nél ez általános dolog.

2. Kulcsszó Blokk egy funkcionális típus deklarálására szolgál - egy függvény argumentum, amelyet helyettesíthet valami hasonlóval, mint egy normál kód blokkja.
fn map_int (f: blokk (int) -> int, vec:) -> (legyen eredmény =; for i in vec (eredmény + =;) ret result;) map_int ((| x | x + 1),);

Itt van egy függvény, aminek a bemenete egy blokk - valójában egy "int-> int" típusú lambda függvény, és egy int típusú vektor (a vektorok szintaxisáról később). Maga a "blokk" a hívó kódban egy kissé szokatlan szintaxissal van írva (| x | x + 1). Személy szerint nekem jobban tetszik a C # lambdas, a | makacsul bitenkénti VAGY-nak (ami egyébként a Rustban is benne van, mint az összes jó öreg C-művelet).

3. A részleges alkalmazás egy függvény létrehozása egy másik függvény alapján, nagyszámú argumentummal, ennek a másik függvénynek néhány argumentuma értékének megadásával. A kulcsszót erre használják. kötniés a "_" helyőrző:

Legyen daynum = bind std :: vec :: position (_, ["mo", "tu", "we", "do", "fr", "sa", "su"])

Az érthetőség kedvéért rögtön leszögezem, hogy ez egyszerű C-ben is megtehető egy egyszerű wrapper létrehozásával, valami ilyesmi:
const char * daynum (int i) (const char * s = ("mo", "tu", "we", "do", "fr", "sa", "su"); return s [i]; )

De a részleges alkalmazás egy funkcionális stílus, nem pedig eljárási stílus (mellesleg a fenti példából nem derül ki, hogyan készítsünk részleges alkalmazást, hogy argumentum nélküli függvényt kapjunk)

Egy másik példa: az add függvény két int argumentummal van deklarálva, és egy int-et ad vissza. Ezután deklarálják a single_param_fn funkcionális típust, amelynek egy int argumentuma van, és egy int értéket ad vissza. A bind használatával két függvényobjektum, az add4 és az add5 deklarálva van, a részleges argumentumokkal rendelkező add függvényre építve.

Fn add (x: int, y: int) -> int (ret x + y;) type single_param_fn = fn (int) -> int; legyen add4: single_param_fn = bind add (4, _); legyen add5: single_param_fn = bind add (_, 5);

A funkcionális objektumok ugyanúgy hívhatók, mint a normál függvények.
assert (add (4,5) == add4 (5)); assert (add (4,5) == add5 (4));

4. Tiszta függvények és predikátumok
A tiszta függvények olyan függvények, amelyeknek nincs mellékhatása (beleértve azokat is, amelyek nem hívnak meg más függvényeket, mint a tiszta függvényeket). Az ilyen funkciókat a tiszta kulcsszó különbözteti meg.
pure fn lt_42 (x: int) -> bool (ret (x< 42); }
A predikátumok tiszta függvények, amelyek bool-típust adnak vissza. Az ilyen függvények a Typestate rendszerben használhatók (lásd alább), azaz fordításkor meghívhatók különféle statikus ellenőrzésekre.

Szintaxis makrók
Tervezett funkció, de nagyon hasznos. Rustban még a fejlesztés korai szakaszában van.
std :: io :: println (#fmt ("% s% d", "a válasz", 42));
A printf-hez hasonló kifejezés, de fordításkor hajtják végre (ennek megfelelően minden argumentumhibát a fordításkor észlel a rendszer). Sajnos nagyon kevés anyag található a szintaktikai makrókról, és ezek maguk is fejlesztés alatt állnak, de van remény, hogy valami olyan lesz, mint a Nemerle makrók.
Mellesleg, ugyanazzal a Nemerlével ellentétben, szerintem nagyon kompetens az a döntés, hogy a makrókat szintaktikailag kiemeljük a # szimbólum használatával: a makró egy olyan entitás, amely nagyon különbözik egy függvénytől, és fontosnak tartom, hogy egy pillantással lássuk, hol függvényeket hívják meg a kódban, és ahol - makrókat.

Attribútumok

A C # attribútumokhoz hasonló fogalom (és még hasonló szintaxissal is). Külön köszönet ezért a fejlesztőknek. Ahogy az várható is volt, az attribútumok metainformációt adnak az általuk jegyzett entitáshoz.
# fn register_win_service () (/ * ... * /)
Az attribútum szintaxisának egy másik változatát találták ki - ugyanaz a sor, de pontosvesszővel a végén, az aktuális környezetet jegyzi meg. Vagyis bármi, ami megfelel az ilyen attribútumot körülvevő legközelebbi göndör kapcsos zárójelnek.
fn register_win_service () (#; / * ... * /)

Párhuzamos számítástechnika

Talán a nyelv egyik legérdekesebb része. Ugyanakkor a tutorialban jelenleg egyáltalán nincs leírva :)
A Rust program egy „feladatfából” áll. Minden feladatnak van egy beviteli funkciója, saját verem, más feladatokkal való interakció eszközei - csatornák a kimenő információkhoz és portok a bejövő számára, és birtokolják a dinamikus kupacban lévő objektumok egy részét.
Sok Rust-feladat létezhet egyetlen operációs rendszer folyamatán belül. A rozsdás feladatok "könnyűek": minden feladat kevesebb memóriát fogyaszt, mint egy operációs rendszer folyamata, és a közöttük való váltás gyorsabb, mint az operációs rendszer folyamatai közötti váltás (ez valószínűleg "szálakat" jelent).

A feladat legalább egy függvényből áll, argumentumok nélkül. A feladat elindítása a spawn funkció segítségével történik. Minden feladatnak lehetnek csatornái, amelyeken keresztül információkat közöl a többi feladattal. A csatorna egy speciális sablon típusú chan, amelyet a csatorna adattípusa paraméterez. Például a chan egy előjel nélküli bájtok átvitelére szolgáló csatorna.
Csatornára küldéshez használja a send függvényt, melynek első argumentuma a csatorna, a második pedig az elküldendő érték. Valójában ez a függvény az értéket a csatorna belső pufferébe helyezi.
A portok az adatok fogadására szolgálnak. A port egy sablonos porttípus, amelyet a port adattípusa paraméterez: a port az előjel nélküli bájtok fogadására szolgáló port.
A portokról való olvasáshoz a recv függvényt használjuk, melynek argumentuma a port, a visszatérési értéke pedig a portról származó adatok. Az olvasás blokkolja a feladatot, azaz. ha a port üres, a feladat függő állapotba kerül mindaddig, amíg egy másik feladat nem küld adatokat a porthoz társított csatornán.
A csatornák portokhoz kötése nagyon egyszerű - a csatorna inicializálásával egy porttal a chan kulcsszó használatával:
let reqport = port ();
legyen reqchan = chan (reqport);
Egy porthoz több csatorna is csatlakoztatható, de fordítva nem – egy csatorna nem csatlakoztatható egyszerre több porthoz.

Typestate

A „typestate” fogalmának nem találtam oroszra általánosan elfogadott fordítását, ezért „típusállapotoknak” fogom hívni. Ennek a funkciónak az a lényege, hogy a statikus gépelésben elfogadott szokásos típusellenőrzésen túl további kontextus-ellenőrzések is lehetségesek a fordítási szakaszban.
A típusok állapotát ilyen vagy olyan formában minden programozó ismeri - a fordító üzenetei szerint "a változó inicializálás nélkül használatos". A fordító meghatározza azokat a helyeket, ahol egy soha nem írt változót használnak olvasásra, és figyelmeztetést ad. Általánosabban ez az ötlet így néz ki: minden objektumnak van egy halmaza állapota, amelyet fel tud venni. Minden állapotban érvényes és érvénytelen műveletek vannak megadva ehhez az objektumhoz. A fordító pedig le tudja ellenőrizni, hogy egy objektumon adott művelet megengedett-e a program egy adott helyén. Fontos, hogy ezeket az ellenőrzéseket a fordításkor végezzék el.

Például, ha van egy "fájl" típusú objektumunk, akkor lehet "zárt" és "nyitott" állapota. A fájlból történő olvasási művelet pedig érvénytelen, ha a fájl be van zárva. A modern nyelvekben gyakori, hogy az olvasási függvény vagy kivételt dob, vagy hibakódot ad vissza. A típusállapot-rendszer a fordításkor észlelhet egy ilyen hibát – ahogy a fordító azt állapítja meg, hogy egy változó olvasási művelete minden lehetséges írási művelet előtt megtörténik, úgy meghatározhatja, hogy a „Read” metódus érvényes „fájl megnyitása” állapotban. , az "Open" metódus előtt kerül meghívásra, amely átviszi az objektumot ebbe az állapotba.

A Rustban létezik a „predikátumok” fogalma – olyan speciális függvények, amelyeknek nincs mellékhatásuk, és bool-típust adnak vissza. Az ilyen függvényeket a fordító felhasználhatja a fordítási időben meghívásra bizonyos feltételek statikus ellenőrzésére.

A megszorítások olyan speciális ellenőrzések, amelyeket fordításkor lehet végrehajtani. Ehhez a check kulcsszót használják.
tiszta fn_kisebb_mint (int a, int b) -< bool { ret a < b; } fn test() { let x: int = 10; let y: int = 20; check is_less_than(x,y); }
A függvények bemeneti paramétereire a predikátumokat a következő módon lehet "akasztani":
fn teszt (int x, int y): kisebb_ mint (x, y) (...)

A betűtípusról nagyon kevés információ áll rendelkezésre, így sok pont még tisztázatlan, de a koncepció mindenesetre érdekes.

Ez minden. Lehetséges, hogy kihagytam néhány érdekességet, de a cikk már akkor is dagadt volt. Ha akarja, most megépítheti a Rust fordítót, és megpróbálhat különféle példákkal játszani. Az összeszereléssel kapcsolatos információkat lásd



Ma a Rust szintaxist a vim és az emacs támogatja a fordítóhoz mellékelt szintaxisfájlok használatával.
Vannak szintaktikai csomagok is a népszerű szabadalmaztatott szerkesztőhöz Magasztos szöveg 2 és az ingyenes szerkesztő Kate. Az IDE-ben még nincs Rust támogatás. Úgy tűnik, a hibakereső támogatás is hiányzik.

A rustc fordítóhoz a következő segédprogramok tartoznak:
> rustdoc- segédprogram a dokumentáció automatikus generálásához forráskódból, mint például a Doxygen;
> rustpkg- csomagkezelő, amely lehetővé teszi további csomagok és könyvtárak egyszerű telepítését;
> rusti- az úgynevezett REPL segédprogram (read-eval-print-loop). Ez lényegében egy tesztértelmező, amely elfogadja a Rust kifejezést parancs sor, lefordítja LLVM belső reprezentációra, végrehajtja és kiadja az eredményt;
> rozsda- egy univerzális segédprogram, amely a paraméterektől függően elindít más segédprogramokat vagy a fordítót. Nekem sosem működött.

Az összes elérhető nyelvi dokumentáció a www.rust-lang.org hivatalos weboldalon található. Van részletes kézikönyv(http://static.rust-lang.org/doc/tutorial.html) - átfogó formális dokumentáció a szintaxis, memóriamodell, futásidejű rendszer stb. minden árnyalatáról, valamint a beépített központi könyvtár dokumentációja és a standard könyvtár std. Minden dokumentáció angol nyelvű. Nincsenek releváns orosz nyelvű anyagok, és néhány elérhető áttekintő cikk már nagyon elavulttá vált.

Ideológia és szintaxis


A Rust egy C-szerű nyelv, amely kapcsos zárójeleket használ a kódblokkok megjelölésére. A nyelv „többparadigma”, azaz. lehetővé teszi kód írását kötelező eljárási, objektumorientált, párhuzamos vagy funkcionális módon. A Rust natív binárisokra fordít minden támogatott platformon (az LLVM-et használja háttérként). Elméletileg a Rust kódnak olyan gyorsnak kell lennie, mint a C / C ++ kódnak. A Rust rendszernyelvként kerül forgalomba, de hiányzik belőle az összeállítási kód blokkjainak beépített támogatása, mint az "igazi" C, C ++ vagy D rendszernyelvekben.

A Rust memóriamodellje natívan nem engedélyezi a nulla vagy lógó mutatókat és a puffertúlcsordulást. Van egy opcionális szemétgyűjtő, amely csak egyetlen kódszálon belül működik. A nyelv beépített támogatja a könnyű multitasking és a szálak közötti üzenetküldést. A Rustban nem létezik megosztott memória. Minden változó fel van osztva veremváltozókra, egy adott szál kupacváltozóira, és úgynevezett "csere" kupacváltozókra, amelyeket minden szál elolvashat, de nem módosítható. Ez automatikusan kiküszöböli a holtpontokat, amelyeket a többszálú programozás csapásaként tartanak számon. A nyelv ABI-ja kompatibilis a C-vel, így a Rust programok további wrapperek nélkül tudnak kapcsolódni a C nyelven írt könyvtárakhoz. Az alacsony szintű rendszerprogramozás igényeihez és a C-vel való kompatibilitás biztosításához a nyelv speciális "nem biztonságos" móddal rendelkezik, a mutatók helyességének ellenőrzése nélkül. Ideológiáját tekintve a Rust áll a legközelebb a Go nyelvhez. A Go-hoz hasonlóan itt is a többszálas programozás egyszerűségén és a nagyméretű alkalmazások fejlesztésének gyorsaságán van a fő hangsúly, a szintaxis pedig éppoly szokatlan és helyenként némileg meglepő. Ugyanakkor a Rust nem olyan minimalista, mint a Go, és azt állítja, hogy rendszernyelv.

A Rust szintaxisát nagyrészt a C és a C ++ nyelvből kölcsönözték, néhány ötlettel a Go, C #, Haskell, Python és Ruby nyelvekből. Nem írom le kimerítően a nyelv szintaxisát, csak a legérdekesebb fogalmakra koncentrálok.

A rozsda egyre népszerűbb, de sokan még mindig nem értik értékét és funkcióját. Beszélni fogunk a Rust programozási nyelv fő előnyeiről.

Mi a közös Rustban és más nyelvekben?

Nehéz elhinni a felsorolt ​​definíciókban, irreális állításnak tűnik, mivel korábban minden nyelv választotta az egyik oldalt: a megbízhatóságot vagy a teljesítményt.

A nagy sebesség feltűnő képviselője, de mindannyian tudjuk, milyen gyakran fordulnak elő hibák a lefoglalt memóriához, távoli szerverekhez való nem megfelelő hozzáférés miatt, és nincs mit mondani a kiszámíthatatlan eredményekről. A többszörös felvételi folyam miatt gyakran nehéz megjósolni az eredményt.

A megbízhatóság iránti elfogultság a legjobban demonstrálja a nyelvet Haskell amely a természetben van összeállítva és magas biztonsági teljesítményt nyújt. Bármi, amit össze lehet fordítani, jól működik. A fő hátrány- ez alacsony teljesítmény, nehéz elképzelni olyan projektet, amely nagy sebességet igényel Haskell.

Egy semleges pozíció, egy bizonyos egyensúly és a többi. Bennük az elfogultság a gyakorlatiasságba kerül.

Rozsda felszívta a legjobb tulajdonságokat C ++és Haskell, és képes volt megőrizni kellő gyakorlatiasságát és funkcionalitását más versenytársakkal szemben.

Miben rejlik a rozsda nyelv szépsége?

A Rust varázslatos tulajdonságait a fordítási alapok és a tulajdonosi entitás információi teszik elérhetővé ( tulajdonos), egy programozóról, aki csak ideiglenesen hibakeres vagy kölcsönöz egy projektet ( változtatható kölcsön), valamint egy hétköznapi nézőről ( megváltoztathatatlan kölcsön).

Beprogramozáskor Jáva vagy C ++, ezeket az információkat a memóriában kell tartania, bár az adatok típusa némileg eltérő. V Rozsda ezt nyelvi konstrukciók segítségével valósítják meg, ez az információ megkönnyíti a fordító számára az azonosság megállapítását és a viselkedési modell kiválasztásának helyességét. A fordító segíthet abban, hogy a lehetséges és gyakori problémákat kiküszöböljük a kódvégrehajtás során.

Ez a nyelv egy kicsit más megközelítést igényel. A furcsaság ellenére az algoritmus meglehetősen nyilvánvaló és hatékony. Most a nyelv alapjairól döntünk, amelyek zsákutcához vezethetnek a tanulmány elején:

  1. Az öröklődési rendszert teljesen megszüntették, speciális struktúrát és képességeket használnak a helyettesítéshez, több részletre jellemző tulajdonságokat.
  2. A mutatók kizárólag olyan kódban vannak jelen, amelyre nem vonatkozik további védelem, vagyis a nem biztonságos () függvényen belül. A biztonságos kódban való helyettesítéshez hivatkozásokat használnak annak biztosítására, hogy a meglévő objektumokra megfelelően mutassanak.
  3. Ha a hivatkozás statikus, és egy adott elemhez vezet, például: immutable borrow = & Object, amíg a hivatkozás meg nem hal, azt egyetlen felhasználó sem módosíthatja.
  4. A mutable borrow = & mut Object mutable link esetén a hivatkozás teljes élettartama alatt nem olvashatja el a tartalmat más felhasználónak.
  5. A fejlesztők a Mac és * nix platformokra összpontosítanak, ezért dolgoznak a rendszeren ablakok csak a GNU környezet használatával lehetséges.

A célközönség meglehetősen fontos, a rusztnyelvnek van kellő aktív közössége, fejlett kommunikációs és képzési rendszere. Javasoljuk, hogy látogassa meg az IRC csatornát vagy a Reddit. A mai napig megírták már, és többségük még mindig folyamatosan fejlődik, projektjeik a GitHubon megtalálhatók.

A nyelv legnagyobb népszerűsége a fejlesztők körében ismert, akik a grafika és a játékok létrehozásának útját választották. Vannak még fejlesztések egy teljes értékű operációs rendszer létrehozására is, de ezek fejlesztése még folyamatban van. Rövid távon lehetőség nyílik kliens programok és webszerverek írására. Mindezek a feladatok a Rust hatáskörébe tartoznak.

A fő, és valószínűleg az egyetlen hátránya a túlságosan aktív fejlesztés. Az új verziók megjelenésével a szintaxis némileg módosul, időszakonként szükségessé válik a viselkedés és a fejlődés logikájának megváltoztatása, hogy alkalmazkodni tudjunk a felmerülő lehetőségekhez. A helyzet a Rust-1.0 megjelenéséig egy ideig folytatódni fog.

Az állandó címsor " Ezen a héten Rustban", Amely megtalálható a Rust" n Stuffs-ban a linken. Mindig van információ a korábbi és múltbeli változásokról, valamint a nyelv fejlődési kilátásairól.


Nagyon tetszett a A rozsdanyelv kritikája és a Miért nem hal meg a C / C ++ című cikk. Azt javasoltuk a szerzőnek, hogy fordítsuk le a cikket angolra és tegyük közzé a blogunkon. Beleegyezett, és örömmel mutatjuk be ezt a cikket orosz és angol nyelv... Az eredeti cikk itt található.

Az eredeti cikk felkerült (szöveg oroszul). A cikk a szerző beleegyezésével megjelent blogunkon.

Megjegyzés: Az alábbiakban azt feltételezem, hogy a Rust egy kísérlet egy gyors és biztonságos nyelv létrehozására. Végül is a Mozilla srácai böngészőmotor-fejlesztő eszközként készítették el. Ha ez csak egy másik biztonságos nyelv, akkor furcsa leszünk. Már van egy fillér tucatnyi különféle biztonságos nyelv, mindenki megtalálja a kedvére valót. És ha nem a C ++ lecserélése a cél, akkor (1) miért készül a nem biztonságos részhalmaz a nyelvben? (2) miért volt kényelmes eltávolítani a könnyű adatfolyamokat a nyelvből? Más szóval, ebben az esetben annak, ami történik, egyáltalán nincs értelme.

Ha hirtelen elolvassa a linux.org.ru fórumot, megjegyzem, hogy ez nem az ebben a szálban tárgyalt 10 pusztán technikai okok listája, amelyek miatt nem tetszik Rust. Ahogy a Skype beszélgetés kedves @ sum3rman elvtárs Nem egy vélemény létezik arról, hogy ezek az okok mennyire "technikaiak". Általában készítettem egy fügelistát, de néhány pontot, ami talán a legérdekesebb, mégis megkockáztatom, hogy idézzem. Valójában elég egyszerű, nem technikai okai vannak a szemnek.

Az, hogy a C / C ++ belátható időn belül nem megy sehova, minden józanul gondolkodó ember számára világos. Senki nem írja át szinte az összes asztali alkalmazást, kernelt operációs rendszer, fordítók, játék- és böngészőmotorok, virtuális gépek, adatbázisok, archiválók, audio- és videokodekek, rengeteg egyéb rendszerkönyvtár és így tovább. Ez egy csomó gyors, hibakereső, időtálló kód. Újraírni nagyon-nagyon drága, kockázatos, és őszintén szólva, csak a legmakacsabb Rust "Omán eltorzult elméjében van értelme. A C / C ++ programozók iránti kereslet nagy volt és lesz is egy nagyon hosszú idő.

Oké, mit szólnál a Rust használatához új kód írásakor?

Ne felejtsük el, hogy nem ez az első próbálkozás a C / C ++ "helyesebbé tételére". Vegyük a D nyelvet, 2001-ben jelent meg, nagyon jó nyelv. Nincsenek betöltetlen állások, nincsenek normális fejlesztési eszközök, vagy különösebben kiemelkedő sikertörténetek. Az OpenMW projekt eredetileg D-ben íródott, majd hirtelen úgy döntöttek, hogy teljesen átírják C ++-ban. Ahogy a fejlesztők bevallják, rengeteg levelet kaptak "nagyszerű projekt, szívesen hozzájárulnánk hozzá, de ezt a hülye D-t nem ismerjük és nem is akarjuk tudni". A Wikipédia arról számol be, hogy D mellett sok más kísérlet is történt a C ++ megölésére, ilyen vagy olyan mértékben, például Vala, Cyclone, Limbo, BitC. Hányan hallottak még ilyen nyelvekről?

Azt hiszem, itt az ideje, hogy tanuljunk a történelemből. Egyetlen épeszű ember sem fog egy új nyelvet belerángatni egy projektbe, amíg legalább nem mutatsz meg neki normális fejlesztőeszközöket, nem mondasz el pár sikersztorit és nem mutatsz meg egy tucat, a közelben élő programozót ezen a nyelven. A programozók talán – a legfiatalabbakat kivéve – soha nem pazarolják idejüket és egészségüket a következő leghelyesebb nyelv megtanulására, amíg meg nem mutatod nekik a normál fejlesztőeszközöket (nem olyan kézműveseket, mint a Racer), néhány tízezer kész könyvtárat (nem „kísérleti”, „instabil” és így tovább), ne meséljen el néhány sikersztorit, és mutasson meg egy tucat üres állást a városukban. A csirke és a tojás probléma. Nagyon ritkán sikerül sikeresen megoldani ezt a problémát (feltételesen, itt a Scalát említhetjük példaként), elsősorban valamilyen nagy cég (Google, Typesafe) idő- és pénzbefektetése miatt, valamilyen okból érdekelt a nyelv népszerűsítése.

Amint már megjegyeztem, a nem technikai okok önmagukban több mint elegendőek. Azonban pusztán kíváncsiságból próbáljuk meg egy pillanatra elképzelni, hogy nincsenek ott. Akkor nincs ok arra, hogy ne írjon Rozsdába? Kiderült, hogy ez is legalább egy nagyon nagy kérdés.

A C / C ++-t különböző dolgok miatt kritizálják. Egyébként nagyon gyakran kifogásolják azok, akik még távolról sem látták a C ++ kódot gyártásban. A probléma röviden és egyértelműen a következőképpen írható le: A C ++ nagyon gyors (és nem igényel memóriát, akkumulátort stb.), de nem biztonságos abban az értelemben, hogy lehetővé teszi, hogy túllépjen a tömbök határain. , tévedésből hozzáfér a felszabadult memóriadarabokhoz, és így tovább. Egy időben ez a probléma biztonságos nyelvek tömegének megjelenéséhez vezetett, mint például a Java, a C #, a Python és mások. De kiderült, hogy ezek a nyelvek a C ++-hoz képest túlságosan erőforrásigényesek és más hátrányaik is vannak, emlékezzen legalább a világ elkerülhetetlen megállítására a szemétgyűjtés során. Ezért az emberek azért küzdenek, hogy a nyelvet olyan gyorssá tegyék, mint a C ++, de egyben biztonságosak is. Az egyik ilyen nyelv a Rust.

A rozsda valóban biztonságos, de sajnos messze nem gyors. Az írás idején a sebességet tekintve a Rust a Java, a Go és a Haskellhez hasonlítható:

Őszintén remélem, hogy idővel valahogy túlhajtják, de addig a sebesség és a biztonság kompromisszumát tekintve nem sokkal érdekesebb, mint a Scala vagy a Go. Mostanáig az a kérdés, hogy egyáltalán lehetséges-e egy nyelvet gyorssá és biztonságossá tenni, vagy a tömb határokon kívüli állandó ellenőrzése, a C könyvtárak kötései körüli biztonságos kötés stb. C ++.

Hogyan biztonságos a Rust? Egyszerűen fogalmazva, ez egy beépített statikus kódelemzővel rendelkező nyelv. Egy igazán klassz statikus analizátor, ami minden C ++-ra jellemző hibát kifog, ráadásul nem csak a memóriakezeléssel kapcsolatosakat, hanem a többszálúságot is. A mutálható objektum linkjét átadtam egy másik szálnak a csatornán keresztül, majd megpróbáltam magam használni ezt a hivatkozást - ez minden, nem fog lefordítani. Ez nagyon király.

Gyakran érvelnek amellett, hogy az esetek 90%-ában a kódnak csak 10%-a fut le (ami, ahogy én megértem, pusztán ökölszabály – nem találtak gyors kutatást ebben a témában). Ezért a program nagy része biztonságos Rustban írható, a hot code 10%-a pedig nem biztonságos részhalmazba, és a jelenlegi Rust implementáció lassúsága nem igazán okoz gondot. Ok, de aztán kiderül, hogy a Rust egyáltalán nem kell, mert Go-ban a kód 90%-át, C-ben 10%-át tudom írni. Csak az ezüstgolyókat keresők és a valóságtól elszakadt eretnekek fogják használni a Rustot kizárólag azon az alapon, hogy a program 100%-a egy nyelven írható. Bár a valóságban ez egyazon nyelv két dialektusa, ami nem sokban különbözik egy csomó Java plusz C vagy Go plus C nyelvtől.

Valójában a 10:90-es szabály még mindig hazugság. Ezt a logikát követve a WebKit 90%-át, a VirtualBox 90%-át vagy a GCC 90%-át átírhatja Java nyelven, és ugyanazt az eredményt kapja. Ez nyilvánvalóan nem így van. Még ha nem is az a lényeg, hogy számos műsorban ez a hozzáállás nagyon eltérő, akkor is figyeljen a kezére. Tegyük fel, hogy a teljes program nem biztonságos C / C ++ nyelven íródott, és a végrehajtási ideje viszonylagosan 0,9 * 1 (a gyorskód kis része) + 0,1 * 1 (sok hideg kód) = 1. Hasonlítsunk össze egy biztonságos nyelvű programmal, ahol Si-ben vannak beillesztések: 0,9 * 1 + 0,1 * 2 = 1,1, hagyományosan a különbség 10%-a. Sok vagy kevés? Méretétől függ. A Google esetében már néhány százalék is dollármilliókat takaríthat meg (lásd az újság 5. bekezdését, „Használat”). Vagy képzelje el, hogy a következő frissítéssel a JVM hirtelen 10%-kal több erőforrást igényel! Még csak sejteni is félek, hány nulla lesz a kamat amerikai pénzre utalása után kapott számban! 10% dofig olyan feladatokban, ahol C és C ++ használatos.

Mantraként ismételgetjük: „Az idő előtti optimalizálás minden rossz gyökere”. De szó szerint, használjuk a buborékos rendezést mindenhol a gyorsrendezés helyett. Nem tudjuk biztosan, hogy ezen a helyen pontosan lelassul a program! Mi értelme van egyes akciók közönséges számlálóit szereplőkbe vagy tranzakciós memóriába csomagolni, ha azonnal használható egy hatékonyabb atom? Általánosságban elmondható, hogy triviális esetekben nincs értelme az all-all-all változók erőltetett inicializálásának, egy csomó további ellenőrzésnek és így tovább. A végén ne 10%-os gyorsulást kapjunk, hanem 2-5%-ot. Ez sem rossz, ha csak pár percnyi plusz gondolkodást igényel. És amint azt már megtudtuk, a C / C ++-ban megoldott feladatokban ez nagy különbség lehet! Aztán ki mondta, hogy könnyebb megtalálni a hot spotot, átírni a kódot (esetleg sok kódot) és bebizonyítani, hogy valóban gyorsabb, mint előre gondolkodni a teljesítményről?

A sebesség és a biztonság közötti kompromisszum mellett magával a nyelv kialakításával kapcsolatban is vannak kérdéseim. Különösen az öt típusú mutató tekintetében. Egyrészt nem rossz, ha a programozó végiggondolja, hogy hol vannak a változók, a veremen vagy a kupon, és lehet, hogy egyszerre több szál is működik velük, vagy nem. De másrészt képzeld el, hogy programot írsz, és kiderült, hogy a változónak nem a veremben kell élnie, hanem a kupacban. Mindent átír a Box használatára. Ezért megérti, hogy valóban szüksége van Rc-re vagy Arc-re. Írd újra. Aztán újra felülírod egy közönséges változóval a veremben. Mindez - normál IDE nélkül. És az alapszakasz nem segít. Nos, vagy csak a „Vec >>> "hello, Java! De a legszomorúbb az, hogy a fordító már tud az összes változó élettartamáról, képes lenne automatikusan megjeleníteni ezeket a Boxokat, Arc-okat stb. De valamiért ez a munkarész megmaradt A programozónak sokkal kényelmesebb lenne, ha „val”-t írnánk (a harmadik évezredben!), és ahol szükséges, kifejezetten jelezzük, hogy Box vagy R. A Rust fejlesztői ebben az értelemben elrontották az egész ötletet.

Emiatt különösen a Rust hatóköre jelentősen szűkül. Józan eszével senki sem írna webes és szerveroldalt ilyen nyelven. Különösen figyelembe véve, hogy a JVM alatt nem nyújt jelentős előnyöket ugyanazokkal a nyelvekkel szemben. És a Go with normál könnyű szálak (nem határidős) sokkal vonzóbbnak tűnik ezekhez a feladatokhoz. A határidős ügyleteknél, hogy ne lődd lábon magad, még meg kell tanulnod dolgozni, és azt mondod, hogy "biztonságos nyelv". Igen, ezeknek a nyelveknek megvannak a sajátosságai, ugyanúgy megállják a világot, de ez a probléma megoldható mind mikroszolgáltatásokba fűrészeléssel, mind más módszerekkel. És igen, senki sem fogja lefordítani a Rust-ot JavaScriptre, nem ír szkripteket az AWS-ben való elrendezéshez, és nem fogja használni a MongoDB lekérdezési nyelveként. Androidra is aligha fognak írni, de más okból - sokkal több architektúra létezik, a JVM-mel sokkal egyszerűbb. Ha hirtelen azt gondolta, hogy Rust „minden feladatra alkalmas”, csalódnom kell.

Nos, a kupachoz:

  • Makrók, a normál kivételek hiánya okozta túlzott bőbeszédűség tartalékaként. A metaprogramozás problémáiról már írtam, főleg nem valószínű, hogy normális IDE-t látunk a Rusthoz emiatt. És nem vagyok benne biztos, de úgy tűnik, hogy a Rust makróinak nincs is névterük.
  • Az emberek idióták, és a rakomány erősen ösztönzi a csomagok közvetlenül a git-tárolókból való kivonását, megkerülve a Crates.io-t. Emiatt nagyon valószínű, hogy ugyanazt a kavarodást kapod a csomagokkal, mint az Erlang világában a Rabarjával. Egyébként a Go világában, úgy tűnik, ugyanaz a helyzet.
  • Sok új nyelvhez hasonlóan a Rust is az egyszerűsítés útját követi. Általában megértem, hogy miért nincs benne normális öröklődés és kivételek, de maga a tény, hogy valaki ilyeneket dönt helyettem, kellemetlen utóízt hagy maga után. A C ++ nem korlátozza a programozót abban, hogy mit használhat és mit nem.
  • Ha az egyszerűsítés útját követnénk, akkor ki kellene dobnunk a nyelv összes ilyen kiterjesztését. Különben kiderül, mint Haskell világában, minden programozó a saját nyelvjárásában ír.
  • Az intelligens mutatók, ha vannak, messze nem ingyenesek, és nem vezetnek kiszámítható szemétszállítási időhöz. Egyes szálak hirtelen kiváltságosakká válnak egy nagyon mély adatstruktúra felszabadítására. Miközben a halott linkek útvesztőjében sétál, a tőle függő szálak türelmesen eltompulnak. Ugyanez a probléma Erlangban is fennáll a kis kupacokkal, magam is megfigyeltem nem egyszer. Az intelligens mutatóknak saját problémáik vannak, ugyanaz a memória töredezettség és szivárgás. Elfelejtettem a wikpointert a ciklikus szerkezetben, ennyi. És ez olyan nyelven van, amely biztonságosnak vallja magát. Ha kiszámítható GC-időt szeretne, vagy tanulmányozza az alkalmazás viselkedését terhelés alatt, és tegyen lépéseket (emlékezzen legalább ugyanazokra az objektumkészletekre), ha a GC-idő nem felel meg Önnek, vagy manuálisan kezelje a memóriát.
  • Látott valaki szigorú leírást a Rust szemantikáról? Neki legalább van memóriamodellje? Szintén számomra egy "biztonságos" nyelv, amely "bizonyítja" a programok helyességét, ami valóban képes értelmezni tíz forráskódját. különböző utak, ha!
  • Nem tudlak nem emlékeztetni erre a probléma szinte mindig az emberekben van, nem a technológiában... Ha rossz C ++ vagy Java kódot kapsz, ami hirtelen lelassul, az nem azért van, mert rossz a technológia, hanem azért, mert nem tanultad meg helyesen használni. Ön is elégedetlen lesz Rusttal, de más okok miatt. Nem egyszerűbb megtanulni a népszerűbb eszközök használatát, és elkezdeni megszeretni őket?

Általánosságban elmondható, hogy a következő 5 évben jobban fogom az időmet a C / C ++ tanulásába fektetni, mint a Rust. C ++ - ez egy ipari szabvány... Ezen a nyelven több mint 30 éve sikeresen megoldottak különféle problémákat. A Rust és a hozzá hasonlók pedig felfoghatatlan játékok homályos jövővel. Legalább a 2000-es évek óta beszélnek a C ++ közelgő haláláról, de ez idő alatt nem kevesebbet írtak C / C ++ nyelven. Inkább az ellenkezője igaz. És azt látjuk, hogy a nyelv fejlődik (C ++ 11, C ++ 14), új eszközök jelennek meg hozzá (ne feledjük, legalább a CLion és a Clang), és csak egy rakás megfelelő üresedés van.

Egy C ++ programozó mindig könnyen talál munkát több mint tisztességes fizetéssel, és ha szükséges, gyorsan át is képezheti Rustot. Ennek ellenkezője nagyon-nagyon kétséges. Amúgy a nyelv, ha van egyáltalán, messze nem az egyetlen és nem is döntő tényező az új munkahely kiválasztásánál. Ezen kívül egy tapasztalt C / C ++ programozó könnyen beleáshat PostgreSQL forrás- vagy Linux kernelekbe, hatékony modern fejlesztőeszközöket használhat, és számos könyv és cikk is rendelkezésére áll (mondjuk az OpenGL-ről).

Takarítson meg időt és egészséget, nincs belőlük annyi, mint amilyennek látszik!

A Rust folyamatosan fejlődik, minden kiadásnál 6 hetente új funkciókat és javításokat vezetnek be. Az ismert hibákat is azonnal kijavítják a szabálytalan kisebb kiadásoknál. Néha a fejlődés ilyen dinamikája akár akadályt is jelenthet: sok „élő” könyvtár ezt megköveteli új verzió fordítóprogramot, de nem minden cég tudja gyorsan frissíteni a projektjein.

Míg a Rust körüli infrastruktúra fejlődik, még mindig nyers. Sok könyvtár, bár már meglehetősen stabilan működik, még mindig kisebb fejlesztéseket igényel a valós használat során. Ha készen áll az ilyen könyvtárak elágazására a GitHubon, és enyhén módosítani az igényeinek megfelelően, akkor szerintem nem lehet különösebb problémája a Rust használatával a termelési projektekben.

Amennyire én tudom, még nincs egyetlen bevált gyakorlatok gyűjteménye a Rust használatához. Számos hasznos tipp található a hivatalos dokumentációban (az ún. Könyvekben), valamint különféle cikkekben elszórva. Vannak azonban olyan hasznos cikkek listái, amelyek segítenek megtalálni közöttük a megfelelőt. Például ezeket:
https://github.com/ctjhoa/rust-learning
https: //github.com/brson/rust-anthology/blob/maste ...

A rozsdát új projektekben használják, és eddig a tendencia a terjeszkedés. Ezen az oldalon megtekintheti, hogy mely cégek használják most a Rustot és mire: https://www.rust-lang.org/en-US/friends.html

Tehát, ha a Rust termelésben való használatát tervezi, készüljön fel erre:

  1. Elég magas küszöb a nyelvbe lépéshez. Itt nincs különösebb nehézség, csak a nyelv gyakorlására van szükség, és az első alkalommal követni kell a fordító tanácsát, hogyan lehet kiküszöbölni a folyamatosan előforduló fordítási hibákat.
  2. Elég gyakori fordítófrissítések, hogy új funkciókat adjunk a nyelvhez. Ez azt okozhatja, hogy a szükséges könyvtárnak a fordító friss verziójára lesz szüksége.
  3. Nyirkos könyvtárak. Valószínűleg neked kell egy kicsit módosítanod rajtuk.
  4. A rozsda leegyszerűsíti az összetettet, de bonyolítja az egyszerűt. Nagyon egyszerű projektekhez, amelyek nem igényelnek nagy teljesítményt és a jövőben jelentős fejlesztéseket, a Rust nem a legjobb választás.
De mit nyersz a Rust használatával?
  1. Nagy teljesítményű programok, automatikus memóriakezelés szemétgyűjtő nélkül.
  2. A programok nagy megbízhatósága és biztonsága, számos lehetséges probléma kiküszöbölése a fordítási szakaszban.
  3. A programok átalakítása és módosítása meglehetősen egyszerű és biztonságos folyamat a kifejlesztett típusrendszernek köszönhetően.
  4. Fejlett projektfüggőség-kezelő rendszer.
  5. Egy igazán jó sokoldalú eszköz: a Rust alkalmas prototípus-készítésre és fejlesztésre, valamint bármilyen típusú programhoz (segédprogramok, asztali alkalmazások, webes alkalmazások, mobil alkalmazások, beágyazott rendszerek). Még mindig nincs mindenre megfelelő támogatás, de a jövőre nézve ez nagy plusz.