D (programmeringsspråk)

D
programmeringsspråk
ForfatterWalter Bright , Andrei Alexandrescu
Opprinnelsesdato2001 [1]
Siste versjon2.086.0 [2]
Paradigmerfunksjonell programmering , imperativ programmering og objektorientert programmering
Vanlige utvidelser.d
Påvirket avC, C ++, C #, Eiffel, Java, Python, Ruby
Det påvirketMiniD, DScript, Vala, Qore, Swift
Referanseimplementering
OperativsystemUnix-lignende (FreeBSD, Linux etc.), Windows, MacOS X og 11
TillatelseGPL / Artistic (DMD frontend),

Boost (standard- og kjøretidsbiblioteker), kilde tilgjengelig (DMD-backend), Fullt åpen kildekode (LDC og GDC)

Nettsteddlang.org

Programmeringsspråket D ble født i desember 1999 fra tankene til Walter Bright .

Det er et objektorientert språk , og kan defineres som en utvikling av C- og C++-språket , og skiller seg fra disse språkene med følgende egenskaper: enklere administrasjon av klasser og maler enn C++, en søppelsamler som i Java , støtte for RTTI ( Runtime type information ), introduksjon av 128- bits heltallstype (ikke brukbar ennå), en moduladministrasjon som ligner på Python i stedet for header-filer, assosiative arrays (i tillegg til den klassiske pekeren - stil , statisk, dynamisk) og mye annet. Den tillater også å kalle opp Windows API og kalle funksjoner skrevet i C (ved å bruke det eksterne nøkkelordet).

For øyeblikket kan du bruke den for Windows , Linux x86 og PPC , macOS , AIX og FreeBSD- systemer via en GCC-kompilatorgrensesnitt kalt GDC . På Windows er det ofte å foretrekke å bruke DMD.

Opprinnelsen til navnet og historien

D er et programmeringsspråk laget av DigitalMars; navnet stammer fra det faktum at det stammer fra en re-engineering av C ++ , noe som gjør det til et språk som skiller seg ut . Målet er å oppnå kraften og den høye ytelsen til lavnivåspråk, men med den store produktiviteten og enkle portabiliteten til høynivåspråk som C , C ++ , C #, Java , Perl , Python , Ruby og lignende. Spesielt reflekterer kompilatorens syntaks og tekniske egenskaper C / C ++ , C # og Java.

Kompilatorfunksjoner

D-kompilatoren er strukturert på en annen måte enn hovedspråkene, og arver styrker og skaper et ekstremt originalt språk. Blant de viktigste funksjonene husker vi

Noen funksjoner

Nestede funksjoner

Som i Pascal kan en funksjon i sin tur inneholde erklæringer om andre funksjoner, samtidig som den respekterer de generelle reglene for omfang for deres bruk. Et eksempel:

void foo () { void A () { B (); // ok C (); // error, C undefined } void B () { void C () { void D () { A (); // ok B (); // ok C (); // ok D (); // ok } } } A (); // ok B (); // ok C (); // feil, C udefinert }

Den innerste funksjonen har tilgang til alle eksterne funksjoner, men en ekstern funksjon kan ikke få tilgang til de interne funksjonene til en intern funksjon. Rekkefølgen på funksjonene er også avgjørende. Et annet eksempel:

void test () { void foo () { bar (); } // feil, bar ikke definert void bar () { foo (); } // ok }

Det kan sees at det gjensidige funksjonsanropet ikke er mulig, siden i kompileringen av foo () er funksjonslinjen ennå ikke definert. Løsningen i D er å bruke delegater (som er forskjellige fra C # delegates):

void test () { void delegat () fp ; void foo () { fp (); } void bar () { foo (); } fp = & bar ; }

En annen funksjon er at en nestet funksjon kan få tilgang til feltene til den eksterne, hvis funksjonen er statisk må feltet også være statisk.

I den eksperimentelle versjonen 2.07 ble reelle lukkinger introdusert i språket.

Funksjonsliteraler

Dette lar deg lage en funksjonspeker eller delegere direkte i et uttrykk, så i stedet for å gjøre dette:

int funksjon ( tegn c ) fp ; // erklære en funksjonspeker void test () { static int foo ( char c ) { return 6 ; } fp = & foo ; }

du kan gjøre det slik:

int funksjon ( tegn c ) fp ; void test () { fp = funksjon int ( char c ) { return 6 ; }; }

Dette gjelder også for delegater, så du kan bruke denne koden:

dobbel test () { dobbel d = 7,6 ; flyte f = 2,3 ; void loop ( int k , int j , void delegat () statement ) { for ( int i = k ; i < j ; i ++) statement (); } loop ( 5 , 100 , delegat { d + = 1 ; } ); loop ( 3 , 10 , delegat { f + = 1 ; } ); returner d + f ; }

Endre størrelse på matriser

Arrays er implementert med nye funksjoner sammenlignet med de i C- og C++-stil (i C ++, men lignende funksjoner er tilgjengelige ved bruk av STL -beholdere ). Gjennom lengdefeltet er det mulig å få tilgang til dimensjonen til en matrise og endre størrelsen på den, uten å ty til dynamisk tildeling som new, malloc og realloc.

int [] array ; while ( 1 ) { c = getinput (); hvis (! c ) bryte ; array . lengde = array . lengde + 1 ; array [ array . lengde -1 ] = c ; _ }

Skjæring

Lar deg opprette en ny referanse til en undergruppe. Syntaksen er:

int [ 10 ] a ; // erklære matrise på 10 int int [] b ; b = a [ 1..3 ]; // a [1..3] er en rekke av 2 elementer, a [1] ea [2] foo ( b [ 1 ]); // ekvivalent med foo (0) a [ 2 ] = 3 ; foo ( b [ 1 ]); // tilsvarende foo (3)

Associative arrays

Også kalt kart eller ordbøker på andre språk, de lar deg knytte verdien av et element i en matrise til en annen type data eller objekt, slik at vi kan ha:

int [ char []] b ; // assosiativ matrise b med ints som er // indeksert av en rekke tegn. // KeyType er char [] b [ "hei" ] = 3 ; // sett verdi assosiert med nøkkelen "hei" til 3 func ( b [ "hei" ]); // pass 3 som parameter til func () ... int * p ; p = ( "hei" i b ); if ( p ! = null ) printf (* p ); b . remove ( "hei" ); ...

Sterke typedefs

La oss vurdere følgende alias:

alias int myint;

Det er mulig å deklarere en funksjon som tar int som et argument og deretter sende den en myint uten at kompilatoren genererer en feil: det vil si at kompilatoren er i stand til å løse aliasreferanser til grunnleggende datatyper.

Hvis du derimot vil at en funksjon bare og alltid skal akseptere en int, og derfor må typedefs betraktes som forskjellige datatyper, kan du bruke typedefs-setningen i stedet for aliaser. For eksempel:

typedef int myint;

Det vil gjøre bruk av myint i en funksjon som aksepterer en int, gi en kompileringsfeil. Det er også mulig å lage typedefs med konstante viste verdier:

typedef int myint = 9718; myint i; // initialisert til 9718

Mixin

En mixin lar deg hente et sett med deklarasjoner fra en spesifisert mal og lagre dem andre steder.

mal Foo () { int x = 5 ; } blande Foo ; struct Bar { mixin Foo ; } void test () { printf ( "x =% d \ n" , x ); // skriver ut 5 { Bar b ; int x = 3 ; printf ( "bx =% d \ n" , b . x ); // skriver ut 5 printf ( "x =% d \ n" , x ); // prints 3 { mixin Foo ; printf ( "x =% d \ n" , x ); // skriver ut 5 x = 4 ; printf ( "x =% d \ n" , x ); // skriver ut 4 } printf ( "x =% d \ n" , x ); // skriver ut 3 } printf ( "x =% d \ n" , x ); // skriver ut 5 }

Dette gjelder også funksjonene:

mal Foo () { void func () { printf ( "Foo.func () \ n" ); } } klasse Bar { mixin Foo ; } klasse Kode : Bar { void func () { printf ( "Code.func () \ n" ); } } void test () { Bar b = ny Bar (); b . func (); // kaller Foo.func () b = ny kode (); b . func (); // kaller Code.func () }

Jeg kan spesifisere typen mal

mal Foo ( T ) { T x = 5 ; } blande Foo ! ( int ); // lag x av typen int

og her er et siste eksempel:

mal duffs_device ( alias id1 , alias id2 , alias s ) { void duff_loop ( ) { if ( id1 < id2 ) { typeof ( id1 ) n = ( id2 - id1 + 7 ) / 8 ; switch (( id2 - id1 ) % 8 ) { case 0 : do { s (); tilfelle 7 : s (); tilfelle 6 : s (); tilfelle 5 : s (); tilfelle 4 : s (); tilfelle 3 : s (); tilfelle 2 : s (); tilfelle 1 : s (); } mens (- n > 0 ); } } } } void foo () { printf ( "foo \ n" ); } void test () { int i = 1 ; int j = 11 ; mixin duffs_device ! ( i , j , delegate { foo (); } ); duff_loop (); // utfører foo () 10 ganger }

Statisk hvis

Den statiske if ble designet for å erstatte forprosessordirektiver. Denne setningen evaluerer et uttrykk på kompileringstidspunktet, uten å opprette et nytt omfang. Et eksempel:

const int i = 3 ; int j = 4 ; statisk hvis ( i == 3 ) // ok, ved modulomfang int x ; klasse C { const int k = 5 ; statisk hvis ( i == 3 ) // ok int x ; ellers lang x ; statisk hvis ( j == 3 ) // feil, j er ikke en konstant int y ; statisk hvis ( k == 5 ) // ok, k er i gjeldende omfang int z ; } mal INT ( int i ) { static if ( i == 32 ) alias int INT ; else static if ( i == 16 ) alias kort INT ; else static assert ( 0 ); // støttes ikke } INT ! ( 32 ) a ; // a er en int INT !( 16 ) b ; // b er en kort INT ! ( 17 ) c ; // feil, statiske påstandsturer

Følgelig er det også en statisk påstand. I D er det måter å utføre enkle kompileringstidsfunksjoner, ved å bruke normal syntaks, uten å ty til maler som i C ++.

Identitetsuttrykk

Den lar deg sjekke identiteten til to objekter med is or! Is-operatoren (som ikke er er). Sjekk deretter, for eksempel for objekter, om de er samme instans, for arrays om de inneholder de samme elementene, etc. Den brukes hovedsakelig til homogenitetssjekk mellom 2 objekter.

Implisitt Type Inference

Ved å bruke auto kan en variabeltype gjøres implisitt i en oppgave.

statisk x = 3 ; // x er typen int auto y = 4u ; // y er typen uint auto s = "streng" ; // s er typen char [6] klasse C { ... } auto c = ny C (); // c er et håndtak til en forekomst av klasse C

Kontraktsprogrammering

Kontraktsprogrammering er flott for å unngå feil. En betingelse sjekkes ved inngang til funksjonen og ved utgang, deretter sjekkes et krav for å utføre kroppen, og returnerer resultatet bare hvis betingelsen er sann. Det er også til stede på Eiffel -språket

long square_root ( long x ) in { assert ( x > = 0 ); } ut ( resultat ) { hevde (( resultat * resultat ) == x ); } body { returnere matematikk . sqrt ( x ); }

Det er også mulighet for å definere klasseinvarianter, som kontrolleres utenfor metodene. Det vil si attributtpåstander som alltid må sjekkes (men denne typen klasseinvarianter håndteres fortsatt ikke best i nærvær av arv).

Enhetstest

De er nyttige for å sikre at koden fungerer. Faktisk unngår den, når den brukes til å teste klasser, å måtte lage en kildefil med i main (), instansiere klassen, bruke den. Det er mulig, i D, å gå frem som følger:

klasse Sum { int add ( int x , int y ) { return x + y ; } unittest { Sum sum = ny Sum ; hevde ( sum.add ( 3 , 4 ) == 7 ) ; _ hevde ( sum.add ( -2 , 0 ) == -2 ) ; _ _ } } void main () { }

For å kjøre slike enhetstester, må du gi kompilatoren parameteren -unittest

Omfangserklæring

Den brukes til å utføre en funksjon ved utgangen av et omfang (uansett om det er feil eller ikke), ved utgangen med feil, og ved utgangen uten feil, her er et eksempel (merk at de utføres i revers, fra bunn til topp):

Et enkelt eksempel er dette:

writef ( "1" ); { writef ( "2" ); scope ( exit ) writef ( "3" ); scope ( exit ) writef ( "4" ); writef ( "5" ); } skrivfln ();

som skriver ut 4321

Dette er et litt mer komplekst eksempel:

klasse Foo { this () { writef ( "0" ); } ~ this () { writef ( "ødelagt" ); } } prøv { scope ( exit ) writef ( "2" ); omfang ( suksess ) writef ( "3" ); auto Foo f = ny Foo (); scope ( feil ) writef ( "4" ); kaste nytt unntak ( "msg" ); scope ( exit ) writef ( "5" ); omfang ( suksess ) writef ( "6" ); scope ( failure ) writef ( "7" ); } catch ( Unntak e ) { } writefln ();

utskrift 0412

Strukturelementjusteringskontroll

Den lar deg spesifisere justeringen av medlemmene i en struktur, med en syntaks som ligner på denne:

align ( 1 ) struct S { byte a ; // plassert ved offset 0 byte [ 3 ] filler1 ; byte b ; // plassert ved offset 4 byte [ 3 ] filler2 ; }

Merknader

  1. ^ Change Log - D Programming Language 1.0 - Digital Mars , på Digital Mars . Hentet 2014-07-25 .
  2. ^ Endre logg - D programmeringsspråk , på D programmeringsspråk . Hentet 2017-07-28 .

Eksterne lenker