Parameter (datorprogrammering)
I datorprogrammering är en parameter eller ett formellt argument en speciell typ av variabel som används i en subrutin för att referera till en av de data som tillhandahålls som indata till subrutinen. Dessa databitar är värdena för argumenten (ofta kallade faktiska argument eller faktiska parametrar ) som subrutinen kommer att anropas/anropas med. En ordnad lista med parametrar ingår vanligtvis i definitionen av en subrutin , så att varje gång subrutinen anropas utvärderas dess argument för det anropet och de resulterande värdena kan tilldelas motsvarande parametrar.
Till skillnad från argument i vanlig matematisk användning är argumentet inom datavetenskap det faktiska inmatningsuttrycket som skickas/levereras till en funktion, procedur eller rutin i anrops-/anropssatsen, medan parametern är variabeln i implementeringen av subrutinen. Till exempel, om man definierar add-
subrutinen som def add(x, y): returnera x + y
, då är x, y
parametrar, medan om detta kallas add(2, 3)
så är 2, 3
argumenten . Observera att variabler (och uttryck därav) från anropskontexten kan vara argument: om subrutinen anropas som a = 2; b = 3; add(a, b)
då är variablerna a, b
argumenten, inte värdena 2, 3
. Se Parametrar och argument för mer information.
Semantiken för hur parametrar kan deklareras och hur (värdet av) argumenten skickas till parametrarna för subrutiner definieras av språkets utvärderingsstrategi , och detaljerna om hur detta representeras i ett visst datorsystem beror på anropet konventionen för det systemet. I det vanligaste fallet, call by value , agerar en parameter inom subrutinen som en ny lokal variabel initierad till värdet på argumentet (en lokal (isolerad) kopia av argumentet om argumentet är en variabel), men i andra fall , t.ex. call by reference , argumentvariabeln som tillhandahålls av anroparen kan påverkas av åtgärder inom den anropade subrutinen.
Exempel
Följande program i programmeringsspråket C definierar en funktion som heter "SalesTax" och har en parameter som heter "price". Typen av pris är "dubbel" (dvs. ett flyttal med dubbel precision) . Funktionens returtyp är också en dubbel.
dubbel försäljningsskatt ( dubbelt pris ) { retur 0,05 * pris ; }
Efter att funktionen har definierats kan den anropas enligt följande:
Försäljningsskatt ( 10,00 );
I det här exemplet har funktionen anropats med argumentet 10.00 . När detta händer kommer 10.00 att tilldelas priset och funktionen börjar beräkna sitt resultat. Stegen för att producera resultatet specificeras nedan, inkluderade i {}. 0,05 * pris
indikerar att det första du ska göra är att multiplicera 0,05 med värdet av priset, vilket ger 0,50. return
betyder att funktionen kommer att producera resultatet av 0,05* pris
. Därför är slutresultatet (om man bortser från eventuella avrundningsfel man stöter på när man representerar decimalbråk som binära bråk) 0,50.
Parametrar och argument
Termerna parameter och argument kan ha olika betydelser i olika programmeringsspråk. Ibland används de omväxlande, och sammanhanget används för att skilja innebörden. Termen parameter (ibland kallad formal parameter ) används ofta för att hänvisa till variabeln som finns i funktionsdefinitionen, medan argument (ibland kallad faktisk parameter ) hänvisar till den faktiska indata som tillhandahålls vid funktionsanrop. Till exempel, om man definierar en funktion som def f(x): ...
, då är x
parametern, och om den anropas av a = ...; f(a)
då är
a argumentet. En parameter är en (obunden) variabel, medan argumentet kan vara en bokstavlig eller variabel eller mer komplext uttryck som involverar bokstaver och variabler. Vid call by value är det som skickas till funktionen värdet på argumentet – till exempel f(2)
och a = 2; f(a)
är ekvivalenta anrop – medan det är i call by reference, med en variabel som argument, är det som skickas en referens till den variabeln – även om syntaxen för funktionsanropet skulle kunna förbli densamma. Specifikationen för pass-by-referens eller pass-by-värde skulle göras i funktionsdeklarationen och/eller definitionen.
Parametrar visas i procedurdefinitioner; argument visas i proceduranrop. I funktionsdefinitionen f(x) = x*x är
variabeln x en parameter; i funktionsanropet f(2)
är värdet 2 funktionens argument. Löst är en parameter en typ och ett argument är en instans.
En parameter är en inneboende egenskap hos proceduren, inkluderad i dess definition. Till exempel, på många språk, skulle en procedur för att addera två angivna heltal tillsammans och beräkna summan behöva två parametrar, en för varje heltal. I allmänhet kan en procedur definieras med valfritt antal parametrar, eller inga parametrar alls. Om en procedur har parametrar kallas den del av dess definition som specificerar parametrarna dess parameterlista .
Däremot är argumenten de uttryck som tillförs proceduren när den anropas, vanligtvis ett uttryck som matchar en av parametrarna. Till skillnad från parametrarna, som utgör en oföränderlig del av procedurens definition, kan argumenten variera från anrop till anrop. Varje gång en procedur anropas kallas den del av proceduranropet som anger argumenten för argumentlistan .
Även om parametrar också ofta kallas argument, betraktas argument ibland som de faktiska värden eller referenser som tilldelas parametervariablerna när subrutinen anropas vid körning . När man diskuterar kod som anropar en subrutin är alla värden eller referenser som skickas in i subrutinen argumenten, och platsen i koden där dessa värden eller referenser ges är parameterlistan . När man diskuterar koden i subrutindefinitionen är variablerna i subrutinens parameterlista parametrarna, medan parametrarnas värden vid körning är argumenten. Till exempel, i C, när man hanterar trådar, är det vanligt att skicka in ett argument av typen void* och kasta det till en förväntad typ:
void ThreadFunction ( void * pThreadArgument ) { // Namnet på den första parametern 'pThreadArgument' är korrekt, snarare än // 'pThreadParameter'. Vid körning är värdet vi använder ett argument. Som // nämnt ovan, reservera termparametern för när du diskuterar // subrutindefinitioner. }
För att bättre förstå skillnaden, överväg följande funktion skriven i C :
int Summa ( int addend1 , int addend2 ) { retur addend1 + addend2 ; }
Funktionen Sum har två parametrar som heter addend1 och addend2 . Den lägger till de värden som skickas till parametrarna och returnerar resultatet till subrutinens anropare (med en teknik som automatiskt tillhandahålls av C-kompilatorn).
Koden som anropar Sum -funktionen kan se ut så här:
int värde1 = 40 ; int värde2 = 2 ; int summa_värde = Summa ( värde1 , värde2 );
Variablerna värde1 och värde2 initieras med värden. värde1 och värde2 är båda argument till summafunktionen i detta sammanhang.
Vid körning skickas värdena som tilldelats dessa variabler till funktionen Sum som argument. I Sum -funktionen utvärderas parametrarna addend1 och addend2 , vilket ger argumenten 40 respektive 2. Värdena för argumenten läggs till och resultatet returneras till anroparen, där det tilldelas variabeln summa_värde .
På grund av skillnaden mellan parametrar och argument är det möjligt att tillhandahålla olämpliga argument till en procedur. Samtalet kan ge för många eller för få argument; ett eller flera av argumenten kan vara av fel typ; eller argument kan tillhandahållas i fel ordning. Alla dessa situationer orsakar en oöverensstämmelse mellan parameter- och argumentlistorna, och proceduren returnerar ofta ett oavsiktligt svar eller genererar ett körtidsfel .
Alternativ konvent i Eiffel
Inom Eiffels mjukvaruutvecklingsmetod och språk har termerna argument och parameter distinkta användningsområden fastställda av konventionen. Termen argument används uteslutande med hänvisning till en rutins indata, och termen parameter används uteslutande i typparameterisering för generiska klasser .
Tänk på följande rutindefinition:
summa ( tillägg1 : HELTAL ; tillägg2 : HELTAL ): INTEGER gör Resultat := tillägg1 + tillägg2 slut
Rutinsumman tar två argument addend1
och addend2
,
som kallas rutinens formella argument . Ett anrop till summa
anger faktiska argument , som visas nedan med värde1
och värde2
.
summa_värde : HELTAL värde1 : HELTAL = 40 värde2 : HELTAL = 2 … summa_värde := summa ( värde1 , värde2 )
Parametrar ses också som antingen formella eller faktiska . Formella generiska parametrar används i definitionen av generiska klasser. I exemplet nedan deklareras klassen HASH_TABLE som en generisk klass som har två formella generiska parametrar,
G
representerar data av intresse och K
representerar hashnyckeln för data:
klass HASH_TABLE [ G , K -> HASHABLE ] …
När en klass blir en klient till HASH_TABLE
, ersätts de formella generiska parametrarna med faktiska generiska parametrar i en generisk härledning . I följande attributdeklaration my_dictionary
användas som en teckensträngsbaserad ordbok . Som sådan ersätts både data och viktiga formella generiska parametrar med faktiska generiska parametrar av typen STRING
.
min_ordbok : HASH_TABLE [ STRING , STRING ]
Datatyper
I starkt skrivna programmeringsspråk måste varje parameters typ anges i procedurdeklarationen. Språk som använder typinferens försöker upptäcka typerna automatiskt från funktionens kropp och användning. Dynamiskt typade programmeringsspråk skjuter upp typupplösningen till körning. Svagt skrivna språk har liten eller ingen typupplösning, utan förlitar sig istället på programmeraren för korrekthet.
Vissa språk använder ett speciellt nyckelord (t.ex. void ) för att indikera att subrutinen inte har några parametrar; i formell typteori tar sådana funktioner en tom parameterlista (vars typ inte är ogiltig , utan snarare enhet ).
Argument passerar
Den exakta mekanismen för att tilldela argument till parametrar, kallad argument passing , beror på den utvärderingsstrategi som används för den parametern (vanligtvis call by value ), som kan specificeras med nyckelord.
Standardargument
Vissa programmeringsspråk som Ada , C++ , Clojure , [ citat behövs ] Common Lisp , Fortran citat behövs ] 90 , Python , Ruby , Tcl och Windows PowerShell [ tillåter att ett standardargument uttryckligen eller implicit ges i en subrutins deklaration. Detta gör att den som ringer kan utelämna det argumentet när subrutinen anropas. Om standardargumentet uttryckligen anges, används det värdet om det inte tillhandahålls av den som ringer. Om standardargumentet är implicit (ibland genom att använda ett nyckelord som Optional ) så tillhandahåller språket ett välkänt värde (som null , Empty , noll, en tom sträng, etc.) om ett värde inte tillhandahålls av den som ringer .
PowerShell exempel:
function doc ( $g = 1 . 21 ) { "$g gigawatt? $g gigawatt? Bra Scott!" }
PS > doc 1,21 gigawatt? 1,21 gigawatt? Bra Scott! PS > doc 88 88 gigawatt? 88 gigawatt? Bra Scott!
Standardargument kan ses som ett specialfall av argumentlistan med variabel längd.
Parameterlistor med variabel längd
Vissa språk tillåter att subrutiner definieras för att acceptera ett variabelt antal argument . För sådana språk måste subrutinerna iterera genom listan med argument.
PowerShell exempel:
function marty { $args | foreach { "tillbaka till året $_" } }
PS > marty 1985 tillbaka till år 1985 PS > marty 2015 1985 1955 tillbaka till år 2015 tillbaka till år 1985 tillbaka till år 1955
Namngivna parametrar
Vissa programmeringsspråk – som Ada och Windows PowerShell – tillåter att subrutiner har namngivna parametrar . Detta gör att anropskoden blir mer självdokumenterande . Det ger också mer flexibilitet för den som ringer, vilket ofta tillåter att ordningen på argumenten ändras eller att argument utelämnas vid behov.
PowerShell exempel:
function jennifer ( $adjectiveYoung , $adjectiveOld ) { "Unga Jennifer: Jag är $adjectiveYoung!" "Gamla Jennifer: Jag är $adjektivOld!" }
PS > jennifer "fresh" "erfaren" Unga Jennifer: Jag är fräsch! Gamla Jennifer: Jag är erfaren! PS > jennifer -adjektivGammal 'erfaren' -adjektivUng 'fräsch' Unga Jennifer: Jag är fräsch! Gamla Jennifer: Jag är erfaren!
Flera parametrar i funktionella språk
I lambdakalkyl har varje funktion exakt en parameter. Det som är tänkt som funktioner med flera parametrar representeras vanligtvis i lambda-kalkyl som en funktion som tar det första argumentet och returnerar en funktion som tar resten av argumenten; detta är en förvandling som kallas currying . Vissa programmeringsspråk, som ML och Haskell , följer detta schema. I dessa språk har varje funktion exakt en parameter, och det som kan se ut som definitionen av en funktion av flera parametrar, är faktiskt syntaktisk socker för definitionen av en funktion som returnerar en funktion, etc. Funktionsapplikation är vänsterassociativ i dessa språk såväl som i lambda-kalkyl, så det som ser ut som en tillämpning av en funktion på flera argument utvärderas korrekt som funktionen som tillämpas på det första argumentet, sedan den resulterande funktionen tillämpas på det andra argumentet, etc.
Utgångsparametrar
En utgångsparameter , även känd som en utgångsparameter eller returparameter , är en parameter som används för utgång, snarare än den mer vanliga användningen för inmatning. Använda call by reference- parametrar, eller call by value-parametrar där värdet är en referens, eftersom utdataparametrar är ett idiom i vissa språk, särskilt C och C++, medan andra språk har inbyggt stöd för utdataparametrar. Språk med inbyggt stöd för utdataparametrar inkluderar Ada (se Ada-underprogram ), Fortran (sedan Fortran 90 ; se Fortran "avsikt" ), olika procedurtillägg till SQL , såsom PL/SQL (se PL/SQL-funktioner ) och Transact -SQL , C# och .NET Framework , Swift och skriptspråket TScript (se TScript-funktionsdeklarationer) .
Närmare bestämt kan man särskilja tre typer av parametrar eller parameterlägen :
ingångsparametrar s , utgångsparametrar och
in-/utgångsparametrar s; dessa betecknas ofta in
, out
, och in out
eller inout
. Ett inmatningsargument (argumentet till en indataparameter) måste vara ett värde, till exempel en initierad variabel eller literal, och får inte omdefinieras eller tilldelas; ett utmatningsargument måste vara en tilldelningsbar variabel, men det behöver inte initieras, något befintligt värde är inte tillgängligt och måste tilldelas ett värde; och ett input/output-argument måste vara en initierad, tilldelbar variabel och kan valfritt tilldelas ett värde. De exakta kraven och tillämpningen varierar mellan språk – till exempel kan utdataparametrar i Ada 83 endast tilldelas, inte läsas, även efter tilldelning (detta togs bort i Ada 95 för att ta bort behovet av en extra ackumulatorvariabel). Dessa är analoga med att ett värde i ett uttryck är ett r-värde (har ett värde), ett l-värde (kan tilldelas) eller ett r-värde/l-värde (har ett värde och kan tilldelas ), även om dessa termer har specialiserade betydelser i C.
I vissa fall särskiljs endast input och input/output, där utdata anses vara en specifik användning av input/output, och i andra fall stöds endast input och output (men inte input/output). Standardläget varierar mellan språken: i Fortran 90 är input/output standard, medan inmatning i C# och SQL-tillägg är standard, och i TScript anges varje parameter uttryckligen som input eller output.
Syntaktisk indikeras parameterläge i allmänhet med ett nyckelord i funktionsdeklarationen, såsom void f(out int x)
i C#. Konventionellt sätts utdataparametrar ofta i slutet av parameterlistan för att tydligt särskilja dem, även om detta inte alltid följs. TScript använder ett annat tillvägagångssätt, där indataparametrar listas i funktionsdeklarationen, sedan utdataparametrar, separerade med ett kolon (:) och det finns ingen returtyp till själva funktionen, som i den här funktionen, som beräknar storleken på en text fragment:
TextExtent ( WString text , Font font : Integer width , Integer height )
Parameterlägen är en form av denotationssemantik , som anger programmerarens avsikt och tillåter kompilatorer att fånga fel och tillämpa optimeringar – de innebär inte nödvändigtvis operativ semantik (hur parameterpasseringen faktiskt sker). Särskilt, även om ingångsparametrar kan implementeras genom anrop efter värde, och utdata och in-/utgångsparametrar genom anrop genom referens – och detta är ett enkelt sätt att implementera dessa lägen på språk utan inbyggt stöd – det är inte alltid så de är genomförs. Denna distinktion diskuteras i detalj i Ada '83 Rationale, som betonar att parameterläget är abstraherat från vilken parameteröverföringsmekanism (genom referens eller genom kopia) som faktiskt implementeras. Till exempel, medan i C# inmatningsparametrar (standard, inget nyckelord) skickas av värde och utgångs- och ingångs-/utgångsparametrar ( out
och ref ) skickas genom referens, i PL/SQL
skickas ingångsparametrar ( IN ) genom referens,
och utgångs- och ingångs-/utgångsparametrar ( OUT
och IN OUT
) skickas som standard av värde och resultatet kopieras tillbaka, men kan skickas genom referens med hjälp av NOCOPY
-kompilatortipset.
En syntaktisk liknande konstruktion som utdataparametrar är att tilldela returvärdet till en variabel med samma namn som funktionen. Detta finns i Pascal och Fortran 66 och Fortran 77 , som i detta Pascal-exempel:
funktion f ( x , y : heltal ) : heltal ; börja f := x + y ; slut ;
Detta är semantiskt annorlunda genom att när den anropas, utvärderas funktionen helt enkelt – den skickas inte en variabel från anropsomfånget för att lagra utdata i.
Använda sig av
Den primära användningen av utgångsparametrar är att returnera flera värden från en funktion, medan användningen av in-/utgångsparametrar är att modifiera tillstånd med hjälp av parameteröverföring (snarare än genom delad miljö, som i globala variabler). En viktig användning av att returnera flera värden är att lösa semi-predikatproblemet med att returnera både ett värde och en felstatus – se Semipredicate-problem: Multivalued return .
Till exempel, för att returnera två variabler från en funktion i C, kan man skriva:
int bredd int höjd ; F ( x , & bredd , & höjd );
där x
är en ingångsparameter och bredd
och höjd
är utdataparametrar.
Ett vanligt användningsfall i C och relaterade språk är för undantagshantering , där en funktion placerar returvärdet i en utdatavariabel, och returnerar ett booleskt värde som motsvarar om funktionen lyckades eller inte. Ett arketypiskt exempel är TryParse
-metoden i .NET, särskilt C#, som analyserar en sträng till ett heltal och returnerar sant
vid framgång och falskt
vid misslyckande. Detta har följande signatur:
public static bool TryParse ( sträng s , ut int resultat )
och kan användas enligt följande:
int resultat ; if (! Int32 . TryParse ( s , result )) { // undantagshantering }
Liknande överväganden gäller för att returnera ett värde av en av flera möjliga typer, där returvärdet kan specificera typen och sedan lagras värdet i en av flera utdatavariabler.
Nackdelar
Utdataparametrar avskräcks ofta i modern programmering, huvudsakligen eftersom de är besvärliga, förvirrande och för låga - vanliga returvärden är betydligt lättare att förstå och arbeta med. Noterbart är att utdataparametrar involverar funktioner med bieffekter (modifiering av utdataparametern) och liknar semantiskt referenser, som är mer förvirrande än rena funktioner och värden, och distinktionen mellan utdataparametrar och input/outputparametrar kan vara subtil. Vidare, eftersom de flesta parametrar i vanliga programmeringsstilar helt enkelt är ingångsparametrar, är utgångsparametrar och in/utgångsparametrar ovanliga och därför mottagliga för missförstånd.
Parametrar för utdata och input/output förhindrar funktionssammansättning eftersom utdata lagras i variabler snarare än i ett uttrycks värde. Således måste man initialt deklarera en variabel, och sedan måste varje steg i en funktionskedja vara ett separat påstående. Till exempel, i C++ följande funktionssammansättning:
Objekt obj = G ( y , F ( x ));
när det skrivs med output och input/output parametrar blir istället (för F
är det en output parameter, för G
en input/output parameter):
Objekt obj ; F ( x , & obj ); G ( y , & obj );
I det speciella fallet med en funktion med en enda utgångs- eller ingångs-/utgångsparameter och inget returvärde, är funktionssammansättning möjlig om utgångs- eller ingångs-/utgångsparametern (eller i C/C++, dess adress) också returneras av funktionen, i så fall blir ovanstående:
Objekt obj ; G ( y , F ( x , & obj ));
Alternativ
Det finns olika alternativ till användningsfallen för utgångsparametrar.
För att returnera flera värden från en funktion är ett alternativ att returnera en tupel . Syntaktiskt är detta tydligare om automatisk sekvensuppackning och parallell tilldelning kan användas, som i Go eller Python, såsom:
def f (): returnera 1 , 2 a , b = f ()
För att returnera ett värde av en av flera typer kan en taggad union istället användas; de vanligaste fallen är nullbara typer ( option types ), där returvärdet kan vara null för att indikera fel. För undantagshantering kan man returnera en nollbar typ, eller ta upp ett undantag. Till exempel, i Python kan man ha antingen:
result = parse ( s ) om resultatet är None : # undantagshantering
eller mer idiomatiskt:
försök : resultat = parse ( s ) förutom ParseError : # undantagshantering
Mikrooptimeringen att inte kräva en lokal variabel och kopiera returen när man använder utdatavariabler kan också tillämpas på konventionella funktioner och returvärden av tillräckligt sofistikerade kompilatorer.
Det vanliga alternativet till utdataparametrar i C och relaterade språk är att returnera en enda datastruktur som innehåller alla returvärden. Till exempel, givet en struktur som kapslar in bredd och höjd, kan man skriva:
WidthHeight width_and_height = F ( x );
I objektorienterade språk, istället för att använda in-/utdataparametrar, kan man ofta använda call by sharing , skicka en referens till ett objekt och sedan mutera objektet, men inte ändra vilket objekt variabeln refererar till.
Se även
- Kommandoradsargument
- Utvärderingsstrategi
- Operatör överbelastning
- Fria variabler och bundna variabler