Sök…


Syntax

  • funcname = funktion (paramA, paramB, ...) kropp; return exprlist end - en enkel funktion
  • funktion funcname (paramA, paramB, ...) kropp; return exprlist end - korthet för ovan
  • lokal funcname = funktion (paramA, paramB, ...) kropp; return exprlist end - en lambda
  • lokalt funknamn ; funcname = funktion (paramA, paramB, ...) kropp; return exprlist end - lambda som kan göra rekursiva samtal
  • lokal funktion funcname (paramA, paramB, ...) kropp; return exprlist end - korthet för ovan
  • funcname (paramA, paramB, ...) - ringa en funktion
  • local var = var eller "Standard" - en standardparameter
  • return nil, "felmeddelanden" - standard sätt att avbryta med ett fel

Anmärkningar

Funktioner är vanligtvis inställda med function a(b,c) ... end och sällan med inställning av en variabel till en anonym funktion ( a = function(a,b) ... end ). Det motsatta är sant när man skickar funktioner som parametrar, anonyma funktioner används oftast och normala funktioner används inte så ofta.

Definiera en funktion

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

Låt oss titta på syntaxen. Först ser vi ett function . Det är ganska beskrivande. Nästa kommer vi att add identifieraren; namnet. Vi ser då argumenten (a, b) dessa kan vara vad som helst och de är lokala. Endast inuti funktionskroppen kan vi komma åt dem. Låt oss hoppa till slutet, vi ser ... ja, end ! Och allt däremellan är funktionskroppen; koden som körs när den heter. Den return sökord är det som gör funktionen faktiskt ge några användbara utgång. Utan den returnerar funktionen ingenting, vilket motsvarar noll. Detta kan naturligtvis vara användbart för saker som interagerar med IO, till exempel:

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

I den funktionen använde vi inte returrättet.

Funktioner kan också returnera värden på villkor, vilket innebär att en funktion har valet att returnera ingenting (noll) eller ett värde. Detta visas i följande exempel.

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

Det är också möjligt för en funktion att returnera flera värden separerade med komma, som visas:

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

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

Funktioner kan också förklaras lokala

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

De kan också sparas i tabeller:

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

Ringer en funktion.

Funktioner är bara användbara om vi kan ringa dem. För att ringa en funktion används följande syntax:

print("Hello, World!")

Vi kallar print . Med hjälp av argumentet "Hello, World" . Som är uppenbart kommer detta att skriva ut Hello, World till output stream. Det returnerade värdet är tillgängligt, precis som alla andra variabler skulle vara.

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

Variabler accepteras också i en funktions parametrar.

local a = 10
local b = 60

local c = add(a, b)

print(c)

Funktioner som förväntar sig ett bord eller en sträng kan kallas med ett snyggt syntaktiskt socker: parenteser som omger samtalet kan utelämnas.

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

Anonyma funktioner

Skapa anonyma funktioner

Anonyma funktioner är precis som vanliga Lua-funktioner, förutom att de inte har ett namn.

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

Som ni ser är funktionen inte tilldelad något namn som print eller add . För att skapa en anonym funktion behöver du bara utelämna namnet. Dessa funktioner kan också ta argument.

Förstå det syntaktiska sockret

Det är viktigt att förstå att följande kod

function double(x)
    return x * 2
end

är faktiskt bara en kortfattning för

double = function(x)
    return x * 2
end

Men funktionen ovan är inte anonym eftersom funktionen direkt tilldelas en variabel!

Funktioner är förstklassiga värden

Detta innebär att en funktion är ett värde med samma rättigheter som konventionella värden som nummer och strängar. Funktioner kan lagras i variabler, i tabeller, kan skickas som argument och kan returneras av andra funktioner.

För att demonstrera detta skapar vi också en "halv" -funktion:

half = function(x)
    return x / 2
end

Så nu har vi två variabler, half och double , som båda innehåller en funktion som ett värde. Tänk om vi ville skapa en funktion som skulle mata numret 4 i två givna funktioner och beräkna summan av båda resultaten?

Vi vill kalla den här funktionen som sumOfTwoFunctions(double, half, 4) . Detta kommer att mata double funktion, half funktion och heltal 4 i vår egen funktion.

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

Ovanstående sumOfTwoFunctions funktion visar hur funktioner kan skickas runt i argument och nås med ett annat namn.

Standardparametrar

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

Denna funktion är en enkel funktion och den fungerar bra. Men vad skulle hända om vi bara ringde sayHello() ?

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

Det är inte riktigt bra. Det finns två sätt att fixa detta:

  1. Du återgår omedelbart från funktionen:

    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. Du ställer in en standardparameter .

    Använd detta enkla uttryck för att göra detta

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

Formspråket name = name or "Jack" fungerar eftersom or i Lua kortslutningar. Om objektet på vänster sida av ett or är något annat än nil eller false , utvärderas aldrig den högra sidan. Å andra sidan, om sayHello kallas utan parameter, kommer name att vara nil , och så kommer strängen "Jack" att tilldelas name . (Observera att detta formspråk därför inte fungerar om den booleska false är ett rimligt värde för den aktuella parametern.)

Flera resultat

Funktioner i Lua kan ge flera resultat.

Till exempel:

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

För att spara dessa värden måste du använda följande syntax när du ringer till en funktion:

local a, b, c = triple(5)

Vilket kommer att resultera i a = b = c = 5 i detta fall. Det är också möjligt att ignorera returnerade värden med hjälp av kastningsvariabeln _ på önskad plats i en lista med variabler:

local a, _, c = triple(5)

I detta fall ignoreras det andra returnerade värdet. Det är också möjligt att ignorera returvärden genom att inte tilldela dem till någon variabel:

local a = triple(5)

Variabel a tilldelas det första returvärdet och de återstående två kommer att kasseras.

När en variabel mängd resultat returneras av en funktion kan man lagra dem alla i en tabell genom att utföra funktionen inuti den:

local results = {triple(5)}

På detta sätt kan man iterera över results att se vad funktionen returnerade.

Notera

Detta kan vara en överraskning i vissa fall, till exempel:

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

Detta händer eftersom string.gsub returnerar 2 värden: den givna strängen, med förekomster av mönstret ersatt, och det totala antalet matchningar som inträffade.

För att lösa detta använder du antingen en mellanvariabel eller lägg () runt samtalet, så här:

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

Detta tar bara det första resultatet av samtalet och ignorerar resten.

Variabelt antal argument

Variadiska argument

Namngivna argument

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

Kontrollera argumenttyper

Vissa funktioner fungerar bara på en viss typ av 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

detta har flera konsekvenser:

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 kan vi kalla funktionen med vilken parameter vi vill, och den kraschar inte programmet.

-- 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

Så, om vi har en funktion som gör något med en instans av en viss klass? Detta är svårt, eftersom klasser och objekt vanligtvis är tabeller, så type kommer att returnera '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

Lösning: jämföra metatabellerna

-- 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

nedläggningar

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

typiskt användningsexempel

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

mer avancerat exempel

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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow