Come configurare smartphone e PC. Portale informativo
  • casa
  • Ferro
  • Linguaggio di programmazione Rust. Panoramica del linguaggio di programmazione Rust

Linguaggio di programmazione Rust. Panoramica del linguaggio di programmazione Rust

Nel 2013 Mozilla, insieme a Samsung, ha annunciato lo sviluppo di un nuovo motore per browser web, Servo. È stato creato appositamente per processori multi-core di dispositivi mobili, è in grado di suddividere le attività in thread paralleli e di ridurre notevolmente il tempo di caricamento delle pagine web. Servo è scritto interamente nel linguaggio di programmazione Rust, sviluppato da Mozilla per la scrittura di applicazioni mobili.

A proposito della lingua

Rust è un linguaggio di programmazione procedurale che supporta una varietà di stili di codifica. Lo sviluppatore Graydon Hoare ha iniziato a creare il linguaggio nel 2006 e tre anni dopo Mozilla si è unita al progetto. Nel 2010, Rust è stato presentato alla conferenza Mozilla Summit. Nello stesso anno lo sviluppo fu trasferito ad un compilatore scritto in Rust. Il compilatore ha utilizzato come database il sistema universale di analisi e trasformazione dei programmi LLVM.

La prima versione stabile del linguaggio è stata rilasciata nel 2015. Dopo il rilascio della versione alpha, Rust ha subito modifiche: all'interno del compilatore sono state lasciate solo funzionalità già pronte che non cambieranno. Tutto il resto è stato spostato nella sezione sperimentale.

Al centro della lingua, Graydon Hoare ha stabilito concetti come:

  • Sicurezza. Rust contiene una serie di restrizioni per i programmatori abilitate per impostazione predefinita. Per disabilitarli è richiesta l'etichetta “unsafe” nei blocchi e nelle funzioni.
  • Velocità. Il linguaggio è paragonabile in termini di velocità a un altro linguaggio di programmazione, il C++, che offre numerosi vantaggi al programmatore.
  • Parallelismo. Il sistema può eseguire più calcoli contemporaneamente e allo stesso tempo possono interagire tra loro.
  • Brevità. Le prime parole chiave in Rust erano limitate a cinque caratteri. Ma in seguito questa restrizione è stata revocata.

Un esempio di uno dei primi codici in Rust

Tuttavia, Rust non è privo di inconvenienti, i più evidenti dei quali sono:

  • Ridondanza del codice.
  • Mancanza di letteratura per l'apprendimento delle lingue.
  • Chiarezza nell'inserimento dei parametri di compilazione. Questo non sempre è adatto ai programmatori esperti, poiché altri linguaggi non hanno regole simili.

Tuttavia, il linguaggio viene regolarmente modernizzato e ampliato: i suoi aggiornamenti vengono rilasciati ogni 6 settimane.

Confronto tra Rust e C++

I creatori di Rust lo considerano il successore del C++, emerso all'inizio degli anni '80 quando lo sviluppatore ha apportato diversi miglioramenti al linguaggio C. Vale quindi la pena confrontare il linguaggio giovane e ancora in evoluzione con quello collaudato nel tempo.

  • Accesso alla memoria remota. In C++, l'eliminazione di una variabile può causare numerosi problemi. Tali complicazioni non sono possibili in Rust, poiché non dispone di comandi per eliminare la memoria. Il compilatore discendente segnalerà che il codice scritto contiene un errore e il compilatore C++ restituirà il risultato senza i valori rimossi, senza nemmeno segnalare il problema.
  • Punto e virgola. Aggiungere un punto e virgola extra al codice causerà un errore in C++, mentre in Rust il corpo del loop è racchiuso tra parentesi graffe.
  • Codice non sicuro. Rust ha un'etichetta "non sicura" che isola il codice principale da quello non sicuro. In futuro, durante la revisione del codice, ciò consentirà di restringere la ricerca delle vulnerabilità.

Firefox è stato implementato in C++: questo linguaggio capriccioso richiedeva una maggiore attenzione ai dettagli. Altrimenti, gli errori si trasformavano in gravi vulnerabilità. Rust è stato progettato per risolvere questo problema.

Prospettive

Nella classifica RedMonk del terzo trimestre del 2018, il linguaggio di programmazione Mozilla si colloca costantemente al 23° posto. Gli esperti ritengono che la sua posizione non rischi di migliorare. Nonostante ciò, nell'agosto 2018 i creatori hanno rilasciato la versione aggiornata di Rust 1.28.

Dopo il rilascio di Rust nel 2015, secondo Stack Overflow, il 74% degli sviluppatori ha voluto conoscerlo. Tuttavia, già nel 2016, è passato al primo posto: il 79% degli utenti ha indicato Rust come linguaggio di programmazione preferito e ha espresso il desiderio di continuare a lavorarci. La ruggine ha preso il primo posto in questo parametro nel 2018.

Stack Overflow è un popolare sistema di domande e risposte di programmazione sviluppato nel 2008.

La popolarità di Rust è confermata dal numero di aziende che lo utilizzano nel loro sviluppo. Attualmente, questo elenco comprende 105 organizzazioni.

Quindi, vorremmo presentare alla vostra attenzione un recente festeggiato (ha compiuto un anno il 15 maggio 2016) - Rust. Si tratta di un linguaggio di programmazione universale sviluppato da Mozilla, i cui tre principi fondamentali sono: velocità, sicurezza ed ergonomia. Gli stessi creatori lo considerano immodestamente uno dei più probabili successori del C/C++. Secondo un sondaggio su StackOverflow, Rust è oggi il linguaggio preferito dagli sviluppatori. Quindi, diamo un'occhiata più da vicino a cosa è.

Ruggine per un principiante

Non voglio ingannare nessuno, quindi ecco una dichiarazione responsabile: Rust è piuttosto difficile da imparare. In primo luogo, ciò è dovuto alla giovinezza della lingua e, di conseguenza, alla piccola quantità di letteratura. In secondo luogo, potrebbe essere ancora più facile per una persona lontana dalla programmazione impararlo che per qualcuno che ha familiarità con altri linguaggi. Quindi, ad esempio, uno specialista IT già pronto sarà molto infastidito dalla necessità di prescrivere le più piccole operazioni e l'assenza di ereditarietà in quanto tale nella lingua lo confonderà semplicemente.

Tuttavia, Rust si sta sviluppando rapidamente (una nuova versione viene rilasciata ogni 6 settimane), la comunità sta crescendo e trovare informazioni su Internet non è più difficile.

Come studiare

Puoi trovare quasi tutto ciò di cui hai bisogno sul sito ufficiale. Inoltre, la comunità dei follower di Rust è molto ampia e amichevole, quindi puoi sempre rivolgerti a IRC (c'è una sezione russa) e al forum ufficiale per chiedere consigli. Inoltre, i libri, compresi quelli elettronici, iniziarono ad apparire poco a poco. È ancora difficile valutarne la qualità, ma questo è un dato di fatto.

Per coloro che hanno superato la fase iniziale di conoscenza, su GiHub è possibile trovare molto materiale utile, inclusi RFC e commit. Inoltre, potrete partecipare di persona o almeno guardare il webcast di una delle conferenze di Rust previste per la seconda metà dell'anno. Ecco il calendario:

  • 9-10 settembre conferenza RustConf a Portland, USA;
  • 17 settembre, Conferenza delle Comunità Europee RustFest a Berlino, Germania;
  • 27 ottobre Conferenza Rust Belt Rust a Pittsburgh, USA;

Ebbene, per incontrare coloro che considerano Rust la loro vocazione, e allo stesso tempo chiedere loro tutta la loro saggezza, potete contattare gli organizzatori e i partecipanti agli incontri degli appassionati di lingue a Mosca.

Peculiarità

Duplicando un po' quanto detto prima, metteremo in evidenza i principali pro e contro del linguaggio Rust.

Professionisti:

  • Lavoro sicuro con la memoria;
  • Alte prestazioni;
  • Tipo di dati algebrici;
  • Prevedibilità della compilazione;

Aspetti negativi:

  • Una certa ridondanza del codice;
  • Alta intensità di sviluppo del linguaggio e, di conseguenza, mancanza di buona letteratura rilevante per lo studio;
  • La necessità di specificare in modo chiaro e inequivocabile i parametri per la compilazione.

In effetti, ci si abitua rapidamente alle differenze, come la sostituzione dell'ereditarietà con le abilità. Non appena i tuoi occhi si abituano e le tue mani si abituano, Rust si trasforma in un linguaggio completamente funzionante, più semplice e funzionale del C++, ma inferiore in “bellezza” a molti altri linguaggi di programmazione. In effetti, la principale differenza tra Rust e i suoi concorrenti e predecessori è la velocità e la sicurezza.

Richiesta

Oggi Rust è popolare tra gli sviluppatori di giochi, grafica e sistemi operativi. Tuttavia, per ovvie ragioni, il numero di luoghi fissi in cui sono richiesti esperti Rust altamente specializzati è estremamente ridotto nel mondo, e ancor di più in Russia. Tuttavia non vi sono ancora segnali che la lingua cadrà nell’oblio; sembra piuttosto una sistematica conquista del mondo. Ciò significa che buone capacità nell'uso di Rust in futuro ti aiuteranno a trovare un lavoro interessante e ben pagato sia nel nostro Paese che all'estero.

Ancora richiesto: professione "".

Ruggineè un nuovo linguaggio di programmazione sperimentale sviluppato da Mozilla. Il linguaggio è compilato e multiparadigma, posizionato come alternativa al C/C++, il che di per sé è interessante, poiché non ci sono nemmeno molti contendenti alla concorrenza. Puoi ricordare D di Walter Bright o Go di Google.
Rust supporta la programmazione funzionale, parallela, procedurale e orientata agli oggetti, ad es. quasi l'intera gamma di paradigmi effettivamente utilizzati nella programmazione delle applicazioni.

Il mio obiettivo non è tradurre la documentazione (inoltre è molto scarsa ed è in continua evoluzione, dal momento che non è stata ancora rilasciata una versione ufficiale del linguaggio), ma voglio piuttosto evidenziare le caratteristiche più interessanti del linguaggio. Le informazioni sono state raccolte sia dalla documentazione ufficiale che dalle pochissime menzioni della lingua su Internet.

Prima impressione

La sintassi del linguaggio è costruita in uno stile tradizionale simile al C (il che è una buona notizia, poiché questo è già uno standard de facto). Naturalmente sono stati presi in considerazione i noti errori di progettazione C/C++.
Un tradizionale Hello World si presenta così:
usa standard; fn main(args: ) ( std::io::println("ciao mondo da " + args + "!"); )

Un esempio leggermente più complicato: la funzione di calcolo fattoriale:

Fn fac(n: int) -> int ( sia risultato = 1, i = 1; mentre i<= n { result *= i; i += 1; } ret result; }

Come puoi vedere dall'esempio, le funzioni sono dichiarate nello stile “funzionale” (questo stile presenta alcuni vantaggi rispetto al tradizionale “int fac(int n)”). Vediamo inferenza automatica del tipo(let parola chiave), nessuna parentesi nell'argomento while (come Go). Un’altra cosa che salta subito all’occhio è la compattezza delle parole chiave. I creatori di Rust hanno davvero tenuto a mantenere tutte le parole chiave più brevi possibile e, a dire il vero, mi piace.

Piccole ma interessanti caratteristiche sintattiche

  • È possibile inserire caratteri di sottolineatura nelle costanti numeriche. Questa è una funzionalità utile; questa funzionalità viene ora aggiunta a molte nuove lingue.
    0xffff_ffff_ffff_ffff_ffff_ffff
  • Costanti binarie. Naturalmente, un vero programmatore deve convertire bin in esadecimale nella sua testa, ma è più conveniente così! 0b1111_1111_1001_0000
  • I corpi di eventuali istruzioni (anche quelle costituite da una singola espressione) devono essere racchiusi tra parentesi graffe. Ad esempio, in C potresti scrivere if(x>0) foo(); , in Rust devi mettere le parentesi graffe attorno a foo()
  • Ma non è necessario che gli argomenti di if, while e operatori simili siano racchiusi tra parentesi
  • in molti casi, i blocchi di codice possono essere considerati come espressioni. In particolare è possibile:
    let x = if the_stars_align() ( 4 ) else if qualcos'altro() ( 3 ) else ( 0 );
  • sintassi della dichiarazione della funzione - prima la parola chiave fn, poi un elenco di argomenti, dopo il nome è indicato il tipo dell'argomento, quindi, se la funzione restituisce un valore, una freccia "->" e il tipo del valore restituito
  • Le variabili vengono dichiarate allo stesso modo: la parola chiave let, il nome della variabile, dopo la variabile è possibile specificare il tipo tramite i due punti, e quindi assegnare un valore iniziale.
    contiamo: int = 5;
  • Per impostazione predefinita, tutte le variabili sono immutabili; La parola chiave mutable viene utilizzata per dichiarare variabili mutabili.
  • i nomi dei tipi base sono i più compatti tra tutti quelli che ho incontrato: i8, i16, i32, i64, u8, u16, u32, u64,f32, f64
  • come accennato in precedenza, è supportata l'inferenza automatica del tipo
Il linguaggio dispone di strumenti di debug del programma integrati:
Parola chiave fallire termina il processo attuale
Parola chiave tronco d'albero restituisce qualsiasi espressione linguistica al log (ad esempio, a stderr)
Parola chiave affermare controlla l'espressione e, se è falsa, termina il processo corrente
Parola chiave Nota consente di visualizzare informazioni aggiuntive in caso di conclusione anomala del processo.

Tipi di dati

La ruggine, come Go, supporta tipizzazione strutturale(sebbene, secondo gli autori, le lingue si siano sviluppate indipendentemente, quindi questa è l'influenza dei loro predecessori comuni: Alef, Limbo, ecc.). Cos'è la tipizzazione strutturale? Ad esempio, hai una struttura dichiarata in qualche file (o, nella terminologia Rust, un "record")
tipo punto = (x: float, y: float);
Puoi dichiarare un sacco di variabili e funzioni con tipi di argomento "punto". Quindi, da qualche altra parte, puoi dichiarare qualche altra struttura, come
digitare MioSuperPunto = (x: float, y: float);
e le variabili di questo tipo saranno pienamente compatibili con le variabili di tipo punto.

Al contrario, la tipizzazione nominativa adottata in C, C++, C# e Java non consente tali costrutti. Con la tipizzazione nominativa, ogni struttura è un tipo unico, incompatibile per impostazione predefinita con altri tipi.

Le strutture in Rust sono chiamate “record”. Esistono anche tuple: si tratta degli stessi record, ma con campi senza nome. Gli elementi di una tupla, a differenza degli elementi di un record, non possono essere mutabili.

Esistono vettori, in qualche modo simili agli array ordinari e in qualche modo simili al tipo std::vettore di stl. Quando si inizializza con un elenco, vengono utilizzate le parentesi quadre e non le parentesi graffe come in C/C++

Sia myvec = ;

Un vettore, tuttavia, è una struttura dati dinamica; in particolare, i vettori supportano la concatenazione.

Sia v: mutabile = ; v += ;

Ci sono modelli. La loro sintassi è abbastanza logica, senza confusione di “template” dal C++. Sono supportati i modelli di funzioni e tipi di dati.

Fn per_rev (v: [T], act: block(T)) ( let i = std::vec::len(v); while i > 0u ( i -= 1u; act(v[i]); ) ) tipo circolare_buff = (inizio: uint, fine: uint, buf: );

La lingua supporta i cosiddetti tag. Questa non è altro che un'unione di C, con un campo aggiuntivo: il codice della variante utilizzata (cioè qualcosa in comune tra un'unione e un'enumerazione). Oppure, da un punto di vista teorico, un tipo di dato algebrico.

Forma del tag (cerchio(punto, float); rettangolo(punto, punto); )

Nel caso più semplice, un tag è identico a un'enumerazione:

Tag animale ( cane; gatto; ) let a: animale = cane; a = gatto;
Nei casi più complessi, ogni elemento della “enumerazione” è una struttura indipendente che ha un proprio “costruttore”.
Un altro esempio interessante è una struttura ricorsiva che viene utilizzata per definire un oggetto di tipo “lista”:
elenco dei tag ( zero; contro(T, @list ); ) lascia una: lista = contro(10, @contro(12, @nil));
I tag possono partecipare alle espressioni di corrispondenza dei modelli, che possono essere piuttosto complesse.
alt x ( contro(a, @contro(b, _)) ( process_pair(a,b); ) contro(10, _) ( process_ten(); ) _ ( fail; ) )

Corrispondenza del modello

Per cominciare, possiamo considerare il modello di corrispondenza come un interruttore migliorato. Viene utilizzata la parola chiave alt, seguita dall'espressione da analizzare e quindi nel corpo dell'istruzione: modelli e azioni se i modelli corrispondono.
alt mio_numero ( 0 ( std::io::println("zero"); ) 1 | 2 ( std::io::println("uno o due"); ) Da 3 a 10 ( std::io::println ("da tre a dieci"); ) _ ( std::io::println("qualcos'altro"); ) )
Come "modelli" puoi utilizzare non solo costanti (come in C), ma anche espressioni più complesse: variabili, tuple, intervalli, tipi, segnaposto ("_"). È possibile specificare condizioni aggiuntive utilizzando l'istruzione quando immediatamente successiva al modello. Esiste una variante speciale dell'operatore per la corrispondenza dei tipi. Ciò è possibile perché la lingua ha un tipo di variante universale Qualunque, i cui oggetti possono contenere valori di qualsiasi tipo.

Puntatori. Oltre ai soliti puntatori "C", Rust supporta speciali puntatori "intelligenti" con conteggio dei riferimenti integrato: condivisi (riquadri condivisi) e unici (riquadri unici). Sono in qualche modo simili a shared_ptr e unique_ptr di C++. Hanno la propria sintassi: @ per condiviso e ~ per unico. Per i puntatori univoci, invece della copia, esiste un'operazione speciale: lo spostamento:
sia x = ~10; lascia che tu<- x;
Dopo tale spostamento, il puntatore x viene deiinizializzato.

Chiusure, applicazioni parziali, iteratori

È qui che inizia la programmazione funzionale. Rust supporta pienamente il concetto di funzioni di ordine superiore, ovvero funzioni che possono accettare altre funzioni come argomenti e restituirle.

1. Parola chiave lambda utilizzato per dichiarare una funzione annidata o un tipo di dati funzionale.

Fn make_plus_function(x: int) -> lambda(int) -> int ( lambda(y: int) -> int ( x + y ) ) let plus_two = make_plus_function(2); asserisci più_due(3) == 5;

In questo esempio, abbiamo una funzione make_plus_function che accetta un argomento "x" di tipo int e restituisce una funzione di tipo "int->int" (lambda è la parola chiave qui). Il corpo della funzione descrive proprio questa funzione. La mancanza di un operatore di “ritorno” crea un po’ di confusione, ma questa è una cosa comune per i FP.

2. Parola chiave bloccare usato per dichiarare un tipo funzionale - un argomento di funzione, che può essere sostituito da qualcosa di simile a un blocco di codice normale.
fn map_int(f: block(int) -> int, vec: ) -> ( let result = ; for i in vec ( result += ; ) ret result; ) map_int((|x| x + 1 ), );

Qui abbiamo una funzione il cui input è un blocco - essenzialmente una funzione lambda di tipo "int->int" e un vettore di tipo int (più avanti sulla sintassi dei vettori). Il “blocco” stesso è scritto nel codice chiamante utilizzando una sintassi alquanto insolita (|x| x + 1). Personalmente preferisco i lambda in C#, il simbolo | percepito persistentemente come OR bit a bit (che, tra l'altro, è presente anche in Rust, come tutte le vecchie operazioni basate su C).

3. L'applicazione parziale è la creazione di una funzione basata su un'altra funzione con più argomenti specificando i valori di alcuni degli argomenti di quell'altra funzione. La parola chiave utilizzata per questo è legamento e un carattere segnaposto "_":

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

Per renderlo più chiaro, dirò subito che questo può essere fatto in C normale creando un semplice wrapper, qualcosa del genere:
const char* daynum (int i) ( const char *s =("mo", "tu", "noi", "facciamo", "fr", "sa", "su"); return s[i]; )

Ma l'applicazione parziale è uno stile funzionale, non procedurale (a proposito, dall'esempio fornito non è chiaro come eseguire un'applicazione parziale per ottenere una funzione senza argomenti)

Un altro esempio: la funzione add viene dichiarata con due argomenti int, restituendo int. Successivamente, viene dichiarato il tipo funzionale single_param_fn, che ha un argomento int e restituisce int. Usando bind, vengono dichiarati due oggetti funzione add4 e add5, costruiti sulla base della funzione add, che ha argomenti parzialmente specificati.

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

Gli oggetti funzione possono essere chiamati allo stesso modo delle normali funzioni.
assert (aggiungi(4,5) == aggiungi4(5)); assert (aggiungi(4,5) == aggiungi5(4));

4. Funzioni pure e predicati
Le funzioni pure sono funzioni che non hanno effetti collaterali (comprese quelle che non chiamano altre funzioni tranne quelle pure). Tali funzioni sono identificate dalla parola chiave pura.
puro fn lt_42(x: int) -> bool ( ret (x< 42); }
I predicati sono funzioni pure che restituiscono il tipo bool. Tali funzioni possono essere utilizzate nel sistema typestate (vedi sotto), ovvero chiamate in fase di compilazione per vari controlli statici.

Macro sintattiche
Una funzionalità pianificata, ma molto utile. È ancora in fase di sviluppo iniziale in Rust.
std::io::println(#fmt("%s è %d", "la risposta", 42));
Un'espressione simile alla printf di C, ma eseguita in fase di compilazione (di conseguenza, tutti gli errori di argomento vengono rilevati in fase di compilazione). Sfortunatamente, ci sono pochissimi materiali sulle macro sintattiche e loro stessi sono in fase di sviluppo, ma c'è speranza che venga fuori qualcosa come le macro Nemerle.
Tra l'altro, a differenza di Nemerle, ritengo molto intelligente la scelta di evidenziare sintatticamente le macro utilizzando il simbolo #: una macro è un'entità molto diversa da una funzione, e credo sia importante vedere a prima vista dove si trovano le funzioni del codice vengono chiamate e dove - macro.

Attributi

Un concetto simile agli attributi C# (e anche con una sintassi simile). Un ringraziamento speciale agli sviluppatori per questo. Come ci si aspetterebbe, gli attributi aggiungono metainformazioni all'entità che annotano.
# fn registro_win_service() ( /* ... */ )
È stata inventata un'altra variante della sintassi degli attributi: la stessa riga, ma con un punto e virgola alla fine, annota il contesto corrente. Cioè, ciò che corrisponde alle parentesi graffe più vicine che racchiudono tale attributo.
fn Register_win_service() ( #; /* ... */ )

Calcolo parallelo

Forse una delle parti più interessanti della lingua. Allo stesso tempo, al momento non è descritto affatto nel tutorial :)
Un programma Rust è costituito da un "albero delle attività". Ogni attività ha una funzione di input, un proprio stack, mezzi di interazione con altre attività: canali per le informazioni in uscita e porte per le informazioni in entrata e possiede alcuni oggetti nell'heap dinamico.
Possono esistere più attività Rust all'interno di un singolo processo del sistema operativo. Le attività di Rust sono "leggere": ciascuna attività consuma meno memoria rispetto al processo del sistema operativo e il passaggio da una all'altra è più veloce del passaggio da un processo all'altro del sistema operativo (qui, probabilmente, intendiamo "thread").

Un'attività è costituita da almeno una funzione senza argomenti. L'attività viene avviata utilizzando la funzione di spawn. Ogni attività può avere canali attraverso i quali trasmette informazioni ad altre attività. Un canale è un tipo di modello speciale chan, parametrizzato dal tipo di dati del canale. Ad esempio, chan è un canale per la trasmissione di byte senza segno.
Per inviare a un canale, utilizzare la funzione send, il cui primo argomento è il canale e il secondo è il valore da inviare. Questa funzione inserisce effettivamente il valore nel buffer interno del canale.
Le porte vengono utilizzate per ricevere dati. Una porta è un tipo di porta generico, parametrizzato da un tipo di dati porta: port è una porta per ricevere byte senza segno.
Per leggere dalle porte, utilizzare la funzione recv, il cui argomento è la porta e il valore restituito sono i dati dalla porta. La lettura blocca il compito, ad es. se la porta è vuota, l'attività entra nello stato di attesa finché un'altra attività non invia dati al canale associato alla porta.
Associare i canali alle porte è molto semplice: inizializzando il canale con una porta utilizzando la parola chiave chan:
lascia reqport = porta();
lascia che reqchan = chan(reqport);
È possibile collegare più canali a una porta, ma non viceversa: un canale non può essere collegato a più porte contemporaneamente.

Stato tipo

Non ho trovato una traduzione generalmente accettata in russo del concetto di "stato tipo", quindi lo chiamerò "stati tipo". L'essenza di questa funzionalità è che oltre al consueto controllo del tipo adottato nella digitazione statica, sono possibili ulteriori controlli contestuali in fase di compilazione.
In una forma o nell'altra, gli stati dei tipi sono familiari a tutti i programmatori: secondo i messaggi del compilatore, "la variabile viene utilizzata senza inizializzazione". Il compilatore rileva i punti in cui viene letta una variabile che non è mai stata scritta ed emette un avviso. In una forma più generale, questa idea assomiglia a questa: ogni oggetto ha un insieme di stati che può assumere. Ciascuno stato definisce operazioni valide e non valide per quell'oggetto. E il compilatore può verificare se un'operazione specifica su un oggetto è consentita in un punto particolare del programma. È importante che questi controlli vengano eseguiti al momento della compilazione.

Ad esempio, se abbiamo un oggetto di tipo “file”, allora può avere lo stato “chiuso” e “aperto”. Inoltre, un'operazione di lettura da un file non è consentita se il file è chiuso. Nei linguaggi moderni, è comune che la funzione di lettura lanci un'eccezione o restituisca un codice di errore. Un sistema di stato del tipo potrebbe rilevare un errore di questo tipo in fase di compilazione: proprio come il compilatore determina che un'operazione di lettura su una variabile avviene prima di qualsiasi possibile operazione di scrittura, potrebbe determinare che il metodo "Leggi", valido nello stato "file aperto" , viene chiamato prima del metodo “Open”, che trasferisce l'oggetto in questo stato.

Rust ha il concetto di "predicati": funzioni speciali che non hanno effetti collaterali e restituiscono un tipo bool. Tali funzioni possono essere utilizzate dal compilatore per essere chiamate in fase di compilazione allo scopo di verificare staticamente determinate condizioni.

I vincoli sono controlli speciali che possono essere eseguiti in fase di compilazione. A questo scopo viene utilizzata la parola chiave check.
pure fn è_meno_di(int a, int b) -< bool { ret a < b; } fn test() { let x: int = 10; let y: int = 20; check is_less_than(x,y); }
I predicati possono essere “appesi” ai parametri di input delle funzioni in questo modo:
fn test(int x, int y) : è_meno_di(x,y) ( ... )

Ci sono pochissime informazioni sullo stato tipografico, quindi molti aspetti non sono ancora chiari, ma il concetto è comunque interessante.

È tutto. È del tutto possibile che mi siano ancora sfuggiti alcuni punti interessanti, ma l'articolo era già gonfio. Se lo desideri, ora puoi creare un compilatore Rust e provare a giocare con vari esempi. Le informazioni sull'assemblaggio sono fornite all'indirizzo


Ci è piaciuto molto l'articolo "Critica del linguaggio Rust e perché C/C++ non morirà mai". Abbiamo suggerito all'autore di tradurre l'articolo in inglese e di pubblicarlo anche sul nostro blog. Ha accettato e siamo lieti di presentare questo articolo in russo e inglese. Si trova l'articolo originale.

Viene pubblicato l'articolo originale (testo in russo). L'articolo è stato pubblicato sul nostro blog con il consenso dell'autore.

Nota: di seguito presumo che Rust sia un tentativo di creare un linguaggio veloce e sicuro. Dopotutto, i ragazzi di Mozilla lo hanno realizzato come strumento di sviluppo del motore del browser. Se questo è solo un altro linguaggio sicuro, allora otteniamo qualcosa di strano. Esistono già una dozzina di lingue sicure diverse, ognuno troverà qualcosa di suo gradimento. E se l'obiettivo non è sostituire il C++, allora (1) perché nel linguaggio viene creato un sottoinsieme non sicuro? (2) perché è stato necessario rimuovere i flussi leggeri dal linguaggio? Non è conveniente? In altre parole, in questo caso, ciò che sta accadendo non ha alcun senso.

Se stai leggendo il forum linux.org.ru, noterò che questo non è l'elenco dei 10 motivi puramente tecnici per non apprezzare Rust discusso in questo thread. Come dimostrato da una discussione su Skype con caro compagno @sum3rman, c'è più di una opinione su quanto “tecniche” debbano essere considerate queste ragioni. In generale, ho stilato un elenco scadente, ma probabilmente rischierò comunque di citarne alcuni dei punti più interessanti. In effetti, ci sono molte ragioni semplici e non tecniche qui.

Il fatto che C/C++ non andrà da nessuna parte nel prossimo futuro è chiaro a qualsiasi persona sobria. Nessuno riscriverà quasi tutte le applicazioni desktop, i kernel del sistema operativo, i compilatori, i motori di giochi e browser, le macchine virtuali, i database, gli archiviatori, i codec audio e video, tonnellate di altre librerie basate su C e così via. Si tratta di un sacco di codice veloce, sottoposto a debug e testato nel tempo. Riscriverlo è molto, molto costoso, rischioso e, a dire il vero, ha senso solo nella coscienza distorta dei fan più ostinati di Rust. La richiesta di programmatori C/C++ è stata e sarà grande per molto tempo.

Ok, che ne dici di usare Rust quando scrivi un nuovo codice?

Ricordiamo che questo non è il primo tentativo di realizzare un C/C++ “più corretto”. Prendiamo ad esempio la lingua D. Apparsa nel 2001, è una lingua molto buona. Non ci sono posti vacanti, né normali strumenti di sviluppo, né storie di successo particolarmente eccezionali. Il progetto OpenMW è stato originariamente scritto in D, ma poi all'improvviso hanno deciso di riscriverlo interamente in C++. Come ammettono gli sviluppatori, hanno ricevuto molte lettere nello stile di "grande progetto, saremmo felici di contribuirvi, ma non sappiamo e non vogliamo conoscere questo stupido D." Wikipedia riporta che oltre a D, ci sono stati molti altri tentativi di uccidere C++ in un modo o nell'altro, ad esempio Vala, Cyclone, Limbo, BitC. Quante persone hanno sentito parlare di queste lingue?

Penso che sia giunto il momento di imparare dalla storia. Nessuna persona sana di mente trascinerà una nuova lingua in un progetto finché non gli mostrerai almeno i normali strumenti di sviluppo, non gli racconterai un paio di storie di successo e non gli mostrerai una dozzina di programmatori in questa lingua che vivono nelle vicinanze. I programmatori, forse, ad eccezione dei più giovani, non perderanno mai tempo e salute nell'apprendimento del prossimo linguaggio più corretto finché non verranno mostrati normali strumenti di sviluppo (non artigianali come Racer), un paio di decine di migliaia di librerie già pronte ( non “sperimentale”, “instabile” e così via), non raccontano un paio di storie di successo e mostrano una dozzina di posti vacanti aperti nella loro città. Problema dell'uovo e della gallina. Molto raramente questo problema può essere risolto con successo (con riserva, Scala può essere citata come esempio), principalmente a causa dell'investimento di tempo e denaro da parte di qualche grande azienda (Google, Typesafe), per qualche motivo interessata a divulgare il lingua.

Come ho già notato, le sole ragioni non tecniche sono più che sufficienti. Tuttavia, per pura curiosità, proviamo a immaginare per un secondo che non ci siano. Allora non c'è motivo di non scrivere in Rust? Si scopre che anche questa è almeno una domanda molto grande.

C/C++ è criticato per varie cose. A proposito, molto spesso le critiche vengono mosse da coloro che non hanno nemmeno visto il codice C++ in produzione anche da lontano. Il problema può essere brevemente e chiaramente descritto così: il C++ è molto veloce (e anche poco impegnativo in termini di memoria, carica della batteria, ecc.), ma non sicuro nel senso che permette di oltrepassare i confini degli array, accedendo erroneamente pezzi di memoria liberati e così via. Un tempo, questo problema ha portato alla nascita di una massa di linguaggi sicuri, come Java, C#, Python e altri. Ma si è scoperto che questi linguaggi, rispetto al C++, richiedono troppo risorse e presentano altri svantaggi, ad esempio l'inevitabile arresto del mondo durante la raccolta dei rifiuti. Pertanto, le persone sono alle prese con il compito di creare un linguaggio veloce come il C++, ma anche sicuro. Uno di questi linguaggi è Rust.

La ruggine è davvero sicura, ma sfortunatamente è tutt’altro che veloce. Al momento in cui scrivo, Rust è paragonabile in velocità a Java, Go e Haskell:

Spero sinceramente che col tempo venga in qualche modo overcloccato, ma fino ad allora, in termini di velocità e compromessi di sicurezza, non è molto più interessante di Scala o Go. La questione rimane ancora aperta se sia possibile rendere un linguaggio veloce e sicuro, o se i controlli costanti per superare i limiti dell'array, i collegamenti sicuri attorno ai collegamenti alle librerie C e così via rendano automaticamente qualsiasi linguaggio 2 volte più lento di C/ C++.

Cosa rende Rust sicuro? In termini semplici, è un linguaggio con un analizzatore di codice statico integrato. Un analizzatore statico davvero molto interessante che rileva tutti gli errori tipici del C++, non solo quelli legati alla gestione della memoria, ma anche al multithreading. Ho passato un collegamento a un oggetto mutabile a un altro thread tramite un canale e poi ho provato a utilizzare questo collegamento da solo: non è stato compilato. E `veramente forte.

Si sostiene spesso che solo il 10% del codice viene eseguito il 90% delle volte (il che, per quanto ho capito, è puramente una regola pratica: non sono riuscito a trovare rapidamente alcuna ricerca rigorosa su questo argomento). Pertanto, la maggior parte del programma può essere scritta in Rust sicuro, con il 10% del codice attivo scritto nel sottoinsieme unsafe, e la lentezza dell'attuale implementazione di Rust non è realmente un problema. Ok, ma poi si scopre che Rust non è affatto necessario, perché posso scrivere il 90% del codice in Go e il 10% in C. Solo i cercatori di soluzioni miracolose e i teorici fuori dal mondo useranno Rust esclusivamente per il motivo che il 100% del programma può essere scritto in una lingua. Anche se in realtà si tratta di due dialetti della stessa lingua, il che non è poi così diverso dalla combinazione Java più C o Go più C.

In effetti, la regola delle 10:90 è ancora una bugia. Con questa logica, potresti riscrivere il 90% di WebKit, il 90% di VirtualBox o il 90% di GCC in Java e ottenere lo stesso risultato. Ovviamente, non è questo il caso. Anche se il punto non è che in alcuni programmi questo atteggiamento è molto diverso, allora guardati le mani. Supponiamo che l'intero programma sia scritto in C/C++ non sicuro e che il suo tempo di esecuzione, relativamente parlando, sia pari a 0,9*1 (una piccola parte di codice caldo) + 0,1*1 (molto codice freddo) = 1. Ora confrontatelo con un programma in linguaggio sicuro con inserti in Si: 0.9*1 + 0.1*2 = 1.1, circa il 10% della differenza. È molto o poco? Dipende dalla tua scala. Nel caso di Google anche una piccola percentuale può risparmiare milioni di dollari (vedi punto 5 del documento “Utilizzo”). Oppure immagina che con il prossimo aggiornamento la JVM inizi improvvisamente a richiedere il 10% di risorse in più! Ho paura anche solo di indovinare quanti zeri ci saranno nella cifra ottenuta dopo aver convertito gli interessi in denaro americano! Il 10% è molto nelle attività in cui vengono utilizzati C e C++.

Ripetiamo come un mantra “l’ottimizzazione prematura è la radice di tutti i mali”. Ma se lo prendiamo alla lettera, usiamo il bubble sort invece del quicksort ovunque. Non sappiamo per certo se il programma rallenterà in questo particolare posto! Che senso ha avvolgere i contatori ordinari di alcune azioni negli attori o nella memoria transazionale se puoi utilizzare immediatamente l'atomico più efficiente? E in generale, in casi banali non ha senso inizializzare forzatamente tutte, tutte, tutte le variabili, eseguire una serie di controlli aggiuntivi e così via. Alla fine non avremo un'accelerazione del 10%, ma del 2-5%. Anche questo non è affatto male, se richiedesse solo un paio di minuti in più di riflessione. E come abbiamo già scoperto, nei problemi risolti in C/C++, questa può fare una grande differenza! Allora, chi ha detto che trovare un hot spot, riscrivere il codice (possibilmente molto codice) e dimostrare che è davvero più veloce sia più facile che pensare in anticipo alle prestazioni?

Se ignoriamo la questione del compromesso velocità-sicurezza, ho anche domande sulla progettazione del linguaggio stesso. In particolare, per quanto riguarda i cinque tipi di puntatori. Da un lato, ciò non è male se il programmatore pensa a dove si trovano le variabili, nello stack o nell'heap, e se più thread possono o meno lavorare con esse contemporaneamente. Ma d'altra parte, immagina di scrivere un programma e si scopre che la variabile non dovrebbe vivere nello stack, ma nell'heap. Riscrivi tutto per usare Box. Quindi capisci che ciò di cui hai veramente bisogno è Rc o Arc. Riscrivi di nuovo. E poi lo riscrivi di nuovo in una variabile regolare nello stack. Tutto questo senza un normale IDE a portata di mano. E i giochi normali non aiutano. Beh, o semplicemente nello stile di "Vec" >>>", ciao Java! Ma la cosa più triste è che il compilatore conosce già la durata di tutte le variabili, potrebbe generare automaticamente tutti questi Box, Arc e così via. Ma per qualche motivo questa parte del lavoro viene trasferita al programmatore. Molto più comodo sarebbe facile scrivere val (nel terzo millennio!), e dove necessario indicare esplicitamente Box o Rc. Gli sviluppatori di Rust in questo senso hanno rovinato l'intera idea.

Proprio per questo motivo il campo di applicazione di Rust è notevolmente ristretto. Nessuno sano di mente scriverebbe web e lato server in un linguaggio del genere. Soprattutto considerando che non offre vantaggi significativi rispetto agli stessi linguaggi sotto JVM. E andare con i normali fili leggeri (non futuri) sembra molto più attraente per questi compiti. Con i futuri, per non spararsi la zappa sui piedi, bisogna comunque imparare a lavorare, e si dice “linguaggio sicuro”. Sì, questi linguaggi hanno le loro caratteristiche, fermano il mondo allo stesso modo, ma questo problema può essere risolto sia tagliando i microservizi che con altre tecniche. E sì, nessuno tradurrà Rust in JavaScript, scriverà script per il layout in AWS o lo utilizzerà come linguaggio di query per MongoDB. È anche improbabile che scrivano per Android, ma per un motivo diverso: esiste molto più di un'architettura ed è molto più semplice con la JVM. Se all'improvviso hai pensato che Rust fosse "adatto a tutti i compiti", devo deluderti.

Bene, per concludere:

  • Le macro sono un backup dell'eccessiva verbosità causata dalla mancanza di normali eccezioni. Ho già scritto dei problemi della metaprogrammazione, in particolare, per questo motivo difficilmente vedremo un normale IDE per Rust. E non ne sono sicuro, ma sembra che le macro in Rust non abbiano nemmeno spazi dei nomi.
  • Le persone sono idiote e cargo incoraggia davvero a estrarre i pacchetti direttamente dai repository git, aggirando Crates.io. Di conseguenza, c'è un'alta probabilità di finire con i pacchi nello stesso pasticcio che nel mondo di Erlang con il suo Rabar, mentre nel mondo di Go sembra che sia la stessa situazione.
  • Come molti nuovi linguaggi, Rust intraprende la strada della semplificazione. In generale, capisco perché non esiste un'eredità normale ed eccezioni, ma il fatto stesso che qualcuno decida queste cose per me lascia un retrogusto sgradevole. Il C++ non pone limiti al programmatore in termini di cosa usare e cosa non usare.
  • Se dovessimo seguire la strada della semplificazione, dovremmo eliminare tutte queste estensioni linguistiche. Altrimenti si scopre che, come nel mondo di Haskell, ogni programmatore scrive nel proprio dialetto.
  • I puntatori intelligenti, semmai, sono tutt'altro che gratuiti e non portano a tempi di raccolta dei rifiuti prevedibili. Qualche thread ha improvvisamente l'onore di liberare una struttura dati molto profonda. Mentre cammina nel labirinto degli anelli morti, i fili che dipendono da lui pazientemente diventano stupidi. Lo stesso problema esiste a Erlang con i suoi piccoli gruppi, l'ho osservato io stesso più di una volta. Anche i puntatori intelligenti hanno i loro problemi, la stessa frammentazione e perdite di memoria. Ho dimenticato il vikpointer nella struttura ciclica, tutto qui. E questo in un linguaggio che pretende di essere sicuro. Se desideri un tempo GC prevedibile, studia il comportamento della tua applicazione sotto carico e agisci (ricorda gli stessi pool di oggetti) se il tempo GC non ti soddisfa oppure gestisci la memoria manualmente.
  • Qualcuno ha visto una descrizione rigorosa della semantica di Rust? Ha almeno un modello di memoria? Anche per me un linguaggio “sicuro” che “dimostra la correttezza” dei programmi, che può effettivamente interpretare il codice sorgente in dieci modi diversi, ah!
  • Non posso fare a meno di ricordartelo ancora una volta Il problema sono quasi sempre le persone, non la tecnologia.. Se ti ritrovi con un codice C++ scadente o Java improvvisamente rallenta, non è perché la tecnologia sia pessima, ma perché non hai imparato a usarla correttamente. Anche tu non sarai soddisfatto di Rust, ma per ragioni diverse. Non sarebbe più semplice imparare a usare e ad amare strumenti più diffusi?

In generale, nei prossimi 5 anni preferirei investire il mio tempo nell'apprendimento del C/C++ piuttosto che di Rust. C++- questo è uno standard del settore. In questa lingua da più di 30 anni un'ampia varietà di problemi viene risolta con successo. E Rust e altri simili sono giocattoli incomprensibili con un futuro vago. Si parla della morte imminente del C++ almeno dagli anni 2000, ma la scrittura in C/C++ è iniziata niente meno che in questo periodo. Piuttosto il contrario. E vediamo che il linguaggio si sta sviluppando (C++11, C++14), appaiono nuovi strumenti (ricordiamo CLion e Clang) e ci sono semplicemente molti posti vacanti corrispondenti.

Un programmatore C++ può sempre trovare facilmente un lavoro con uno stipendio più che dignitoso e, se necessario, riqualificarsi rapidamente in Rust. Il contrario è molto, molto dubbio. A proposito, la lingua, se non altro, non è l'unico e non il fattore decisivo nella scelta di un nuovo luogo di lavoro. Inoltre, un programmatore C/C++ esperto può facilmente scavare nel codice sorgente PostgreSQL o nel kernel Linux, utilizzare potenti strumenti di sviluppo moderni e avere anche molti libri e articoli a sua disposizione (ad esempio, su OpenGL).

Prenditi cura del tuo tempo e della tua salute, non ne hai tanto quanto pensi!



Ciao, cari lettori!

La vita non si ferma e O"Reilly ha pensato di pubblicare il primo libro fondamentale sul linguaggio di programmazione Rust:

Interessati a questo argomento, abbiamo deciso di mettere in discussione la traduzione di un articolo di revisione sul linguaggio Rust, pubblicato nel dicembre 2014. L'articolo è stato leggermente abbreviato perché alcuni passaggi sono già obsoleti, ma l'autore esamina attentamente questo linguaggio nel contesto delle alternative esistenti, sottolineandone i vantaggi (incondizionati) e gli svantaggi (condizionati).

Tuttavia, per renderlo ancora più interessante, lasciamo nei commenti a questo articolo un collegamento a un altro articolo su Rust, pubblicato in uno dei nostri blog di programmazione in lingua russa preferiti. Per cominciare, vai a cat.

Disclaimer: il gusto per i linguaggi di programmazione è una questione molto soggettiva, proprio come questo post. Prendetela con sano scetticismo.

Recentemente sono emersi diversi nuovi linguaggi di programmazione. Tra questi, ero particolarmente interessato a Rust. Di seguito condividerò le mie impressioni su Rust e lo confronterò con molti altri linguaggi di programmazione.

Barriera all'apprendimento di Rust

Non ho conosciuto Rust al primo tentativo. Esistono diversi ostacoli all’apprendimento di questa lingua, tra cui:

  1. La lingua sta cambiando rapidamente. Non esiste un “dittatore benigno per la vita” in Rust. Il linguaggio si evolve attraverso il contributo dei membri del team principale e della comunità.
  2. Considerando il primo punto, I tutorial su Rust sono molto scarsi. C'è un manuale, altra documentazione ufficiale e il sito Rust by example sono ottime risorse. Tuttavia, Rust è molto più complesso. Spesso devi setacciare RFC, blog e persino commenti su Github per trovare le informazioni di cui hai bisogno, e anche se queste informazioni sono apparse solo ieri, non ne sei ancora del tutto sicuro. Non vedo l'ora di leggere un buon libro autorevole su Rust, anche se scommetto che sarà lungo.
  3. Il sistema di proprietà di Rust e il meccanismo di controllo dei prestiti possono creare confusione per i principianti. Per garantire la sicurezza della memoria senza la garbage collection, Rust utilizza un intricato sistema di prestito e proprietà. Spesso spaventa i neofiti.
  4. Il compilatore Rust è molto severo. Chiamo Rust un linguaggio disciplinare. Tutto ciò che non è completamente ovvio per il compilatore Rust deve essere specificato tu stesso, e alcune delle tue intenzioni potresti non essere nemmeno a conoscenza all'inizio. Questa barriera di apprendimento, insieme a tutte le altre, spesso si traduce in una prima impressione scoraggiante di Rust.

Vantaggi

La ruggine ha molti vantaggi. Alcuni di loro sono unici.

Sicurezza della memoria senza garbage collection

Questo è forse il risultato più importante di Rust. Nei linguaggi di programmazione di basso livello che consentono la manipolazione diretta della memoria, errori come use-after-free o perdite di memoria in fase di esecuzione sono piuttosto costosi. Nel moderno C++, la capacità di gestire tali problemi è migliorata, ma richiede una rigorosa disciplina tecnica (leggi: i programmatori continuano a eseguire operazioni non sicure). Di conseguenza, a mio avviso, in generale, il C++ non può risolvere questo problema in modo fondamentale e affidabile.

È vero che i programmatori Rust possono scrivere codice non sicuro in un blocco non sicuro, ma (1) questo viene fatto deliberatamente e (2) i blocchi non sicuri possono costituire solo una parte molto piccola dell'intero codice base, ma sono strettamente controllati.
Il Garbage Collector è lo strumento di sicurezza della memoria più comune. Se vai d'accordo con GC, hai alcune opzioni. Tuttavia, il sistema di proprietà di Rust garantisce non solo la sicurezza della memoria, ma anche la sicurezza dei dati e delle risorse (vedi sotto)

RAII e risorse

RAII (acquisizione di risorse è inizializzazione) è un termine strano, ma rende bene l'idea. Su Wikipedia leggiamo che RAII funziona con oggetti allocati sullo stack. Il sistema di proprietà di Rust consente di applicare questo principio anche agli oggetti allocati nell'heap. Ciò rende il rilascio automatico delle risorse, ad esempio memoria, file, socket, altamente prevedibile e garantito in fase di compilazione.
Linguaggi dinamici come Python o Ruby hanno capacità simili, ma non corrispondono alla potenza di Rust IMO.

Competitività senza corsa ai dati

Rust garantisce la sicurezza dei dati durante la programmazione simultanea, ovvero garantisce che solo molti lettori o uno "scrittore" possano accedere ai dati in un dato momento.

Tipo di dati algebrici

Oltre ai tipi regolari (tuple e strutture), Rust fornisce anche tipi di enumerazione (qui chiamati “tipi di somma” o “tipi di variante”) e modelli di corrispondenza. È sorprendente che un linguaggio di programmazione di sistema abbia un sistema di tipi così sviluppato.

Composizione sull'eredità

Rust favorisce chiaramente la composizione del tipo rispetto all'ereditarietà. Sono nel campo in cui questo fatto è considerato una vittoria. Quando Rust supporta i tipi generici, i tratti giocano un ruolo chiave.

Svantaggi (condizionale)

Tutto deve essere molto chiaro

La ruggine è un linguaggio disciplinato. Il compilatore deve comunicare tutto in modo molto chiaro, altrimenti giurerà finché non ci saranno più punti poco chiari. Ciò generalmente va a vantaggio della qualità del codice, ma può essere eccessivo quando si tratta di prototipazione rapida o attività una tantum.

Di conseguenza: devi scrivere un codice migliore e più chiaro in Rust. Una volta compreso questo, gli spigoli possono più o meno scomparire.

La raccolta dei rifiuti è secondaria

Rust ha un garbage collector molto semplice: Rc, un conteggio dei riferimenti, e Arc, un conteggio dei riferimenti atomici senza rilevamento round robin. Tuttavia, queste funzionalità non funzionano nella lingua per impostazione predefinita e dovrai utilizzare i meccanismi di gestione della memoria standard di Rust (Stack, & e Box) più spesso. Se i problemi di memoria nella tua applicazione non sono significativi, allora dovrai tollerare il modello di sicurezza della memoria di Rust, che non utilizza la garbage collection.

L’espressività non è fine a se stessa

Il linguaggio Rust non si preoccupa dell'espressività o della bellezza del codice. Sicuramente non è male in questo senso, ma non è così meraviglioso come potresti desiderare che sia.

Barriera all'ingresso relativamente alta

In linea di principio, Rust non è uno di quei linguaggi che puoi padroneggiare rapidamente e scrivere codice professionale in poche settimane. Rust è forse più compatto del C++, ma è decisamente più grande di molti linguaggi di programmazione. Rispetto ad altre lingue, non può essere definito molto accessibile. Questo può essere un problema se la tua priorità è la velocità di acquisizione della lingua.

Rust e altri linguaggi

Linguaggi dinamici

I linguaggi dinamici (di scripting) si trovano all'estremità opposta dello spettro dei linguaggi di programmazione rispetto a Rust. Rispetto a Rust, scrivere codice in linguaggi dinamici è solitamente più veloce e più semplice. Penso che i linguaggi dinamici battano Rust in queste situazioni:

  • Prototipazione rapida o attività una tantum
  • Il codice non è per la produzione o uno in cui un errore in fase di esecuzione rappresenta un piccolo problema
  • Progetto proprio (individuale).
  • Lavoro semiautomatico (ad esempio parsing/analisi dei log, elaborazione batch di testi)

In questi casi, non dovresti provare a fare tutto alla perfezione. Al contrario, Rust, secondo me, è più adatto per:

  • Lavora in un team medio o grande
  • Codice orientato all'uso a lungo termine nella produzione
  • Il codice che verrà utilizzato per un lungo periodo richiede una manutenzione regolare e/o un refactoring
  • Codice che scriveresti molti test unitari per garantire la sicurezza

In generale, quando la qualità del codice è fondamentale. I linguaggi dinamici ti aiutano a scrivere il codice più velocemente nella fase iniziale, ma in seguito il lavoro rallenta: devi scrivere più test, la linea di sviluppo viene interrotta o addirittura si verificano interruzioni nella produzione. Il compilatore Rust ti obbliga a fare molte cose correttamente in fase di compilazione, quando è meno costoso identificare e correggere i bug.

Andare

Il confronto tra queste due lingue è un ottimo motivo per discutere, ma poiché le sto studiando da tempo, condividerò comunque qui le mie impressioni soggettive al riguardo. Rispetto a Rust, ecco cosa mi piace di Go:

  • leggero: il linguaggio è piccolo (e semplice, ma molto potente)
  • utilità gofmt – riduce significativamente il carico mentale durante la programmazione
  • routine/canale
  • Compilazione istantanea

Perché ho lasciato Go:

  • È troppo minimalista. Il sistema dei tipi e il linguaggio stesso non sono molto estensibili
  • La programmazione Go mi sembra un po' secca. Mi ricorda i tempi in cui programmavo in Java: buono per lo sviluppo aziendale, meccanico e... non così interessante (promemoria: sui gusti non si discute)
  • La popolarità di Go continua grazie al supporto di Google, ma questo mi rende un po' scettico. Quando gli interessi della comunità e dell'azienda non coincidono, la prima può essere sacrificata. Naturalmente, ogni azienda persegue principalmente i propri interessi. Non c'è niente di sbagliato. È solo... un po' fastidioso. (Molti linguaggi e framework promossi dalle aziende affrontano un problema simile. Almeno Mozilla non dipende dai prezzi delle azioni.)

Nim

Nim (precedentemente chiamato Nimrod) è un linguaggio molto interessante. Si compila in C, quindi le prestazioni sono abbastanza buone. Esteriormente assomiglia a Python, un linguaggio in cui mi è sempre piaciuto programmare. È un linguaggio di garbage collection, ma fornisce un supporto soft in tempo reale e il comportamento del garbage collector stesso è più prevedibile. Ha un sistema di effetti interessante. In linea di principio, mi piace molto questa lingua.

Il problema più grande nel suo caso è l’immaturità dell’ecosistema. Il linguaggio in sé è ben costruito e relativamente stabile, ma attualmente non è abbastanza per garantire il successo di un linguaggio di programmazione. Documentazione, librerie standard, repository di pacchetti, framework di supporto, partecipazione di comunità e terze parti... preparare tutto per la produzione non è facile.

Senza specialisti che completino la lingua a tempo pieno, quest’ultima fase può essere molto estenuante. Tra i nuovi linguaggi di programmazione, Nim non può ancora vantare un supporto serio.
Detto questo gli auguro successo e continuo a seguirlo.

Altri

Esistono altre lingue come Julia e . Julia è un linguaggio dinamico con buone prestazioni e chiamate fluide in stile C. (Se ti piacciono i linguaggi dinamici e i REPL, presta attenzione). Julia ha conquistato l'attenzione di tutti grazie ai suoi ambiti numerici e scientifici. Anche se ha il potenziale per diventare una lingua di uso generale, mi sembra che lo sviluppo di una lingua sia fortemente influenzato dalla comunità dei suoi originatori.

D, almeno inizialmente, era un tentativo di creare "C++, ma migliore". La sua versione 1.0 è stata rilasciata nel 2007, quindi questo linguaggio non è così nuovo. Questo è un buon linguaggio, ma per ragioni oggettive non ha ancora messo radici: il motivo è la divisione in Phobos/Tango in una fase iniziale, e la garanzia di sicurezza della memoria principalmente attraverso la raccolta dei rifiuti, e il posizionamento iniziale come sostituto di C++.

Perché penso che le possibilità di Rust siano piuttosto alte

Ci sono così tanti nuovi linguaggi di programmazione in uscita in questi giorni. Cosa, secondo me, distingue Rust tra questi? Fornirò le seguenti argomentazioni:

Un vero e proprio linguaggio per la programmazione dei sistemi

L'incorporamento non è un compito facile. Forse può essere risolto letteralmente in diversi linguaggi, o anche solo in due: C e C++. (Questo potrebbe essere il motivo per cui Skylight ha scelto Rust per sviluppare un'estensione per Ruby, anche se era estremamente rischioso.) È notevole il modo in cui Rust è riuscito a eliminare il sovraccarico del tempo di esecuzione. Questo apre una prospettiva unica per Rust.

Senza Nullo

Un oggetto/puntatore nullo (il cosiddetto "bug da un miliardo di dollari") è una fonte comune di errori di runtime. Esistono solo pochi linguaggi di programmazione che non hanno linguaggi nulli, per lo più funzionali. Il punto è che eliminare null richiede un sistema di tipi molto avanzato. In genere, gestire questo problema a livello sintattico del linguaggio richiede un tipo di dati algebrico e una corrispondenza di modelli.

Linguaggio di basso livello con costrutti avanzati di alto livello

Essendo un "linguaggio bare metal" fino al midollo (almeno in teoria), Rust offre anche molte funzionalità di livello relativamente alto, tra cui tipo di dati algebrico, corrispondenza di modelli, tratti, inferenza di tipo e così via.

Comunità forte e rilevanza pratica

La comunità di Rust è molto amichevole e attiva. (Naturalmente questa è un'impressione soggettiva). Inoltre, Rust è stato utilizzato in alcuni progetti pratici seri, in particolare il compilatore Rust, Servo, Skylight, ecc. ancora allo stadio di sviluppo del linguaggio.

Finora, nessun errore grave

A volte, lo sviluppo di un linguaggio o di una struttura all'interno di un'azienda può accidentalmente raggiungere un vicolo cieco. Fortunatamente, il team principale di Rust sta facendo un ottimo lavoro finora. Continua così, Ruggine!

Rust per lo sviluppo web

Se Rust è un linguaggio di programmazione di sistema, è adatto allo sviluppo web? Anche io sto cercando una risposta a questa domanda.

Librerie e framework

Innanzitutto alcune librerie HTTP devono essere pronte per questo. (Questo è descritto sul sito web “Siamo ancora web”). La prima libreria ruggine-http è già obsoleta; il suo potenziale successore Teepee è praticamente in animazione sospesa. Fortunatamente, Hyper sembra un buon candidato. È già stato accettato in Servo, un progetto simbiotico di Rust, che considero una benedizione essere la libreria HTTP per Rust.

La libreria standard Rust non supporta ancora l'I/O asincrono. A questo scopo è possibile utilizzare la libreria esterna mio, che fornisce I/O socket non bloccanti. Il supporto del thread verde è stato rimosso come parte della semplificazione dell'I/O.

Sono in corso di sviluppo diversi framework web per Rust, tra cui Iron e nickel.rs. Potrebbe volerci del tempo prima che la situazione con loro si calmi.

Rust è un linguaggio per il web?

Un giorno le librerie e i framework saranno pronti. La domanda è: Rust stesso è adatto allo sviluppo web? La gestione della memoria di basso livello e le funzionalità di sicurezza di Rust sono troppo complesse?

Penso che alla fine tutto dipenda da cosa ti aspetti dal progetto. Sopra, confrontando Rust con i linguaggi dinamici in progetti a breve termine, ho menzionato che in questi casi la complessità di Rust può essere ingiustificata. Ma se ti aspetti che il prodotto duri a lungo, diciamo sei mesi o più, allora Rust potrebbe essere una buona opzione.

Rust è adatto alle startup web?

E le startup? Richiedono cicli rapidi di prototipazione e sviluppo. Questa è una domanda più controversa, ma resto della mia opinione: se stai guardando un progetto a lungo termine, la scelta del linguaggio di programmazione giusto è importante e Rust merita un'attenzione speciale. Dal punto di vista aziendale, un linguaggio che consente la prototipazione rapida offre vantaggi significativi, mentre il refactoring e l'eliminazione dei colli di bottiglia possono sempre essere rimandati per dopo. La realtà ingegneristica è che il costo del lavoro di refactoring è solitamente più alto di quanto sembri e, anche se si scuotono molti elementi del sistema, il codice scritto molto tempo fa rimarrà comunque in qualche angolo. Per molti anni.

Prova Ruggine!

Puoi aiutare e trasferire alcuni fondi per lo sviluppo del sito



I migliori articoli sull'argomento