Uppräknad typ

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 19 maj 2014; kontroller kräver 12 redigeringar .

Uppräknad typ (förkortad uppräkning , eng.  uppräkning, uppräknad typ ) - i programmeringsdatatyp , vars uppsättning värden är en begränsad lista med identifierare.

Beskrivning och användning

En uppräknad typ definieras som en uppsättning identifierare som ur språksynpunkt spelar samma roll som vanliga namngivna konstanter, men som är associerade med den typen. Den klassiska beskrivningen av en uppräkningstyp i Pascal är följande:

typ Cardsuit = ( klöver , ruter , hjärter , spader ) ;

Här deklareras Cardsuit-datatypen, vars värden kan vara vilken som helst av de fyra listade konstanterna. En typvariabel Cardsuitkan ta ett av värdena clubs, diamonds, hearts, spades, det är tillåtet att jämföra värden av uppräkningstypen för likhet eller olikhet, samt använda dem i urvalssatser (i Pascal - case) som värden som identifierar alternativ.

Användningen av uppräkningar gör det möjligt att göra källkoderna för program mer läsbara, eftersom de tillåter att ersätta "magiska siffror" som kodar vissa värden med läsbara namn.

På grundval av uppräkningar på vissa språk kan typuppsättningar skapas . I sådana fall förstås (och beskrivs) en uppsättning som en oordnad samling av unika värden av en enumtyp.

En uppräknad typ kan användas i deklarationer av variabler och formella parametrar för funktioner (procedurer, metoder). Värden av en uppräknad typ kan tilldelas motsvarande variabler och passeras genom parametrar för motsvarande typer i funktioner. Dessutom stöds alltid jämförelse av uppräknade värden för jämlikhet och ojämlikhet. Vissa språk stöder även andra jämförelseoperatorer för värden av uppräknade typer. Resultatet av att jämföra två uppräknade värden i sådana fall bestäms som regel av ordningen på dessa värden i typdeklarationen - värdet som förekommer tidigare i typdeklarationen anses vara "mindre" än värdet som inträffar senare. Ibland kan en uppräknad typ eller något värdeintervall av en uppräknad typ också användas som en indextyp för en matris. I det här fallet finns det ett element i arrayen för varje värde i det valda intervallet, och den faktiska ordningen på elementen motsvarar ordningen på värdena i typdeklarationen.

Implementering

Normalt, under kompilering, representeras uppräkningsvärden med hjälp av heltal. Beroende på det specifika programmeringsspråket kan en sådan representation antingen vara helt dold för programmeraren eller tillgänglig för honom med hjälp av vissa "lösningar" (till exempel påtvingad konvertering av ett enumtypvärde till ett "heltalstypvärde"), eller till och med kontrolleras av programmeraren (i sådana fall har programmeraren möjlighet att uttryckligen ange vilka siffror alla eller vissa värden av enum-typen kommer att kodas med. Alla alternativ har sina positiva och negativa egenskaper. Å ena sidan berövar möjligheten att använda de numeriska värdena för konstanterna som utgör uppräkningstypen, särskilt när den missbrukas, användningen av dessa typer och skapar risken för fel (när man använder numeriska värden för som det inte finns några motsvarande konstanter i typen). Å andra sidan ger explicit värdehantering några ytterligare funktioner. Till exempel tillåter det att använda enumtyper när du organiserar ett gränssnitt med moduler skrivna på andra språk, om de använder eller returnerar heltalskodade värden från någon fördefinierad uppsättning.

En annan möjlighet som uppräknade typer tillhandahåller på språkimplementeringsnivån är minnesbesparing. Med en liten mängd enumtyp räcker några bitar för att lagra ett värde av denna typ (ovan typ Cardsuitkräver endast två bitar per värde, medan ett standardheltal på de flesta använda arkitekturer tar 32 bitar - 16 gånger mer), och kompilatorn kan använda detta faktum för att kompaktera lagring av data i minnet. Detta kan vara särskilt viktigt om flera värden av enumtyper lagras i en enda post - komprimering av poster vid bearbetning av ett stort antal av dem kan frigöra mycket minne. Kompilatorer implementerar vanligtvis inte den här funktionen, åtminstone inte på senare tid när datorminnet har blivit mycket billigare.

Kritik

Uppräkningstypen är traditionell för utvecklade programmeringsspråk, används ganska brett och tas ofta för given. Men denna typ är inte heller utan kritik från teoretiker och praktiker av programmering. Så när man utvecklade programmeringsspråket Oberon inkluderades uppräknade typer i listan över funktioner som togs bort från språket. Niklaus Wirth , formgivaren av språket, citerade följande skäl:

  • "i ett ökande antal program leder den ogenomtänkta användningen av enums ... till en befolkningsexplosion bland typer, vilket i sin tur inte leder till tydlighet i programmen, utan till ordspråkighet" [1] ;
  • när en enum-typ exporteras av en modul (det vill säga den blir en del av ett gränssnitt ), överträds den allmänna regeln - kommandot typ export exporterar samtidigt alla dess element, medan typexport för alla andra typer döljer dess interna struktur;
  • Ur en programläsbarhetssynpunkt finns det inget som hindrar dig från att bara använda en grupp av meddefinierade namngivna konstanter istället för en uppräknad typ, speciellt i närvaro av språkmekanismer som moduler eller klasser.

Å andra sidan, till exempel i Java , som till en början inte innehöll en uppräknad typ, introducerades denna typ senare av inte bara bekvämlighetsskäl, utan också av tillförlitlighet: problemet med att använda grupper av namngivna konstanter istället för uppräkningar är att det finns Det finns ingen kontroll från kompilatorn vad gäller unikheten hos värdekonstanter, såväl som möjligheten att slumpmässigt tilldela värden till variabler som inte motsvarar någon av dessa konstanter.

Beskrivning av enums på olika språk

Ada

I Ada-språket specificeras uppräkningar med ett nyckelord isföljt av en kommaseparerad lista med värden:

typ Cardsuit är ( klöver , ruter , hjärter , spader );

C och språk med C-liknande syntax

Den ursprungliga K&R -dialekten av C hade inte uppräknade typer, men de lades till i ANSI C- standarden .

enum cardsuit { KLUBBAR , DIAMANTER , HJÄRTA , SPADER };

Dynamiska, svagt skrivna språk med C-liknande syntax (som perl eller JavaScript ) har i allmänhet inga uppräkningar.

C++

C++ enums ärver direkt beteendet hos C enums, förutom att den uppräknade typen i C++ är en riktig typ, och nyckelordet enumanvänds bara när man deklarerar en sådan typ. Om, vid bearbetning av en parameter som är en uppräkning, något värde från uppräkningen inte behandlas (till exempel glömdes ett av uppräkningselementen att behandlas i konstruktionen switch), då kan kompilatorn utfärda en varning om det glömda värdet. [2]

C++11 tillhandahåller en andra, typsäker enumtyp som inte är implicit konverterbar till en integraltyp. Detta definieras av frasen "enum-klass". Till exempel:

enum klass Färg { Röd , Grön , Blå };

En bastyp är en implementering av en viss integraltyp som är tillräckligt stor för att hålla alla listade värden (det behöver inte vara den minsta möjliga typen!). I C++ kan du ange bastypen direkt. Detta tillåter "vidarebefordran" av enums:

enum klass Färg : lång { Röd , Grön , Blå }; // måste matcha storleken och layouten för minnestypen "lång" enum- klass Shapes : char ; // preliminär förklaring. Om värden senare definieras som inte passar i 'char' är detta ett fel. C# enum Cardsuit { klöver , ruter , spader , hjärter } Java

I den ursprungliga Java fanns det inga uppräkningar, istället föreslogs det att använda klasser med statiska konstanter. Eftersom version 5 (1.5) uppräkningar har införts i språket är de en fullfjädrad klass där du kan lägga till ett godtyckligt antal fält och metoder. Enums infördes för att förbättra typsäkerhetskontrollen. [3]

enum Cardsuit { klöver , ruter , spader , hjärter } Kotlin uppräkningsklass Riktning { NORD , SYD , VÄST , ÖST } _

Haskell

I vissa programmeringsspråk (t.ex. Haskell) kan uppräkningar emuleras med hjälp av algebraiska typer . Till exempel är en boolesk typ som innehåller två identifierare för att representera sanningsvärden kodad så här:

data Bool = Falskt | Sann

Nim

typ enumType = enum ett , två , tre var a : enumType = tre var b = två eko a > b

Vala

//Regular enum enum Färger { GRÖN = 1 , BLÅ , RÖD } //Flaggor enum [ Flaggor ] enum Borders { VÄNSTER , HÖGER , TOP , BOTTOM } void draw_borders ( Borders selected_borders ) { // motsvarar: if ((Borders.LEFT & selected_borders) > 0) if ( Borders . LEFT in selected_borders ) { } }

soliditet

pragmatisk soliditet ^ 0.4.4 ; kontrakt SimpleEnum { enum SomeData { DEFAULT , ONE , TWO } SomeData someData ; function SimpleEnum (){ someData = SomeData . DEFAULT ; } function setValues ​​( uint _value ){ require ( uint ( SomeData . TWO ) >= _value ); someData = SomeData ( _värde ); } funktion getValue () konstant returnerar ( uint ){ return uint ( someData ); } }


Anteckningar

  1. N. Wirth. Från Modula till Oberon . Hämtad 17 april 2008. Arkiverad från originalet 19 september 2011.
  2. Uppräkningar i C++ (c++ uppräkningstyper) . Hämtad 20 april 2009. Arkiverad från originalet 16 april 2009.
  3. Enums . Hämtad 13 februari 2008. Arkiverad från originalet 27 februari 2008.