Rust | |
---|---|
Sprog klasse | proceduremæssigt programmeringssprog , funktionelt programmeringssprog , multiparadigme programmeringssprog , imperativt programmeringssprog , systemprogrammeringssprog [d] , gratis og open source software , kompileret programmeringssprog og programmeringssprog |
Dukkede op i | 2006 [1] [5] |
Forfatter | Graydon Choir [d] |
Udvikler | Mozilla [1] , Graydon Hore [d] [1] [2] og Rust Foundation [d] [3] |
Filtypenavn _ | .rs |
Frigøre |
|
Blev påvirket | Alef [d] [6],C++[7],C#[7],Cyclone[7],Erlang[7],Haskell[7],Limbo[7], Newsqueak [d] ,OCaml[7],Ruby[ 7],Scheme[7],SML[7]ogSwift[7] |
Licens | Apache-licens 2.0 [8] [9] og MIT-licens [8] [9] |
Internet side | rust-lang.org _ |
OS | på tværs af platforme |
Mediefiler på Wikimedia Commons |
Rust (Rust, [ rʌst ]; rust fra engelsk - "rust") er et multiparadigme - kompileret programmeringssprog, der kombinerer funktionelle og proceduremæssige programmeringsparadigmer med et objektsystem baseret på træk . Hukommelsesstyring udføres gennem mekanismen "ejerskab" ved hjælp af affine typer [10] , som giver dig mulighed for at undvære skraldeopsamlingssystemet under programafvikling. Rust garanterer hukommelsessikkerhed med compilerens indbyggede statiske referencetjek ( lånetjek ). Der er værktøjer, der giver dig mulighed for at bruge teknikkerne til objektorienteret programmering [11] .
Nøglesprogprioriteter: Sikkerhed, hastighed og samtidighed . Rust er velegnet til systemprogrammering , især betragtes det som et lovende sprog til udvikling af operativsystemkerner [10] . Rust kan sammenlignes med C++ / C med hensyn til hastighed og funktioner , men giver mere sikkerhed, når man arbejder med hukommelse, hvilket leveres af referencekontrolmekanismerne indbygget i sproget. Udførelsen af Rust-programmer lettes ved brug af "nul-omkostningsabstraktioner" [12] .
Efter flere års aktiv udvikling blev den første stabile version (1.0) udgivet den 15. maj 2015, hvorefter nye versioner udgives hver 6. uge [13] . For sprogversioner udgivet efter 1.0 er bagudkompatibilitet erklæret [14] .
Udviklet siden 2010'erne af Mozilla Research og finansieret af Mozilla Foundation . Fra 2020 var det planlagt at overføre sprogets intellektuelle ejendomsret og udviklings- og finansieringsprocesser til Rust Foundation [15] . Den 8. februar 2021 annoncerede de fem stiftende virksomheder ( AWS , Huawei , Google , Microsoft og Mozilla ) officielt dannelsen af Rust Foundation. [16] [17]
I syv på hinanden følgende år fra 2016 til 2022 har Rust været nummer 1 på listen over "Mest elskede programmeringssprog" af den årlige Stack Overflow Developer Survey [18] [19] [20] [21] .
Arbejdet med sproget blev startet af Mozilla -medarbejder Graydon Hor i 2006. Forfatteren navngav projektet Rust, ifølge ham, forbundet med svampe af rustfamilien ( eng. rust fungi ) [22] .
I 2009 [23] begyndte Mozilla separat at sponsorere udviklingen af Rust. Et år senere blev sproget officielt præsenteret på Mozilla Summit 2010 [24] . Den originale compiler, implementeret i OCaml , er blevet erstattet med en ny skrevet i Rust og bruger LLVM til at generere maskinkode [25] ; året efter kompilerede den nye compiler sig selv for første gang [26] .
Den første officielle alfaversion af Rust (0.1) blev udgivet i januar 2012 [27] .
I april 2013 blev Servo lanceret , et eksperimentelt projekt af Mozilla for at udvikle en browsermotor i Rust. [28]
Den første stabile version af Rust (1.0) blev udgivet i maj 2015. Programmeringsgrænsefladerne og sprogfunktionerne har gennemgået en væsentlig revision, hvorefter kun helt klar-til-brug funktioner er tilbage som standard, hvis implementering ikke ændres i fremtiden. Alle andre funktioner overføres til kategorien eksperimentel og tages ud af leveringen som standard [29] .
Stærk statisk typning anvendes . Generisk programmering understøttes med understøttelse af parametrisk polymorfi , automatisk typeinferens er givet for lokale variabler (men ikke for funktionsparametre).
Implementeret understøttelse af enkelte datatyper — typer, der har præcis én instans og ikke optager hukommelsesplads, eksempler:
Implementerede tomme datatyper — typer, der ikke kan instansieres; implementeret som optegnede typer, der ikke har nogen muligheder: enum Void {}.
Alle datatyper i sproget er opdelt i to hovedgrupper: simple og standard bibliotekstyper.
Simple typer (typer med konstant længde indbygget i selve sproget) - numerisk, boolsk, tegn, matrix, udsnit, strengudsnit, tupel, reference, funktionsmarkør. Nogle af de simple typer er "maskine", det vil sige, at de implementeres direkte i moderne processorer , såsom numerisk, boolesk og karakter. Typer leveret af standardbiblioteket std(variabel længde): vektor, streng, hash-tabel og lignende.
Numeriske typer:
Boolean ( bool ): true, false.
Character ( char ): En type, der repræsenterer et Unicode-tegn (intern datarepræsentation som u32). Eksempelværdier: '₽', '\n', '\x7f', '\u{CA0}',
Funktionsmarkør ( funktionsmarkør ): Funktionsobjekter har en type bestemt af deres signatur, det vil sige parametre og returværdi. Eksempel:let f: fn(i32) -> i32 = plus_one;
En reference (delt lån - delt lån ) &T(delt, ikke mutable, ejer ikke en ressource), i stedet for at tage ejerskab af ressourcen, låner den den. Navne, der låner noget, frigiver ikke ressourcen, når de går uden for anvendelsesområdet. Derudover går ejernavnene i lånt tilstand.
En reference, der kan ændres (mutable borrow ) ( &mut Tejer ikke ressourcen). Giver dig mulighed for at ændre den ressource, der bliver lånt.
Strukturer ( struct ):
Enumeration ( enum ): hver mulighed i en optælling i Rust kan også associeres med andre data, hvorfor opregningen også kaldes en tagget union eller sumtype . Syntaksen for at deklarere varianter ligner syntaksen for at erklære strukturer: der kan være varianter uden data, varianter med navngivne data og varianter med unavngivne data:
Valget bør gives fortrinsret const, da en konstant ofte ikke behøver en specifik adresse i hukommelsen og constgiver dig mulighed for at udføre optimeringer som konstant foldning .
Sproget implementerer en hukommelsesstyringsmodel fokuseret på sikre samtidighedsmønstre, der forhindrer forkert hukommelsesadgang, hvilket er en almindelig kilde til kritiske segmenteringsfejl i andre programmeringssprog. Giver kontrol over brugen af uinitialiserede og deinitialiserede variabler; det er umuligt at dele delte tilstande af flere opgaver; statisk analyse af levetiden for pointere og check for out-of-bounds-array er tilvejebragt (automatisk og altid, men det er muligt at slå check-in- unsafeblokkene fra ved hjælp af metoden get_unchecked).
Den såkaldte Move-semantik er implementeret: Rust "overfører" ( flytter ) som standard en pointer til et objekt på heapen til en ny ejer på tildeling, hvilket gør den gamle variabel ugyldig. Dette sker ikke, hvis typen implementerer Copy-egenskaben, fordi dataene på stakken er kopieret.
lad a = "et objekt med data på heapen" . to_string (); // objekt sendt til variabel b // variabel a bliver uinitialiseret lad b = a ; // fejl! lad c = a ; // objektdata på stakken lad a = 55 ; // en kopi af objektet sendes til variabel b lad b = a ; // c = 55 lad c = a ;Et andet træk ved hukommelsesmodellen er understøttelse af lån ( lån ) med mulighed for at ændre det lånte objekt ( &mut) og uden det ( &): Leksisk og semantisk ligner meget links, men har specifikationer: at låne et objekt ligner semantikken i " Enten mange læsere eller en forfatter " - en genstand kan lånes enten én gang med mulighed for at ændre objektet, eller gentagne gange uden; lån kan genlånes til en anden låntager. I modsætning til den sædvanlige "Enten mange læsere eller en forfatter"-semantik, gælder den ikke i forbindelse med trådsynkronisering, men universelt. Kontrol af rigtigheden af lån finder sted på kompileringstidspunktet og genererer ikke yderligere eksekverbar kode (princippet om nulomkostningsabstraktioner ). Compileren kontrollerer også forholdet mellem lånets levetid og selve objektet - lån kan ikke leve længere (gå ud over omfanget ) af det lånte objekt. Lån fungerer med alle data uanset deres placering (stak, lokal eller delt heap, andre specielle placeringer). Det er nødvendigt at skelne mellem uafhængige begreber - mutabiliteten af selve låningen ( let mut b = &c) og mutabiliteten af det lånte objekt ( let b = &mut c).
Box - En smart pointer, der ejer et objekt på dyngen, ødelægger objektet og frigør hukommelse, når det går uden for rækkevidde.
Cell ( Celle , RefCell ) implementerer indholdsmutabilitet, mens selve cellen er uforanderlig.
Referencetalte ( Rc<T>) og atomreferencetalte ( Arc<T>) pointere: Referencetalte smarte pointere, der ødelægger et objekt og frigiver hukommelse, når tælleren nulstilles. Arc implementerer trådsikkerhed for referenceantallet (men ikke for selve objektet). Rc og Arc styrer et uforanderligt objekt, så deres typiske brug er både Rc<Cell<T>>i et enkelt-trådet program og Arc<Mutex<T>>i et flertrådet.
Rå pointers uforanderlige ( *const T) og mutable ( *mut T): Pointere uden sikkerhedsgaranti. Det anbefales kraftigt ikke at bruge dem.
Bindinger er uforanderlige som standard, og for at erklære en variabel mutable, skal du bruge mut nøgleordet .
Eksempler:
lad x = 80 ; // bind ejer x til værdi 80 lad mut y = 50 ; // foranderlig binding lad z = & x ; // uforanderlig reference til uforanderlig binding lad w = & mut y ; // uforanderlig reference til foranderlig binding lad r = & mut y ; // fejl: kan ikke oprette en anden reference til en foranderlig binding * w = 90 // y = 90 * z = 30 // fejl: Forsøg på at ændre via reference til en uforanderlig binding lad n = Box :: new ( 42 ); // pakning lad m = Rc :: ny ( 55 ); // referencetæller lad data = Arc :: new ( "test_string" ) // atomtællerI sin ph.d.-afhandling beviste Ralph Jung formelt trådsikkerheden og sikkerheden ved hukommelsesstyring ved at bruge partitioneringslogik i sin RustBelt-model og Iris-værktøjet (baseret på Coq ) [30] .
Sprogets syntaks ligner C og C++ ; sproget skelner mellem store og små bogstaver, kodeblokke er begrænset af krøllede klammeparenteser; standardnavnene på kontrolstrukturer, hvis , andet , mens og for bruges ; kommentarer skrives også i C-format; modulnavne er adskilt af to kolontegn ( ::). Identifikatorer kan indeholde latinske bogstaver, tal og understregninger. Strengliteraler kan bruge et hvilket som helst UTF-8 unicode-tegn.
Et sæt operatorer i Rust: aritmetik ( * - multiplikation, / - division, % - tager resten af division, + - addition, - - subtraktion og en unær præfiksoperator -til at ændre fortegnet for et tal), bitvis ( >>, <<, &, |og ^), sammenligning operatorer ( ==, !=, <, >, <=, >=), logiske ( &&og ||). Rust bruger den binære operator til at kaste typer as. Implicit type casting forekommer i et meget lille sæt situationer [31] .
Rust understøtter makroer , regulære udtrykserstatninger, der kører i præ-kompileringsfasen, mere avanceret og sikrere end C. Makroer (makroer) er brugerdefinerede, simple syntaksudvidelser, der kan udføres med en kommando macro_rules!. Makroer er defineret i samme stil som mønstermatchningskonstruktionen. Makroattributten er et udråbstegn i slutningen af navnet. Også understøttet er såkaldte "proceduremæssige" makroer [32] , der har evnen til at udføre vilkårlig kode på kompileringstidspunktet.
Nøgleordet letdefinerer en binding (lokal variabel).
lad x : i32 = 5 ;Denne notation betyder: " x er en typebinding i32(32-bit heltal) med værdi fem".
På sproget er match-konstruktionen en generaliseret og forbedret version af C-switch-konstruktionen. Desuden er match den mest kraftfulde, alsidige og, man kan endda sige, nøglekontrolelementet ikke kun for udførelsesflowet, men også for datastrukturer i sproget. Flere mønstre kan matches i matchudtryk ved hjælp af syntaksen |, som betyder logisk eller.
lad x = 10 ; match x { 1 | 2 => println! ( "en eller to" ), 3 => println! ( "tre" ) 4 ..= 10 => println! ( "fra fire til ti" ), // Denne gren vil fungere, fordi 10 hører til dette område. _ => println! ( "alt, der ikke matcher betingelserne ovenfor" ), // "_" matcher enhver værdi }Når du arbejder med sammensatte datatyper (struktur, optælling, tuple, array), kan du parse dem i dele ("destrukturere") inde i skabelonen. Struktur destrukturering:
structPoint { _ x : i32 , y : i32 , } lad punkt = Punkt { x : 0 , y : 0 }; match point { Punkt { x : 0 , y } => println! ( "x er nul, y er lig med {}" , y ), // da "x" er lig nul, vil denne gren fungere. Punkt { x , y : 0 } => println! ( "x er lig med {}, y er nul" , x ), Punkt { x , y } => println! ( "x = {}, y = {}" , x , y ), }Destrukturering af en enum:
enum farve { Rgb ( i32 , i32 , i32 ), hsv ( i32 , i32 , i32 ), } lad farve = Farve :: Hsv ( 0 , 0 , 100 ); match farve { Farve :: Rgb ( 0 , 0 , 0 ) | Farve :: Hsv ( 0 , 0 , 0 ) => println! ( "sort" ) Farve :: Rgb ( 255 , 255 , 255 ) | Farve :: Hsv ( 0 , 0 , 100 ) => println! ( "hvid" ), // denne gren vil fungere. Farve :: Rgb ( rød , grøn , blå ) => { println! ( "rød: {}, grøn: {}, blå: {}" , rød , grøn , blå ) } // vil fungere for alle Rgb-værdier, der ikke matcher betingelserne ovenfor. Farve :: Hsv ( nuance , mætning , lysstyrke ) => println! ( "nuance: {}, mætning: {}, lysstyrke: {}" , farvetone , mætning , lysstyrke ), // det samme, men med Hsv. }Tuple destrukturering:
lad ( a , b ) = ( 1 , 2 ); println! ( "{}" , a ); // 1 println! ( "{}" , b ); // 2Syntaksen if letgiver dig mulighed for at kombinere ifog letind i en mindre verbose konstruktion og derefter behandle værdierne svarende til kun ét mønster, mens du ignorerer alle andre. Denne syntaks er passende, når kun ét mønster skal matches.
lad x = Nogle ( 10 ); hvis lad Nogle ( værdi ) = x { // her er vi ved at destrukturere x, variabelværdien gemmer værdien 10. // denne gren vil blive udført, fordi "x" gemmer værdien inde. println! ( "værdi = {}" , værdi ); } andet { // "else"-operatoren fungerer her som en erstatning for "_" i matchudtryk. println! ( "x - tom" ); }I blokke og funktioner markeret med unsafe( usikre fra engelsk - "usikker"), giver compileren dig kun mulighed for at gøre fem yderligere ting:
Du unsafeskal ty til, når du laver abstraktioner på lavt niveau, især når du udvikler Rust-standardbiblioteket; normal kode anbefales at blive skrevet uden unsafe.
I Rust er objektsystemet baseret på træk ( træk ) og strukturer ( strukturer ). Træk definerer metodesignaturer , der skal implementeres for hver type (oftest en struktur), der implementerer egenskaben. Et træk kan også indeholde standardimplementeringer af metoder. Implementeringen af træk for en given struktur, samt implementeringen af strukturens egne metoder, betegnes med nøgleordet impl. Sproget indeholder flere dusin indbyggede træk, hvoraf de fleste bruges til operatøroverbelastning , og nogle af dem har en særlig betydning.
Rust understøtter egenskabsarvsanalogien - en egenskab kan kræve en implementeringstype for at implementere andre egenskaber. Der er dog ingen sproglig støtte til nedarvning af selve typerne, og dermed klassisk OOP , i Rust. I stedet for typearv implementeres klassehierarki- analogien ved at introducere træk, herunder en forfaderstruktur i en underordnet struktur, eller indføre opregninger for at generalisere forskellige strukturer [33] .
Sproget understøtter generiske typer ( generiske ). Ud over funktioner kan Rust også generalisere komplekse datatyper, strukturer og enums . Rust -kompileren kompilerer generiske funktioner meget effektivt ved at monomorfisere dem (genererer en separat kopi af hver generisk funktion direkte ved hvert call point). Således kan kopien tilpasses specifikke typer argumenter, og derfor optimeres til disse typer. I denne henseende er Rusts generiske funktioner sammenlignelige i ydeevne med C++ sprogskabeloner .
Tidligere versioner af sproget understøttede letvægtstråde, men de blev opgivet til fordel for native operativsystemtråde . Den anbefalede metode til at udveksle data mellem tråde er dog at sende beskeder i stedet for at bruge delt hukommelse. For at opnå høj ydeevne er det muligt at sende data ikke gennem kopiering, men ved hjælp af egne pointere ( Box<T>). De garanterer kun én ejer.
Definitionen og påkaldelsen af asynkrone operationer understøttes på sprogsyntaksniveau: et nøgleord asyncdefinerer en asynkron funktion eller blok; et normalt kald til en sådan funktion returnerer et objekt med en egenskab Future - et håndtag til en doven asynkron operation [34] . Opkaldet .awaittillader en asynkron operation at vente, indtil en anden asynkron operation er afsluttet. Samtidig indgår implementeringen af eksekveringsmiljøet for asynkrone operationer hverken i kernen af sproget eller i standardbiblioteket, men leveres af tredjepartsbiblioteker [35] .
Modulsystem: en kompileringsenhed ("kasse") kan bestå af flere moduler. Hierarkiet af moduler matcher normalt hierarkiet af mapper og projektfiler. Et modul er (som regel) en separat fil og er også et navneområde og et af midlerne til at kontrollere synligheden af identifikatorer: inden for modulet (og i undermoduler) er alle identifikatorer "synlige", i højere moduler kun offentlige ( pub) funktioner, typer, træk, konstanter, undermoduler, strukturfelter.
Automatiseret test: Sproget gør det muligt at implementere automatiserede enhedstests (unit tests ) direkte i det modul eller undermodul, der testes. Testmetoder ignoreres under kompilering og kaldes kun under test. Integrationstest er implementeret som separate kasser i tests.
Automatiseret dokumentation: Rustdoc- værktøjet giver dig mulighed for at generere HTML-dokumentation direkte fra kildekoden. Dokumentation i koden er markeret med en tredobbelt skråstreg ( /// Пример документации) eller en dobbelt skråstreg med et udråbstegn, for moduldokumentation - ( //! Пример документации модуля). Markup-sproget Markdown understøttes . Kode, der er eksekverbar (dokumentationstest) kan indlejres i dokumentationen. Dette giver blandt andet mulighed for at tjekke dokumentationens relevans ved ændringer i projektet.
Pakkestyringssystem: Cargo Package Manager (som også er hovedværktøjet til at oprette, kompilere og teste projekter) ved hjælp af Cargo-manifestfilen. toml løser projektafhængigheder importerede kasser) ved at downloade dem fra crates.io- lageret .
Krav til identifikatorer: compileren kontrollerer implementeringen af navngivningskonventioner for variabler, typer, funktioner og så videre ( slange_case , UpperCamelCase , SCREAMING_SNAKE_CASE), såvel som ubrugte identifikatorer; ubrugte identifikatorer anbefales at starte med en understregning; der er visse retningslinjer for navngivning af konstruktører, typekonverteringsmetoder osv. [36]
Rusts hukommelsesstyringsprincipper er markant forskellige fra begge sprog med fuld hukommelsesadgang og sprog med fuld hukommelseskontrol af skraldeopsamleren . Rusts hukommelsesmodel er bygget på en sådan måde, at den på den ene side giver udvikleren mulighed for at kontrollere, hvor data skal allokeres, indføre adskillelse efter pointertyper og give kontrol over deres brug på kompileringsstadiet. På den anden side har Rusts referencetællingsmekanisme en tendens til at kaste kompileringsfejl i tilfælde, hvor brugen af andre sprog resulterer i runtime fejl eller programnedbrud.
Sproget giver dig mulighed for at erklære funktioner og kodeblokke som "usikre" ( unsafe). Nogle begrænsninger gælder ikke i omfanget af en sådan usikker kode, så det er muligt at udføre operationer på et lavere niveau, men udvikleren skal fuldt ud forstå, hvad han gør.
Mozilla projekter | |
---|---|
Browsere | |
Andre projekter | |
Udvikler sig ikke | |
Infrastruktur | |
Komponenter |
|