Zoeken…


Syntaxis

  • funcname = function (paramA, paramB, ...) body; einde exprlist terug - een eenvoudige functie
  • functienaam (paramA, paramB, ...) body; einde exprlist terug - steno voor hierboven
  • lokale funcnaam = functie (paramA, paramB, ...) body; terugkeer exprlist einde - een lambda
  • lokale functienaam ; funcname = function (paramA, paramB, ...) body; einde exprlist terug - lambda die recursieve oproepen kan doen
  • lokale functienaam (paramA, paramB, ...) body; einde exprlist terug - steno voor hierboven
  • funcname (paramA, paramB, ...) - roep een functie op
  • lokale var = var of "Standaard" - een standaardparameter
  • return nul, "foutmeldingen" - standaard manier om af te breken met een fout

Opmerkingen

Functies worden meestal ingesteld met function a(b,c) ... end en zelden met het instellen van een variabele op een anonieme functie ( a = function(a,b) ... end ). Het tegenovergestelde is waar wanneer functies als parameters worden doorgegeven, anonieme functies meestal worden gebruikt en normale functies niet zo vaak worden gebruikt.

Een functie definiëren

function add(a, b)
    return a + b
end
-- creates a function called add, which returns the sum of it's two arguments

Laten we de syntaxis bekijken. Eerst zien we een function sleutelwoord. Nou, dat is behoorlijk beschrijvend. Vervolgens zien we de add identifier; de naam. We zien dan de argumenten (a, b) deze kunnen van alles zijn en ze zijn lokaal. Alleen binnen het functielichaam kunnen we er toegang toe krijgen. Laten we doorgaan tot het einde, we zien ... wel, het end ! En alles dat daar tussenin zit, is het functielichaam; de code die wordt uitgevoerd wanneer deze wordt aangeroepen. Het sleutelwoord return zorgt ervoor dat de functie daadwerkelijk nuttige uitvoer oplevert. Zonder deze functie retourneert de functie niets, wat overeenkomt met het retourneren van nul. Dit kan natuurlijk handig zijn voor dingen die interageren met IO, bijvoorbeeld:

function printHello(name)
    print("Hello, " .. name .. "!");
end 

In die functie hebben we de retourverklaring niet gebruikt.

Functies kunnen ook waarden voorwaardelijk retourneren, wat betekent dat een functie de keuze heeft om niets (nul) of een waarde te retourneren. Dit wordt aangetoond in het volgende voorbeeld.

function add(a, b)
    if (a + b <= 100) then
        return a + b -- Returns a value
    else
        print("This function doesn't return values over 100!") -- Returns nil
    end
end

Het is ook mogelijk voor een functie om meerdere waarden te scheiden, gescheiden door komma's, zoals weergegeven:

function doOperations(a, b)
    return a+b, a-b, a*b
end

added, subbed, multiplied = doOperations(4,2)

Functies kunnen ook lokaal worden verklaard

do
    local function add(a, b) return a+b end
    print(add(1,2)) --> prints 3
end
print(add(2, 2)) --> exits with error, because 'add' is not defined here

Ze kunnen ook in tabellen worden opgeslagen:

tab = {function(a,b) return a+b end}
(tab[1])(1, 2) --> returns 3

Functie aanroepen.

Functies zijn alleen nuttig als we ze kunnen aanroepen. Om een functie aan te roepen wordt de volgende syntaxis gebruikt:

print("Hello, World!")

We roepen de print op. Met behulp van het argument "Hello, World" . Zoals duidelijk is, wordt hiermee Hello, World naar de outputstroom afgedrukt. De geretourneerde waarde is toegankelijk, net als elke andere variabele.

local added = add(10, 50) -- 60

Variabelen worden ook geaccepteerd in de parameters van een functie.

local a = 10
local b = 60

local c = add(a, b)

print(c)

Functies die een tafel of een string verwachten, kunnen worden opgeroepen met een nette syntactische suiker: haakjes rond de oproep kunnen worden weggelaten.

print"Hello, world!"
for k, v in pairs{"Hello, world!"} do print(k, v) end

Anonieme functies

Anonieme functies maken

Anonieme functies zijn net als gewone Lua-functies, behalve dat ze geen naam hebben.

doThrice(function()
    print("Hello!")
end)

Zoals u kunt zien, is de functie niet toegewezen aan een naam zoals print of add . Om een anonieme functie te maken, hoeft u alleen de naam weg te laten. Deze functies kunnen ook argumenten aannemen.

Inzicht in de syntactische suiker

Het is belangrijk om te begrijpen dat de volgende code

function double(x)
    return x * 2
end

is eigenlijk maar een afkorting voor

double = function(x)
    return x * 2
end

Bovenstaande functie is echter niet anoniem omdat de functie direct is toegewezen aan een variabele!

Functies zijn eerste klas waarden

Dit betekent dat een functie een waarde is met dezelfde rechten als conventionele waarden zoals getallen en strings. Functies kunnen worden opgeslagen in variabelen, in tabellen, kunnen worden doorgegeven als argumenten en kunnen worden geretourneerd door andere functies.

Om dit aan te tonen, maken we ook een "halve" functie:

half = function(x)
    return x / 2
end

We hebben nu twee variabelen, half en double , die beide een functie als waarde bevatten. Wat als we een functie wilden maken die het getal 4 in twee gegeven functies zou invoeren en de som van beide resultaten zou berekenen?

We willen deze functie sumOfTwoFunctions(double, half, 4) zoals sumOfTwoFunctions(double, half, 4) . Hiermee worden de double functie, de half functie en het gehele getal 4 in onze eigen functie ingevoerd.

function sumOfTwoFunctions(firstFunction, secondFunction, input)
    return firstFunction(input) + secondFunction(input)
end

De bovenstaande sumOfTwoFunctions functie laat zien hoe functies binnen argumenten kunnen worden doorgegeven en met een andere naam kunnen worden gebruikt.

Standaard parameters

function sayHello(name)
    print("Hello, " .. name .. "!")
end

Die functie is een eenvoudige functie en werkt goed. Maar wat zou er gebeuren als we gewoon sayHello() zouden noemen?

stdin:2: attempt to concatenate local 'name' (a nil value)
stack traceback:
    stdin:2: in function 'sayHello'
    stdin:1: in main chunk
    [C]: in ?

Dat is niet bepaald geweldig. Er zijn twee manieren om dit op te lossen:

  1. U keert onmiddellijk terug van de functie:

    function sayHello(name)
      if not (type(name) == "string") then
        return nil, "argument #1: expected string, got " .. type(name)
      end -- Bail out if there's no name.
      -- in lua it is a convention to return nil followed by an error message on error
    
      print("Hello, " .. name .. "!") -- Normal behavior if name exists.
    end
    
  2. U stelt een standaardparameter in .

    Gebruik hiervoor deze eenvoudige uitdrukking

function sayHello(name)
    name = name or "Jack" -- Jack is the default, 
                          -- but if the parameter name is given, 
                          -- name will be used instead
    print("Hello, " .. name .. "!")
end

Het idioom name = name or "Jack" werkt omdat or in Lua kortsluiting. Als het item aan de linkerkant van een or iets anders is dan nil of false , wordt de rechterkant nooit geëvalueerd. Aan de andere kant, als sayHello zonder parameter wordt aangeroepen, is de name nil en wordt de tekenreeks "Jack" toegewezen aan de name . (Merk op dat dit idioom daarom niet zal werken als de Booleaanse false een redelijke waarde is voor de parameter in kwestie.)

Meerdere resultaten

Functies in Lua kunnen meerdere resultaten opleveren.

Bijvoorbeeld:

function triple(x)
    return x, x, x
end

Wanneer u een functie aanroept, moet u de volgende syntaxis gebruiken om deze waarden op te slaan:

local a, b, c = triple(5)

Wat in dit geval resulteert in a = b = c = 5 . Het is ook mogelijk om geretourneerde waarden te negeren door de wegwerpvariabele _ op de gewenste plaats in een lijst met variabelen te gebruiken:

local a, _, c = triple(5)

In dit geval wordt de tweede geretourneerde waarde genegeerd. Het is ook mogelijk om retourwaarden te negeren door ze niet aan een variabele toe te wijzen:

local a = triple(5)

Variabele a krijgt de eerste retourwaarde toegewezen en de resterende twee worden genegeerd.

Wanneer een variabel aantal resultaten door een functie wordt geretourneerd, kan men ze allemaal in een tabel opslaan door de functie erin uit te voeren:

local results = {triple(5)}

Op deze manier kan men de results doorlopen om te zien wat de functie heeft teruggegeven.

Notitie

Dit kan in sommige gevallen een verrassing zijn, bijvoorbeeld:

local t = {}
table.insert(t, string.gsub("  hi", "^%s*(.*)$", "%1")) --> bad argument #2 to 'insert' (number expected, got string)

Dit gebeurt omdat string.gsub 2 waarden retourneert: de opgegeven tekenreeks, waarbij het patroon wordt vervangen en het totale aantal overeenkomsten dat heeft plaatsgevonden.

Om dit op te lossen, gebruikt u een tussenliggende variabele of put () rond de aanroep, als volgt:

table.insert(t, (string.gsub("  hi", "^%s*(.*)$", "%1"))) --> works. t = {"hi"}

Dit pakt alleen het eerste resultaat van de oproep en negeert de rest.

Variabel aantal argumenten

Variadische argumenten

Genoemde argumenten

local function A(name, age, hobby)
    print(name .. "is " .. age .. " years old and likes " .. hobby)
end
A("john", "eating", 23) --> prints 'john is eating years old and likes 23'
-- oops, seems we got the order of the arguments wrong...
-- this happens a lot, specially with long functions that take a lot of arguments
-- and where the order doesn't follow any particular logic

local function B(tab)
    print(tab.name .. "is " .. tab.age .. " years old and likes " .. tab.hobby)
end
local john = {name="john", hobby="golf", age="over 9000", comment="plays too much golf"}
B(john)
--> will print 'John is over 9000 years old and likes golf'
-- I also added a 'comment' argument just to show that excess arguments are ignored by the function

B({name = "tim"}) -- can also be written as
B{name = "tim"} -- to avoid cluttering the code
--> both will print 'tim is nil years old and likes nil'
-- remember to check for missing arguments and deal with them

function C(tab)
    if not tab.age then return nil, "age not defined" end
    tab.hobby = tab.hobby or "nothing"
    -- print stuff
end

-- note that if we later decide to do a 'person' class
-- we just need to make sure that this class has the three fields
-- age, hobby and name, and it will be compatible with these functions

-- example:
local john = ClassPerson.new("John", 20, "golf") -- some sort of constructor
john.address = "some place" -- modify the object
john:do_something("information") -- call some function of the object
C(john) -- this works because objects are *usually* implemented as tables

Argumenttypen controleren

Sommige functies werken alleen op een bepaald type argument:

function foo(tab)
    return tab.bar
end
--> returns nil if tab has no field bar, which is acceptable
--> returns 'attempt to index a number value' if tab is, for example, 3
--> which is unacceptable

function kungfoo(tab)
    if type(tab) ~= "table" then
        return nil, "take your useless " .. type(tab) .." somewhere else!"
    end

    return tab.bar
end

dit heeft verschillende implicaties:

print(kungfoo(20)) --> prints 'nil, take your useless number somewhere else!'

if kungfoo(20) then print "good" else print "bad" end --> prints bad

foo = kungfoo(20) or "bar" --> sets foo to "bar"

nu kunnen we de functie aanroepen met welke parameter we maar willen, en het zal het programma niet laten crashen.

-- if we actually WANT to abort execution on error, we can still do
result = assert(kungfoo({bar=20})) --> this will return 20
result = assert(kungfoo(20)) --> this will throw an error

Dus, wat als we een functie hebben die iets doet met een instantie van een specifieke klasse? Dit is moeilijk, omdat klassen en objecten meestal tabellen zijn, dus de type retourneert 'table' .

local Class = {data="important"}
local meta = {__index=Class}

function Class.new()
    return setmetatable({}, meta)
end
-- this is just a very basic implementation of an object class in lua

object = Class.new()
fake = {}

print(type(object)), print(type(fake)) --> prints 'table' twice

Oplossing: vergelijk de metatabellen

-- continuation of previous code snippet
Class.is_instance(tab)
    return getmetatable(tab) == meta
end

Class.is_instance(object) --> returns true
Class.is_instance(fake) --> returns false
Class.is_instance(Class) --> returns false
Class.is_instance("a string") --> returns false, doesn't crash the program
Class.is_instance(nil) --> also returns false, doesn't crash either

sluitingen

do
    local tab = {1, 2, 3}
    function closure()
        for key, value in ipairs(tab) do
            print(key, "I can still see you")
        end
    end
    closure()
    --> 1 I can still see you
    --> 2 I can still see you
    --> 3 I can still see you
end

print(tab) --> nil
-- tab is out of scope

closure()
--> 1 I can still see you
--> 2 I can still see you
--> 3 I can still see you
-- the function can still see tab

typisch gebruiksvoorbeeld

function new_adder(number)
    return function(input)
        return input + number
    end
end
add_3 = new_adder(3)
print(add_3(2)) --> prints 5

meer geavanceerd gebruiksvoorbeeld

function base64.newDecoder(str) -- Decoder factory
    if #str ~= 64 then return nil, "string must be 64 characters long!" end

    local tab = {}
    local counter = 0
    for c in str:gmatch"." do
        tab[string.byte(c)] = counter
        counter = counter + 1
    end

    return function(str)
        local result = ""

        for abcd in str:gmatch"..?.?.?" do
            local a, b, c, d = string.byte(abcd,1,-1)
            a, b, c, d = tab[a], tab[b] or 0, tab[c] or 0, tab[d] or 0
            result = result .. (
                string.char( ((a<<2)+(b>>4))%256 ) ..
                string.char( ((b<<4)+(c>>2))%256 ) ..
                string.char( ((c<<6)+d)%256 )
            )
        end
        return result
    end
end


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