som mange utviklere har Jeg vært interessert i Rust for en stund. Ikke bare fordi Det vises i så mange overskrifter På Hacker News, eller på grunn av den nye tilnærmingen språket tar til sikkerhet og ytelse, men også fordi folk ser ut til å snakke om det med en bestemt følelse av kjærlighet og beundring. På Toppen av Det Er Rust av spesiell interesse for meg fordi Den deler noen av de samme målene og funksjonene til mitt favorittspråk: Swift. Siden jeg nylig har tatt deg tid til å prøve Rust i noen små personlige prosjekter, ønsket jeg å ta litt tid til å dokumentere mine inntrykk av språket, spesielt i hvordan Det sammenlignes Med Swift.

Det Store Bildet

Rust og Swift har mange ting til felles: De er begge kompilerte språk med kraftige, moderne typesystemer og fokus på sikkerhet. Funksjoner som algebraiske typer, og førsteklasses håndtering av valgfrie verdier bidra til å flytte mange klasser av feil fra runtime å kompilere tid i begge disse språkene.

så hvordan er disse språkene forskjellige? Den beste måten jeg kan karakterisere forskjellen er:

Swift gjør det enkelt å skrive sikker kode.
Rust gjør det vanskelig å skrive usikker kode.

disse to uttalelsene kan høres ekvivalente, Men det er et viktig skille. Begge språk har verktøy for å oppnå sikkerhet, men de gjør forskjellige avveininger for å oppnå Det: Swift prioriterer ergonomi på bekostning av ytelse, Mens Rust prioriterer ytelse på bekostning av ergonomi.

Avveiningen: Ytelse vs Ergonomi

den største måten denne forskjellen i prioritet er demonstrert, er i tilnærmingen disse språkene har til minnehåndtering. Jeg begynner Med Rust fordi språkets tilnærming til minnehåndtering er en av de unike salgsargumentene.

i Rust styres minnet primært statisk (ja det finnes andre moduser for minnehåndtering som referansetelling, men vi ignorerer dem for nå). Hva dette betyr er at Rust-kompilatoren analyserer programmet ditt, og i henhold til et sett med regler bestemmer når minnet skal tildeles og slippes ut.

For å levere sikkerhet bruker Rust en ny strategi kalt lånekontroll. Måten dette fungerer i praksis er at, som programmerer, hver gang du passerer rundt en variabel (dvs. en referanse til en minneplassering), må du angi om referansen er foranderlig eller uforanderlig. Kompilatoren bruker deretter et sett med regler for å sikre at du ikke kan mutere et enkelt minne på to steder samtidig, noe som gjør det beviselig at programmet ikke har dataløp.

denne tilnærmingen har noen svært fordelaktige egenskaper med hensyn til minnebruk og ytelse. Lånekontroll kan være svært parsimonious med minne, siden det generelt unngår kopieringsverdier. Det unngår også ytelsen overhead av en løsning som søppelrydding, siden arbeidet blir gjort på kompileringstid i stedet for kjøretid.

det kommer Imidlertid med noen ulemper så langt som brukervennlighet. På grunn av naturen av eierskap I Rust, er det noen designmønstre som rett og slett ikke fungerer I Rust. For eksempel er det ikke trivielt å implementere noe som en dobbeltkoblet liste eller en global variabel. Dette blir sannsynligvis mer intuitivt med tiden, og det er løsninger for disse problemene, Men Rust pålegger absolutt begrensninger på programmereren som ikke er til stede på andre språk.

Selv om Det ikke er så ofte snakket Om Som Rust, Har Swift også en interessant historie når det gjelder minnehåndtering.

Swift har to grunnleggende typer variabler: referansetyper og verdityper. Generelt er referansetyper heap-allokert, og styres av referansetelling. Dette betyr at ved kjøring spores antall referanser til et referansetellt objekt, og objektet fordeles når tellingen når null. Referanse telling I Swift er alltid atomic: dette betyr at hver gang en referanse teller endringer, det må være en synkronisering mellom ALLE CPU tråder. Dette har fordelen av å eliminere muligheten for at en referanse blir feilaktig frigjort i en multi-threaded applikasjon, men kommer til en betydelig ytelseskostnad da CPU-synkronisering er veldig dyr.

Rust har også verktøy for referansetelling og atomreferansetelling, men disse er opt-in i stedet for å være standard.

Verdityper, derimot, er stack-allokert generelt, og deres minne styres statisk. Oppførselen til verdityper I Swift er imidlertid mye forskjellig fra Hvordan Rust håndterer minne. I Swift, verdityper har det som kalles «kopier-på-skriv» atferd kopieres som standard, noe som betyr at hver gang en verditype skrives til en ny variabel, eller sendes til en funksjon, en kopi er gjort.

Copy-on-write Kopiering som standard oppnår noen av de samme målene for lånekontroll: som programmerer trenger du vanligvis aldri å bekymre deg for en verdi som endres mystisk på grunn av uventet bivirkning andre steder i programmet. Det krever også litt mindre kognitiv belastning enn lånekontroll, siden det er hele klasser av eierskapsrelaterte kompileringsfeil i Rust som ganske enkelt ikke eksisterer i Swift. Men det kommer til en pris: de ekstra kopiene krever ekstra minnebruk og CPU-sykluser for å fullføre.

I Rust er det også mulig å kopiere verdier som en måte å stille lånekontrollfeil på, men dette legger til visuell støy da kopier må spesifiseres eksplisitt.

Så Her har Vi et godt eksempel på avveininger gjort av disse to språkene: Swift gir deg noen brede forutsetninger om hvordan minne skal håndteres samtidig opprettholde et sikkerhetsnivå. Det er litt som hvordan En c++ programmerer kan håndtere minne i henhold til beste praksis før du gir mye tanke på optimalisering. Dette gjør det veldig enkelt å hoppe inn og skrive kode uten å gi mye tanke til lavt nivå detaljer, og også å oppnå noen grunnleggende kjøretidssikkerhet og korrekthet garanterer at du ikke ville komme på et språk som Python eller Golang. Men det kommer med noen ytelsesklipper, som det er lett å falle av uten å innse det før du kjører programmet. Det er mulig å skrive Swift-Kode med Høy ytelse, men dette krever ofte nøye profilering og optimalisering for å oppnå.

Rust, derimot, gir deg mange spesifikke verktøy for å spesifisere hvordan minne skal administreres, og legger deretter noen harde restriksjoner på hvordan du bruker dem for å unngå usikker oppførsel. Dette gir deg veldig fine ytelsesegenskaper rett ut av esken, men det krever at du tar på seg den ekstra kognitive overhead for å sikre at alle reglene følges.

min takeaway fra dette har vært at mens disse språkene har noen felles mål, har de fundamentalt forskjellige egenskaper som egner seg til forskjellige brukssaker. Rust, for eksempel, synes det klare valget for noe som innebygd utvikling, hvor optimal bruk av minne og CPU-sykluser er ekstremt viktig, og hvor kodekompileringssløyfen kan være tregere, så det er verdifullt å fange alle mulige problemer ved kompileringstid. Mens Swift kan være et bedre valg for noe som datavitenskap eller serverløs logikk, hvor ytelse er en sekundær bekymring, og det er verdifullt å jobbe nærmere problemdomenet uten å måtte vurdere mange detaljer på lavt nivå.

I alle fall vil jeg være veldig interessert i å følge begge disse språkene i fremtiden, og jeg vil følge dette innlegget med flere observasjoner om sammenligningen mellom Swift og Rust.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert.