Zoeken…


Invoering

Varargs , zoals ze algemeen bekend staan, staan functies toe om een willekeurig aantal argumenten zonder specificatie aan te nemen. Alle argumenten die aan een dergelijke functie worden gegeven, zijn verpakt in een enkele structuur die bekend staat als de vararglijst ; die is geschreven als ... in Lua. Er zijn basismethoden voor het extraheren van het aantal gegeven argumenten en de waarde van die argumenten met de functie select() , maar geavanceerdere gebruikspatronen kunnen de structuur optimaal benutten.

Syntaxis

  • ... - Maakt de functie waarvan de lijst met argumenten waarin deze verschijnt een variadische functie
  • select (what, ...) - Als 'what' een getal is in bereik 1 tot het aantal elementen in de vararg, retourneert het 'what'th-element naar het laatste element in de vararg. Het rendement is nul als de index buiten bereik is. Als 'wat' de tekenreeks '#' is, retourneert het aantal elementen in de vararg.

Opmerkingen

rendement

De vararg-lijst wordt geïmplementeerd als een gekoppelde lijst in de PUC-Rio-implementatie van de taal, dit betekent dat indexen O (n) zijn. Dat betekent dat het herhalen van de elementen in een vararg met behulp van select() , zoals het onderstaande voorbeeld, een O (n ^ 2) -bewerking is.

for i = 1, select('#', ...) do
    print(select(i, ...))
end

Als u van plan bent de elementen in een vararglijst te herhalen, pak dan eerst de lijst in een tabel in. Tabeltoegang is O (1), dus iteratie is O (n) in totaal. Of, als u daartoe geneigd bent, zie het voorbeeld van foldr() in het gedeelte voor geavanceerd gebruik; het gebruikt recursie om over een vararglijst in O (n) te itereren.

Volgorde Lengte Definitie

De vararg is nuttig omdat de lengte van de vararg expliciet doorgegeven (of berekende) nils respecteert. Bijvoorbeeld.

function test(...)
    return select('#', ...)
end

test()             --> 0
test(nil, 1, nil)  --> 3

Dit gedrag is echter in strijd met het gedrag van tabellen, waarbij de lengte-operator # niet werkt met 'gaten' (ingesloten nils) in reeksen. Het berekenen van de lengte van een tafel met gaten is niet gedefinieerd en kan niet worden vertrouwd. Afhankelijk van de waarden in ... kan het nemen van de lengte van {...} dus niet leiden tot het 'juiste' antwoord. In Lua 5.2+ is table.pack() geïntroduceerd om dit tekort aan te pakken (er is een functie in het voorbeeld die deze functie implementeert in pure Lua).

Idiomatisch gebruik

Omdat varargs hun lengte dragen, gebruiken mensen ze als sequenties om het probleem met gaten in tabellen te voorkomen. Dit was niet het beoogde gebruik en één waarvoor de referentie-implementatie van Lua niet optimaliseert. Hoewel een dergelijk gebruik in de voorbeelden wordt onderzocht, wordt het in het algemeen afgekeurd.

Basics

Variadische functies worden gemaakt met behulp van de ... ellipsen syntaxis in de lijst met argumenten van de functiedefinitie.

function id(...)
    return
end

Als u deze functie als id(1, 2, 3, 4, 5) ) zou noemen id(1, 2, 3, 4, 5) dan ... (AKA de vararglijst) zou de waarden 1, 2, 3, 4, 5 .

Voor functies kunnen vereiste argumenten nodig zijn, evenals ...

function head(x, ...)
    return x
end

De eenvoudigste manier om elementen uit de vararglijst te halen, is om er eenvoudig variabelen aan toe te wijzen.

function head3(...)
    local a, b, c = ...
    return a, b, c
end

select() kan ook worden gebruikt om het aantal elementen te vinden en elementen te extraheren van ... indirect.

function my_print(...)
    for i = 1, select('#', ...) do
        io.write(tostring(select(i, ...)) .. '\t')
    end
    io.write '\n'
end

... kan in een tafel worden verpakt voor gebruiksgemak, met behulp van {...} . Hiermee worden alle argumenten in het volgende deel van de tabel geplaatst.

5.2

table.pack(...) kan ook worden gebruikt om de vararglijst in een tabel in te pakken. Het voordeel van table.pack(...) is dat het veld n van de geretourneerde tabel wordt ingesteld op de waarde select('#', ...) . Dit is belangrijk als uw lijst met argumenten nul kan bevatten (zie opmerkingen hieronder).

function my_tablepack(...)
    local t = {...}
    t.n = select('#', ...)
    return t
end

De vararglijst kan ook worden geretourneerd vanuit functies. Het resultaat is meerdere retouren.

function all_or_none(...)
    local t = table.pack(...)
    for i = 1, t.n do
        if not t[i] then
            return    -- return none
        end
    end
    return ...    -- return all
end

Geavanceerd gebruik

Zoals vermeld in de basisvoorbeelden, kunt u variabel gebonden argumenten en de lijst met variabele argumenten ( ... ) gebruiken. U kunt dit feit gebruiken om een lijst recursief uit elkaar te trekken, net zoals in andere talen (zoals Haskell). Hieronder is een implementatie van foldr() die daarvan profiteert. Elke recursieve aanroep bindt de kop van de vararglijst aan x en geeft de rest van de lijst door aan een recursieve aanroep. Hierdoor wordt de lijst vernietigd totdat er slechts één argument is ( select('#', ...) == 0 ). Daarna wordt elke waarde toegepast op het functieargument f met het eerder berekende resultaat.

function foldr(f, ...)
    if select('#', ...) < 2 then return ... end
    local function helper(x, ...)
        if select('#', ...) == 0 then
          return x
        end
        return f(x, helper(...))
    end
    return helper(...)
end

function sum(a, b)
    return a + b
end

foldr(sum, 1, 2, 3, 4)
--> 10    

U kunt andere functiedefinities die deze programmeerstijl gebruiken hier vinden in nummer 3 tot en met nummer 8.

De enige idiomatische gegevensstructuur van Lua is de tabel. De operator voor de lengte van de tabel is niet gedefinieerd als er zich nil ergens in een reeks bevinden. In tegenstelling tot tafels, de vararg lijst opzichten expliciete nil s zoals vermeld in de basis voorbeelden en de opmerkingen sectie (lees dat gedeelte als u nog niet). Met weinig werk kan de vararglijst elke bewerking uitvoeren die een tabel naast mutatie kan uitvoeren. Dit maakt de vararglijst een goede kandidaat voor het implementeren van onveranderlijke tupels.

function tuple(...)
    -- packages a vararg list into an easily passable value
    local co = coroutine.wrap(function(...)
        coroutine.yield()
        while true do
            coroutine.yield(...)
        end
    end)
    co(...)
    return co
end

local t = tuple((function() return 1, 2, nil, 4, 5 end)())

print(t())                 --> 1    2    nil    4    5    | easily unpack for multiple args
local a, b, d = t()        --> a = 1, b = 2, c = nil      | destructure the tuple
print((select(4, t())))    --> 4                          | index the tuple
print(select('#', t()))    --> 5                          | find the tuple arity (nil respecting)

local function change_index(tpl, i, v)
    -- sets a value at an index in a tuple (non-mutating)
    local function helper(n, x, ...)
        if select('#', ...) == 0 then
            if n == i then
                return v
            else
                return x
            end
        else
            if n == i then
                return v, helper(n+1, ...)
            else
                return x, helper(n+1, ...)
            end
        end
    end
    return tuple(helper(1, tpl()))
end

local n = change_index(t, 3, 3)
print(t())                 --> 1    2    nil    4    5
print(n())                 --> 1    2    3    4    5

Het belangrijkste verschil tussen wat hierboven en tabellen is, is dat tabellen veranderlijk zijn en pointer-semantiek hebben, waarbij de tuple die eigenschappen niet heeft. Bovendien kunnen tupels expliciete nil en een nooit-ongedefinieerde lengte-bewerking hebben.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow