Tildeling er en bindende mekanisme i programmering , der giver dig mulighed for dynamisk at ændre forholdet mellem navnene på dataobjekter (normalt variabler ) med deres værdier. Strengt taget er ændring af værdier en bivirkning af tildelingsoperationen, og i mange moderne programmeringssprog returnerer selve operationen også et resultat (normalt en kopi af den tildelte værdi). På det fysiske niveau er resultatet af en tildelingsoperation at skrive og omskrive hukommelsesceller eller processorregistre .
Opgave er en af de centrale konstruktioner i imperative programmeringssprog , implementeret effektivt og enkelt på von Neumann-arkitekturen , der er grundlaget for moderne computere .
I objektorienterede programmeringssprog er opgavens semantik ret anderledes. For eksempel i Kotlin -sproget kopieres objektet ved tildeling, og i Rust -sproget flyttes objektet (move-semantics), og det gamle bundt bliver ugyldigt.
Logisk programmering tager en anden, algebraisk tilgang. Der er ingen almindelig ("destruktiv") opgave her. Der er kun ukendte, der endnu ikke er blevet beregnet, og tilsvarende identifikatorer til at angive disse ukendte. Programmet bestemmer kun deres værdier, de er selv konstante. Selvfølgelig skriver programmet i implementeringen til hukommelsen, men programmeringssprog afspejler ikke dette, hvilket giver programmøren mulighed for at arbejde med identifikatorer med konstante værdier og ikke med variabler.
Ren funktionel programmering bruger ikke variabler og behøver ikke en eksplicit opgaveerklæring.
Den generelle syntaks for en simpel opgave er som følger:
<udtryk til venstre> <tildelingsoperator> <udtryk til højre>"Udtrykket til venstre" skal efter evaluering føre til placeringen af dataobjektet, til målvariablen, identifikatoren for den hukommelsescelle, som optagelsen vil blive foretaget til. Sådanne referencer kaldes "venstre-værdier" ( engelsk lvalue ). Typiske eksempler på en venstrehåndsværdi er et variabelnavn ( x), en sti til en variabel i navneområde og biblioteker ( Namespace.Library.Object.AnotherObject.Property), en matrixsti med et udtryk i stedet for indekset ( this.a[i+j*k]), men mere komplekse muligheder gives senere i denne artikel.
"Udtrykket til højre" skal på den ene eller anden måde angive den værdi, der skal tildeles dataobjektet. Selv hvis navnet på den samme variabel står til højre som til venstre, fortolkes det således forskelligt - sådanne referencer kaldes "højrehåndsværdier" ( engelsk rvalue ). Det anvendte sprog pålægger udtrykket yderligere begrænsninger : i statisk indtastede sprog skal det altså have samme type som målvariablen, eller en type, der er støbt til den; på nogle sprog (for eksempel C eller Python ), kan en anden tildelingsoperator ( a=b=c) også inkluderes i udtrykket.
Den mest almindelige opgaveoperatør i programmeringssprog er =, :=eller ←. Men speciel syntaks kan ikke introduceres - for eksempel i Tcl :
sæt <målvariabel> <udtryk>Denne notation svarer til at kalde en funktion . På samme måde i gammeldags COBOL :
GIVER 2 MED 2, GI FIRE.Valget af opgavesymbolet er et spørgsmål om kontrovers blandt sprogdesignere. Der er en opfattelse af, at brugen af et symbol =til opgave forvirrer programmører , og rejser også spørgsmålet om at vælge et symbol for sammenligningsoperatøren , hvilket er svært at løse godt .
Således udtalte Niklaus Wirth [1] :
Et velkendt dårligt eksempel er valget af et lighedstegn til at betegne en opgave, som går tilbage til Fortran i 1957 og stadig blindt gentages af en masse sprogudviklere. Denne dårlige idé vælter den ældgamle tradition med at bruge tegnet " = " til at angive en lighedssammenligning, et prædikat, der evalueres til " sandt " eller " falsk ". Men i Fortran begyndte dette symbol at betegne tildeling, tvang til ligestilling. I dette tilfælde er operanderne i en ulige position: den venstre operand, variablen, skal gøres lig med den højre operand, udtrykket. Så x = y betyder ikke det samme som y = x.
Originaltekst (engelsk)[ Visskjule] Et berygtet eksempel på en dårlig idé var valget af lighedstegnet til at betegne opgave. Det går tilbage til Fortran i 1957 og er blindt blevet kopieret af hære af sprogdesignere. Hvorfor er det en dårlig idé? Fordi det vælter en århundrede gammel tradition at lade "=" betegne en sammenligning for lighed, et prædikat som enten er sandt eller falsk. Men Fortran fik det til at betyde overdragelse, håndhævelse af lighed. I dette tilfælde er operanderne på ulige fod: Den venstre operand (en variabel) skal gøres lig med den højre operand (et udtryk). x = y betyder ikke det samme som y = x. [2]Implementeringen af denne holdning af Wirth kan anses for, at i Pascal -sproget , som han er forfatter til, er opgaveoperatøren :=, mens den til sammenligning blot bruges =.
Valget af lighedsoperatørsymbolet på sproget, når det bruges =som en opgave, afgøres af:
Notation af lighed i C == er en kilde til hyppige fejl på grund af muligheden for at bruge tildeling i kontrolkonstruktioner, men på andre sprog løses problemet ved at indføre yderligere begrænsninger.
For eksempel i PL/1 sprogudtrykket :
A = B = Cvariablen Аtildeles den boolske værdi af relationsudtrykket В = С. En sådan notation fører til nedsat læsbarhed og bruges sjældent.
Langt fra altid "intuitiv" (for programmører af imperative sprog) måde at fortolke opgaven på er den eneste sande og mulige.
Ud fra den syntaks, der bruges i imperative sprog, er det ikke altid muligt at forstå, hvordan opgavesemantikken er implementeret, medmindre det er eksplicit defineret i sproget.
For eksempel, i Forth , før tildeling, skal værdien og adressen på en variabel gå ind i datastakken, og dette kan gøres længe før den faktiske tildeling udføres.
Eksempel:
\ Definerer variablen AAA og tildeler den værdien 10 i næste linje VARIABEL AAA 10 AAA!Det samme lidt anderledes:
ti VARIABEL AAA AAA! TvetydighedOvervej et eksempel:
X=2+1Dette kan forstås som "resultatet af beregningen 2+1 (dvs. 3) er tildelt en variabel X" eller som "operationen 2+1 er tildelt en variabel X". Hvis sproget er statisk skrevet , så er der ingen tvetydighed, det løses af typen af variablen X("heltal" eller "operation"). I Prolog er skrivning dynamisk , så der er to tildelingsoperationer: is - tildeling af en tilsvarende værdi og = - tildeling af et mønster. I dette tilfælde:
X er 2 + 1, X = 3 X=2+1, X=3Den første sekvens vil blive genkendt som sand, den anden - falsk.
TekstNår man beskæftiger sig med objekter af store størrelser og kompleks struktur, bruger mange sprog den såkaldte " referencesemantik ". Det betyder, at tildeling i klassisk forstand ikke forekommer, men værdien af målvariablen anses for at være placeret samme sted som værdien af kildevariablen. For eksempel ( Python ):
a = [1, 2, 3] b = a a[1] = 1000Derefter bvil den have en værdi [1, 1000, 3] - simpelthen fordi dens værdi faktisk er værdien af a. Antallet af referencer til det samme dataobjekt kaldes dets kardinalitet, og selve objektet bliver dræbt (ødelagt eller givet til skraldeopsamleren ), når dets kardinalitet når nul. Programmeringssprog på lavere niveau (såsom C ) giver programmøren mulighed for eksplicit at kontrollere, om pointer-semantik eller kopi-semantik bruges.
Operation substitutionMange sprog giver mulighed for at ændre betydningen af en opgave, enten gennem ejendomsmekanismen eller gennem overbelastning af opgaveoperatøren. Substitution kan være nødvendig for at udføre kontrol af gyldigheden af den tildelte værdi eller andre yderligere operationer. Overbelastning af opgaveoperatøren bruges ofte til at give en "dyb kopi", det vil sige kopiering af værdier i stedet for referencer, som kopieres som standard på mange sprog.
Sådanne mekanismer gør det muligt at give bekvemmelighed på arbejdet, så for en programmør er der ingen forskel mellem at bruge en indbygget operatør og en overbelastet. Af samme grund er problemer mulige, da den overbelastede operatørs handlinger kan være helt anderledes end standardoperatørens handlinger, og funktionskaldet er ikke indlysende og let kan forveksles med en indbygget operation.
Da opgaveoperatøren er meget udbredt, forsøger programmeringssprogsudviklere at udvikle nye konstruktioner for at forenkle skrivningen af typiske operationer (for at tilføje det såkaldte " syntaktiske sukker " til sproget). Derudover er inklusionskriteriet i programmeringssprog på lavt niveau ofte evnen til at kompilere til effektiv eksekverbar kode. [3] C -sproget er især berømt for denne ejendom .
Et alternativ til den simple operator er muligheden for at tildele værdien af et udtryk til flere objekter . For eksempel i PL/1 er operatøren
SUM, TOTAL = 0tildeler samtidigt nul til variablerne SUMog TOTAL. I Ada er opgave også et udsagn, ikke et udtryk, så notationen for flere tildelinger er:
SUM, TOTAL: Heltal := 0;En lignende opgave i Python har følgende syntaks:
sum = total = 0I modsætning til PL/1, Ada og Python, hvor multiple tildelinger kun betragtes som en stenografi, i C , Lisp og andre, har denne syntaks et strengt grundlag: tildelingsoperatoren returnerer simpelthen den værdi, der er tildelt den (se ovenfor). Så det sidste eksempel er faktisk:
sum = (total = 0)En linje som denne vil fungere i C (hvis du tilføjer et semikolon i slutningen), men vil forårsage en fejl i Python.
Nogle sprog, såsom Ruby og Python , understøtter en udvidet tildelingssyntaks kaldet parallel tildeling:
a , b = 1 , 11Det antages, at en sådan opgave udføres samtidigt og parallelt , hvilket gør det muligt kort at implementere ved hjælp af denne konstruktion operationen med at udveksle værdierne af to variable.
Skrivning ved hjælp af parallel tildeling | "Traditionel" tildeling: kræver en ekstra variabel og tre operationer | "Økonomisk" opgave: kræver ikke en ekstra variabel, men indeholder også tre operationer | Endnu mere "økonomisk" tildeling: kræver ikke en ekstra variabel, fungerer med bitoperationer |
---|---|---|---|
a, b = b, a | t = a a = b b=t | a = a + b b = a - b a = a - b | a ^= b b ^= a a ^= b |
Den næstsidste aritmetiske mulighed er usikker i programmeringssprog eller hardwareplatforme, der kontrollerer for aritmetiske overløb .
Sidstnævnte mulighed fungerer kun med typer, der understøtter bitvise operationer (for eksempel vil C#double -kompileren ikke tillade dig at udveksle variable værdier på denne måde).
Nogle sprog (såsom PHP ) har konstruktioner til at simulere parallel tildeling:
liste ( $a , $b ) = matrix ( $b , $a );Nogle programmeringssprog, såsom C++ , tillader betingede mål i opgavesætninger. For eksempel udtrykket:
( flag ? tæll1 : tæl2 ) = 0 ;vil tildele en værdi til 0variablen count1if , og if . flag==truecount2flag==false
En anden variant af betinget tildeling ( Ruby ):
a ||= 10Denne konstruktion tildeler kun en aværdi til en variabel, hvis værdien endnu ikke er blevet tildelt eller er lig med false.
Operatoren for sammensat tildeling giver dig mulighed for at forkorte en almindeligt brugt tildelingsform. Ved at bruge denne metode kan du forkorte notationen for en tildeling, der bruger målvariablen som den første operand på højre side af udtrykket, for eksempel:
a = a + bSyntaksen for C -sammensatte tildelingsoperatoren er foreningen af den ønskede binære operator og =. For eksempel er følgende poster tilsvarende
sum += value; | sum = sum + value; |
Programmeringssprog, der understøtter sammensatte operatorer ( C++ , C# , Python , Java osv.) har normalt versioner for de fleste af disse sprogs binære operatorer+= ( ,, -=osv &=.).
På sprogene i C -familien er der fire unære (det vil sige at tage et argument) aritmetiske operatorer til at øge og dekrementere tal med én: to " "-operatorer og to " "-operatorer. Operatorer kan skrives før operanden (præfiks) eller efter den (postfix eller suffiks). Præfiks- og postfix-operatorer er forskellige i evalueringsrækkefølgen. Præfiksoperatører ændrer et tal med én og returnerer det ændrede nummer. Postfix-operatører gemmer et tal i en midlertidig variabel, ændrer det oprindelige tal og returnerer værdien af den midlertidige variabel. ++--
Et eksempel på brug af operatoren : ++
Forøgelse af værdien af en variabel med én | Tilsvarende notation |
---|---|
count ++; | count = count + 1; |
Selvom det ikke ligner en opgave, er det det. Resultatet af udførelsen af ovenstående erklæring er det samme som resultatet af udførelsen af opgaven.
Operatørerne " " kaldes inkrementoperatorer, og " "-operatorerne kaldes dekrementeringsoperatorer. Operatorer bruges ofte i C-sproget, når de håndterer pointere og array- indekser . ++--
Betjening af moderne computere består i at læse data fra hukommelsen eller enheden ind i registre, udføre operationer på disse data og skrive til hukommelsen eller enheden. Hovedoperationen her er dataoverførsel (fra registre til hukommelse, fra hukommelse til register, fra register til register). Derfor udtrykkes det direkte af instruktionerne fra moderne processorer . Så for x86- arkitekturen (alle kommandoerne nedenfor gælder også for denne arkitektur), er dette en operation movog dens varianter til at sende data af forskellige størrelser. Tildelingsoperationen (overførsel af data fra en hukommelsescelle til en anden) implementeres praktisk talt direkte af denne kommando. Generelt kræves der to instruktioner for at udføre en dataoverførsel i hukommelsen: en hukommelse-til-register-bevægelse og en register-til-hukommelse-bevægelse, men med optimeringer kan antallet af instruktioner reduceres i de fleste tilfælde.
movl -4(%ebp), % instruktioner til tildeling |