Variadická funkce - Variadic function
v matematika a v programování, a variadická funkce je funkce na neurčito arity, tj. ten, který přijímá proměnný počet argumenty. Podpora variadických funkcí se velmi liší programovací jazyky.
Termín variadic je neologismus sahající až do let 1936-1937.[1] Termín nebyl široce používán až do 70. let.
Přehled
Existuje mnoho matematických a logických operací, které přirozeně narážejí na variadické funkce. Například součet čísel nebo zřetězení řetězců nebo jiných sekvencí jsou operace, které lze považovat za použitelné pro libovolný počet operandů (i když formálně v těchto případech asociativní majetek je použito).
Další operací, která byla implementována jako variadická funkce v mnoha jazycích, je výstupní formátování. The C funkce printf
a Společný Lisp funkce formát
jsou dva takové příklady. Oba mají jeden argument, který určuje formátování výstupu, a jakékoliv číslo argumentů, které poskytují hodnoty k formátování.
Variadic funkce mohou vystavit bezpečnost typu problémy v některých jazycích. Například C printf
, je-li používán opatrně, může vést ke třídě bezpečnostních děr známých jako formátování řetězcových útoků. Útok je možný, protože jazyková podpora pro variadické funkce není typově bezpečná: umožňuje funkci pokusit se vyskočit více argumentů z zásobník než tam byly umístěny, poškodily zásobník a vedly k neočekávanému chování. V důsledku toho Koordinační centrum CERT považuje variadické funkce v jazyce C za bezpečnostní riziko vysoké závažnosti.[2]
Ve funkčních jazycích lze variadics považovat za doplňkové k aplikovat funkce, která bere funkci a seznam / sekvenci / pole jako argumenty a volá funkci s argumenty dodanými v tomto seznamu, čímž předá funkci proměnný počet argumentů.[Citace je zapotřebí ] Ve funkčním jazyce Haskell, variadické funkce lze implementovat vrácením hodnoty a typová třída T
; pokud instance T
jsou konečnou návratovou hodnotou r
a funkce (T t) => x -> t
, to umožňuje libovolný počet dalších argumentů X
.[je třeba další vysvětlení ]
Příbuzný předmět v přepis termínu výzkum se nazývá živé plotynebo zajišťovací proměnné.[3] Na rozdíl od variadics, což jsou funkce s argumenty, živé ploty jsou sekvence samotných argumentů. Mohou také mít omezení (například „neberou více než 4 argumenty“) do té míry, že nemají proměnnou délku (například „berou přesně 4 argumenty“) - a tak je nazývají variadics může být zavádějící. Odkazují však na stejný jev a někdy je frázování smíšené, což má za následek názvy jako variadická proměnná (synonymum pro zajištění). Všimněte si dvojího významu slova proměnná a rozdíl mezi argumenty a proměnnými ve funkčním programování a přepisování termínů. Například výraz (funkce) může mít tři proměnné, z nichž jedna je hedge, což umožňuje výrazu přijmout tři nebo více argumentů (nebo dva nebo více, pokud je hedge povolen prázdný).
Příklady
V C.
Aby bylo možné implementovat variadické funkce v programovacím jazyce C, standard stdarg.h
je použit hlavičkový soubor. Starší varargs.h
záhlaví bylo zastaralé ve prospěch stdarg.h
. V C ++ je soubor záhlaví cstdarg
se používá.[4]
#zahrnout <stdarg.h>#zahrnout <stdio.h>dvojnásobek průměrný(int počet, ...) { va_list ap; int j; dvojnásobek součet = 0; va_start(ap, počet); / * Vyžaduje poslední pevný parametr (pro získání adresy) * / pro (j = 0; j < počet; j++) { součet += va_arg(ap, int); / * Zvyšuje ap na další argument. * / } va_end(ap); vrátit se součet / počet;}int hlavní(int argc, char konst *argv[]) { printf("%F n", průměrný(3, 1, 2, 3)); vrátit se 0;}
Tím se vypočítá průměr libovolného počtu argumentů. Všimněte si, že funkce nezná počet argumentů ani jejich typy. Výše uvedená funkce očekává, že typy budou int
a že počet argumentů je předán v prvním argumentu (jedná se o časté použití, ale v žádném případě není vynuceno jazykem nebo překladačem). V některých dalších případech, například printf, počet a typy argumentů se zjistí z formátovacího řetězce. V obou případech to závisí na programátorovi, který poskytne správné informace. Pokud je předáno méně argumentů, než se funkce domnívá, nebo jsou typy argumentů nesprávné, mohlo by to způsobit, že se načte do neplatných oblastí paměti a může to vést k zranitelnostem, jako je formátovat řetězec útok.
stdarg.h
deklaruje typ, va_list
a definuje čtyři makra: va_start
, va_arg
, va_copy
, a va_end
. Každé vyvolání va_start
a va_copy
musí odpovídat odpovídajícímu vyvolání va_end
. Při práci s argumenty proměnných funkce obvykle deklaruje proměnnou typu va_list
(ap
v příkladu), se kterými budou manipulovat makra.
va_start
trvá dva argumenty, ava_list
objekt a odkaz na poslední parametr funkce (ten před elipsou; toto makro používá k orientaci). Inicializujeva_list
objekt pro použití uživatelemva_arg
nebova_copy
. Kompilátor obvykle vydá varování, pokud je odkaz nesprávný (např. Odkaz na jiný parametr než ten poslední nebo odkaz na úplně jiný objekt), ale nezabrání tomu, aby se kompilace dokončila normálně.va_arg
trvá dva argumenty, ava_list
objekt (dříve inicializovaný) a deskriptor typu. Rozbalí se na další argument proměnné a má zadaný typ. Postupná vyvoláníva_arg
umožní zpracování každého z proměnných argumentů. K nespecifikovanému chování dochází, pokud je typ nesprávný nebo neexistuje žádný další argument proměnné.va_end
trvá jeden argument, ava_list
objekt. Slouží k vyčištění. Pokud byste například chtěli skenovat proměnné argumenty více než jednou, znovu byste inicializovali svůjva_list
objekt vyvolánímva_end
a pakva_start
znovu na tom.va_copy
trvá dva argumenty, obava_list
předměty. Klonuje druhý (který musel být inicializován) do prvního. Pokud se vrátíme k příkladu „vícekrát skenovat proměnné argumenty“, lze toho dosáhnout vyvolánímva_start
na prvníva_list
, pak pomocíva_copy
naklonit to do sekundyva_list
. Po prvním naskenování proměnných argumentů pomocíva_arg
a prvníva_list
(likvidace sva_end
), můžete proměnné argumenty skenovat podruhé pomocíva_arg
a druhýva_list
. Nezapomeňteva_end
klonva_list
.
V C #
C # popisuje variadické funkce pomocí parametry
klíčové slovo. Pro argumenty však musí být uveden typ objekt[]
lze použít jako univerzální.
použitím Systém;třída Program{ statický int Foo(int A, int b, parametry int[] args) { // Vrátí součet celých čísel v args, ignoruje a a b. int součet = 0; pro každého (int i v args) součet += i; vrátit se součet; } statický prázdnota Hlavní(tětiva[] args) { Řídicí panel.WriteLine(Foo(1, 2)); // 0 Řídicí panel.WriteLine(Foo(1, 2, 3, 10, 20)); // 33 }}
V C ++
#zahrnout <iostream>#zahrnout <cstdarg>prázdnota simple_printf(konst char* fmt...) ;int hlavní(){ simple_printf("dcff", 3, 'A', 1.999, 42.5); }prázdnota simple_printf(konst char* fmt...) // C-style „const char * fmt, ...“ je také platný{ va_list args; va_start(args, fmt); zatímco (*fmt != '\0') { -li (*fmt == 'd') { int i = va_arg(args, int); std::cout << i << ' n'; } jiný -li (*fmt == 'C') { // zaznamenat automatický převod na integrální typ int C = va_arg(args, int); std::cout << static_cast<char>(C) << ' n'; } jiný -li (*fmt == 'F') { dvojnásobek d = va_arg(args, dvojnásobek); std::cout << d << ' n'; } ++fmt; } va_end(args);}
V Go
Variadic funkce lze volat s libovolným počtem koncových argumentů.[5] fmt.Println
je běžná variadická funkce; používá prázdné rozhraní jako typ typu catch-all.
balík hlavníimport "fmt"// Tato variadická funkce bere jako argumenty libovolný počet ints.func součet(čísla ...int) { fmt.Tisk("Součet ", čísla) // Také variadická funkce. celkový := 0 pro _, počet := rozsah čísla { celkový += počet } fmt.Println(" je", celkový) // Také variadická funkce.}func hlavní() { // Variadic funkce lze volat obvyklým způsobem s individual // argumenty. součet(1, 2) // "Součet [1 2] je 3" součet(1, 2, 3) // „Součet [1 2 3] je 6“ // Pokud již máte v řezu více arg, použijte je na variadic // funkce využívající func (řez ...) jako je tento. čísla := []int{1, 2, 3, 4} součet(čísla...) // „Součet [1 2 3 4] je 10“}
Výstup:
Součet [1 2] je 3 Součet [1 2 3] je 6 Součet [1 2 3 4] je 10
V Javě
Stejně jako u C #, Objekt
typ je k dispozici jako univerzální.
veřejnost třída Program { soukromé statický prázdnota printArgs(Tětiva... struny) { pro (Tětiva tětiva : struny) { Systém.ven.tisk(tětiva); } } veřejnost statický prázdnota hlavní(Tětiva[] args) { // kompilátor zabalí argumenty předané printArgs uvnitř pole // znamená printArgs je jen metoda, která bere jeden argument, kterým je řetězcové pole proměnné délky printArgs("Ahoj"); // zkratka pro printArgs (["ahoj"]) printArgs("Ahoj", "svět"); // zkratka pro printArgs (["ahoj", "svět"]) }}
V JavaScriptu
JavaScript se nestará o typy variadic argumentů.
funkce součet(...čísla) { vrátit se čísla.snížit((A, b) => A + b);}součet(1, 2, 3) // 6součet(3, 2) // 5
V PHP
PHP se nestará o typy variadic argumentů.
funkce součet(...$ počty): celé číslo{ vrátit se pole_sum($ počty);}echo součet(1, 2, 3); // 6
V Pythonu
Python se nestará o typy variadic argumentů.
def foo(A, b, *args): tisk(args) # args je n-tice (neměnná sekvence).foo(1, 2) # ()foo(1, 2, 3) # (3,)foo(1, 2, 3, "Ahoj") # (3, „ahoj“)
Argumenty klíčových slov lze uložit do slovníku, např. def bar (* args, ** kwargs)
.
V Raku
V Raku je typ parametrů, které vytvářejí variadické funkce, známý jako slurpy parametry pole a jsou rozděleny do tří skupin:
- Zploštělá kaše. Tyto parametry jsou deklarovány jednou hvězdičkou (
*
) a zplošťují argumenty rozpuštěním jedné nebo více vrstev prvků, které lze iterovat (tj. Iterable ).sub foo($ a, $ b, *@args) { říci @args.perl;}foo(1, 2) # []foo(1, 2, 3) # [3]foo(1, 2, 3, "Ahoj") # [3 „ahoj“]foo(1, 2, 3, [4, 5], [6]); # [3, 4, 5, 6]
- Neplácený kašovitý. Tyto parametry jsou deklarovány dvěma hvězdičkami () a nezplošťují žádné iterovatelné argumenty v seznamu, ale udržují argumenty víceméně tak, jak jsou:
sub bar($ a, $ b, **@args) { říci @args.perl;}bar(1, 2); # []bar(1, 2, 3); # [3]bar(1, 2, 3, "Ahoj"); # [3 „ahoj“]bar(1, 2, 3, [4, 5], [6]); # [3, [4, 5], [6]]
- Kontextová slurpy. Tyto parametry jsou deklarovány s plusem (
+
) podepsat a použijí "pravidlo jednoho argumentu ", který rozhoduje o tom, jak zacházet s kašovitým argumentem na základě kontextu. Jednoduše řečeno, pokud je předán pouze jeden argument a tento argument je iterovatelný, použije se tento argument k vyplnění pole parametrů slurpy. V ostatních případech+@
funguje jako**@
(tj. neohrabaný slurpy).sub zaz($ a, $ b, +@args) { říci @args.perl;}zaz(1, 2); # []zaz(1, 2, 3); # [3]zaz(1, 2, 3, "Ahoj"); # [3 „ahoj“]zaz(1, 2, [4, 5]); # [4, 5], jediný argurment vyplňuje polezaz(1, 2, 3, [4, 5]); # [3, [4, 5]], chová se jako ** @zaz(1, 2, 3, [4, 5], [6]); # [3, [4, 5], [6]], chová se jako ** @
V Ruby
Ruby se nestará o typy variadic argumentů.
def foo(*args) tisk argskonecfoo(1)# tisků „[1] => nula“foo(1, 2)# tisků „[1, 2] => žádné“
Ve Swiftu
Swift se stará o typ variadic argumentů, ale o vše Žádný
typ je k dispozici.
func pozdravit(timeOfTheDay: Tětiva, jména: Tětiva...) { // zde je název [String] tisk(„Vypadá to, že máme \(jména.počet) lidé") pro název v jména { tisk("Ahoj \(název), dobrý \(timeOfTheDay)") }}pozdravit(timeOfTheDay: "ráno", jména: "Joseph", "Clara", "William", "Maria")// Výstup:// Vypadá to, že máme 4 lidi// Ahoj Josephe, dobré ráno// Ahoj Claro, dobré ráno// Ahoj William, dobré ráno// Ahoj Maria, dobré ráno
Viz také
- Varargs v programovacím jazyce Java
- Variadic makro (Programovací jazyk C)
- Variadic šablona
Reference
- ^ Henry S. Leonard a H. N. Goodman, Kalkul jednotlivců. Abstrakt přednášky na druhém zasedání Asociace pro symbolickou logiku, které se konalo v Cambridge MA ve dnech 28. – 30. Prosince 1936, [1], Journal of Symbolic Logic 2(1) 1937, 63.
- ^ Klemens, Ben (2014). Tipy 21. století C: C z nové školy. O'Reilly Media, Inc. str. 224. ISBN 1491904445.
- ^ CLP (H): Logické programování omezení pro živé ploty
- ^ "
(stdarg.h) - reference C ++" . www.cplusplus.com. - ^ https://gobyexample.com/variadic-functions
externí odkazy
- Variadická funkce. Rosettský kód úkol ukazující implementaci variadických funkcí ve více než padesáti programovacích jazycích.
- Funkce proměnných argumentů - Výukový program o funkcích proměnných argumentů pro C ++
- Manuál GNU libc