Oletusargumentti - Default argument
Vuonna ohjelmointi , joka on oletuksena argumentti on argumentti on funktio , joka ohjelmoija ei tarvitse eritellä. Useimmilla ohjelmointikielillä funktiot voivat viedä yhden tai useamman argumentin. Yleensä kukin argumentti on määriteltävä kokonaisuudessaan (näin on C-ohjelmointikielellä ). Myöhemmät kielet (esimerkiksi C ++: ssa ) sallivat ohjelmoijan määrittää oletusargumentit, joilla on aina arvo, vaikka sitä ei olekaan määritetty kutsuttaessa toimintoa.
Oletusargumentit C ++: ssa
Harkitse seuraavaa toimintoilmoitusta:
int MyFunc(int a, int b, int c = 12);
Tähän toimintoon kuuluu kolme argumenttia, joista viimeisellä on oletusarvo kaksitoista. Ohjelmoija voi kutsua tätä toimintoa kahdella tavalla:
int result = MyFunc(1, 2, 3);
result = MyFunc(1, 2);
Ensimmäisessä tapauksessa c- nimisen argumentin arvo määritetään normaaliksi. Toisessa tapauksessa argumentti jätetään pois, ja sen sijaan käytetään oletusarvoa 12 .
Ei ole mitään keinoa tietää, onko soittaja määrittänyt argumentin vai onko käytetty oletusarvoa.
Edellä mainittu menetelmä on erityisen hyödyllinen, kun halutaan asettaa oletuskriteerit, jotta toimintoa voidaan kutsua parametreilla tai ilman niitä. Harkitse seuraavaa:
void PrintGreeting(std::ostream& stream = std::cout) {
// This outputs a message to the given stream.
stream << "hello world!";
}
Toimintokutsu:
PrintGreeting();
tulostaa oletuksena " hei maailma !" on standardi ulostulo std::cout (tyypillisesti näyttö). Toisaalta mikä tahansa objektityyppi std::ostreamvoidaan nyt siirtää samaan toimintoon ja toiminto tulostaa annetulle virralle vakiolähdön sijaan.
PrintGreeting(std::cerr);
Koska oletusargumenttien arvot "täytetään" puhelupaikassa eikä kutsuttavan funktion rungossa, virtuaalifunktiot ottavat oletusarvoarvonsa osoittimen tai viitteen staattisesta tyypistä, jonka kautta puhelu soitetaan, eikä virtuaalisen funktion rungon toimittavan objektin dynaamisesta tyypistä.
struct Base {
virtual std::pair<int, int> Foo(int x = 1) {
return {x, 1};
}
};
struct Derived : public Base {
std::pair<int, int> Foo(int x = 2) override {
return {x, 2};
}
};
int main() {
Derived d;
Base& b = d;
assert(d.Foo() == std::make_pair(2, 2));
assert(b.Foo() == std::make_pair(1, 2));
}
Ylikuormitetut menetelmät
Joillakin kielillä, kuten Java , ei ole oletusargumentteja. Samaa käyttäytymistä voidaan kuitenkin simuloida käyttämällä menetelmän ylikuormitusta luomaan ylikuormitettuja saman nimisiä menetelmiä, jotka ottavat useita argumentteja; ja versiot, joissa on vähemmän argumentteja, yksinkertaisesti kutsuvat versioita, joissa on enemmän argumentteja, oletusarvoina puuttuvina argumentteina:
int MyFunc(int a, int b) { return MyFunc(a, b, 12); }
int MyFunc(int a, int b, int c) { /* main implementation here */ }
Kuitenkin, lisäksi useita muita haittoja , koska oletuksena argumentteja ei mallinnettu tyyppinen järjestelmä, tyyppi soittopyynnön (eli korkeamman asteen funktiota) ei voi ilmaista, että se hyväksyy joko ylikuormitusta tai simuloida oletuksena argumentit ylikuormitetut toiminnot. Ottaa huomioon, JavaScript ei-ylikuormitettu toiminto määritelmä voi korvata oletuksena, kun tulon arvo on undefined(riippumatta siitä, onko se oli implisiittisesti undefinedkautta argumentin poissaolon puhelun sivuston tai eksplisiittisesti siirretään undefinedarvo); joka mallinnetaan valinnaisena argumenttiparametrityyppinä ?: TypeScriptissä . JavaScriptin ratkaisua ei ole ratkaistu staattisesti (ts. Ei käännösaikana, minkä vuoksi TypeScript mallintaa vain toiminnon tyypin allekirjoituksen valinnaisuudet eikä oletusarvot), mikä aiheuttaa ylimääräisiä ajonaikaisia yleiskustannuksia, vaikka se tarjoaa enemmän joustavuutta, että soittopyynnöt voivat itsenäisesti hallita oletusarvoja sen sijaan, että keskitetysti sanelisi soittopyynnön syöttävän toiminnon (takaisinsoittotyyppinen allekirjoitus) -tyyppinen allekirjoitus. Lokitiedostoa liuos voidaan simuloida Java kanssa Optionalpaitsi, analogisen implisiittisen undefinedkunkin poissa argumentti on nimenomaisesti Optional.<Integer>absent()on puhelu päällä.
Arviointi
Jokaisen funktion kutsun oletusarvoarvot on välitettävä kutsutulle funktiolle.
Jos oletusarvoarvo sisältää sivuvaikutuksia, se on merkittävä, kun nämä sivuvaikutukset arvioidaan - kerran koko ohjelmalle (jäsennys-, kokoamis- tai latausaikana) tai kerran toimintokutsua kohti puhelun aikana.
Python on merkittävä kieli, joka arvioi lausekkeet oletusargumenteissa kerran, kun funktio-ilmoitus arvioidaan. Jos halutaan arviointi toimintokutsua kohden, se voidaan toistaa siten, että oletusarvo on sentinel-arvo , kuten None, ja sitten funktion runko arvioi oletusarvon sivuvaikutukset vain, jos sentinel-arvo välitettiin.
Esimerkiksi:
import random
def eager(a=random.random()):
return a
x = eager()
y = eager()
assert x == y
def lazy(a=None):
if a is None:
a = random.random()
return a
x = lazy()
y = lazy()
assert x != y
Laajuus
Yleensä oletusargumentti käyttäytyy identtisesti parametrin tai funktion alussa ilmoitetun paikallisen muuttujan välittämän argumentin kanssa, ja sillä on sama laajuus ja laajuus (elinikä) kuin parametrilla tai muulla paikallisella muuttujalla, nimittäin automaattinen muuttuja, joka jaetaan uudelleen toiminnon lopettamisen yhteydessä.
Muissa tapauksissa oletusargumentti voidaan sen sijaan jakaa staattisesti. Jos muuttuja on muutettavissa, se säilyttää arvon funktiokutsujen aikana, kuten staattisen muuttujan kohdalla .
Tämä käyttäytyminen löytyy Pythonista muuttuville tyypeille, kuten luetteloille. Kuten arvioinnissa, jotta voidaan varmistaa sama laajuus kuin paikallinen muuttuja, voidaan käyttää sentinel-arvoa:
def eager(a=[]):
return a
x = eager()
x += [1]
assert eager() == [1]
def lazy(a=None):
if a is None:
a = []
return a
x = lazy()
x += [1]
assert lazy() == []