Suche…


Syntax

  • funcname = function (paramA, paramB, ...) body; return exprlist end - eine einfache Funktion
  • Funktion funcname (parama, paramB, ...) Körper; exprlist end zurückgeben - Abkürzung für oben
  • local funcname = function (paramA, paramB, ...) body; return exprlist end - ein Lambda
  • lokaler Funkname ; funcname = function (paramA, paramB, ...) body; return exprlist end - Lambda, das rekursive Aufrufe ausführen kann
  • lokale Funktion Funkname (paramA, paramB, ...) body; exprlist end zurückgeben - Abkürzung für oben
  • funcname (paramA, paramB, ...) - eine Funktion aufrufen
  • local var = var oder "Default" - ein Standardparameter
  • nil zurückgeben, "Fehlermeldungen" - Standardmethode zum Abbruch mit einem Fehler

Bemerkungen

Funktionen werden normalerweise mit der function a(b,c) ... end und selten mit dem Setzen einer Variablen auf eine anonyme Funktion ( a = function(a,b) ... end ) gesetzt. Das Gegenteil ist der Fall, wenn Funktionen als Parameter übergeben werden, meistens anonyme Funktionen verwendet werden und normale Funktionen nicht so oft verwendet werden.

Funktion definieren

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

Schauen wir uns die Syntax an. Zuerst sehen wir ein function . Nun, das ist ziemlich beschreibend. Als Nächstes sehen wir die Kennung zum add . der Name. Wir sehen dann die Argumente (a, b) diese können alles sein und sie sind lokal. Nur innerhalb des Funktionskörpers können wir auf sie zugreifen. Überspringen wir bis zum Ende, wir sehen ... nun, das end ! Und alles, was dazwischen ist, ist der Funktionskörper; Der Code, der ausgeführt wird, wenn er aufgerufen wird. Das Schlüsselwort return bewirkt, dass die Funktion tatsächlich nützliche Ergebnisse liefert. Ohne diese Funktion gibt die Funktion nichts zurück, was gleichbedeutend mit der Rückgabe von Null ist. Dies kann natürlich für Dinge hilfreich sein, die mit IO interagieren, zum Beispiel:

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

In dieser Funktion haben wir die return-Anweisung nicht verwendet.

Funktionen können Werte auch bedingt zurückgeben, was bedeutet, dass eine Funktion die Wahl hat, nichts (null) oder einen Wert zurückzugeben. Dies wird im folgenden Beispiel gezeigt.

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

Es ist auch möglich, dass eine Funktion mehrere durch Kommas getrennte Werte zurückgibt, wie gezeigt:

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

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

Funktionen können auch als lokal deklariert werden

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

Sie können auch in Tabellen gespeichert werden:

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

Funktion aufrufen

Funktionen sind nur nützlich, wenn wir sie aufrufen können. Um eine Funktion aufzurufen, wird folgende Syntax verwendet:

print("Hello, World!")

Wir rufen die print . Verwenden Sie das Argument "Hello, World" . Es ist offensichtlich, dass Hello, World in den Ausgabestrom gedruckt wird. Auf den zurückgegebenen Wert kann wie auf jede andere Variable zugegriffen werden.

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

Variablen werden auch in den Parametern einer Funktion akzeptiert.

local a = 10
local b = 60

local c = add(a, b)

print(c)

Funktionen, die eine Tabelle oder einen String erwarten, können mit einem sauberen syntaktischen Zucker aufgerufen werden: Klammern, die den Aufruf umgeben, können weggelassen werden.

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

Anonyme Funktionen

Anonyme Funktionen erstellen

Anonyme Funktionen sind wie normale Lua-Funktionen, es sei denn, sie haben keinen Namen.

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

Wie Sie sehen, ist die Funktion keinem Namen wie print oder add . Um eine anonyme Funktion zu erstellen, müssen Sie nur den Namen weglassen. Diese Funktionen können auch Argumente enthalten.

Den syntaktischen Zucker verstehen

Es ist wichtig zu verstehen, dass der folgende Code

function double(x)
    return x * 2
end

ist eigentlich nur eine Abkürzung für

double = function(x)
    return x * 2
end

Die obige Funktion ist jedoch nicht anonym, da die Funktion direkt einer Variablen zugeordnet ist!

Funktionen sind erstklassige Werte

Dies bedeutet, dass eine Funktion ein Wert ist, der dieselben Rechte wie herkömmliche Werte wie Zahlen und Strings hat. Funktionen können in Variablen gespeichert werden, in Tabellen, können als Argumente übergeben und von anderen Funktionen zurückgegeben werden.

Um dies zu demonstrieren, erstellen wir auch eine "halbe" Funktion:

half = function(x)
    return x / 2
end

Jetzt haben wir zwei Variablen, die half und die double , die beide eine Funktion als Wert enthalten. Was wäre, wenn wir eine Funktion erstellen wollten, die die Zahl 4 in zwei gegebene Funktionen einspeist und die Summe der beiden Ergebnisse berechnet?

Wir wollen diese Funktion wie sumOfTwoFunctions(double, half, 4) . Dies führt die double , die half und die Ganzzahl 4 in unsere eigene Funktion ein.

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

Die obige sumOfTwoFunctions Funktion zeigt, wie Funktionen innerhalb von Argumenten weitergegeben und mit einem anderen Namen aufgerufen werden können.

Standardparameter

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

Diese Funktion ist eine einfache Funktion und funktioniert gut. Aber was würde passieren, wenn wir einfach 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 ?

Das ist nicht gerade toll. Es gibt zwei Möglichkeiten, dies zu beheben:

  1. Sie kehren sofort von der Funktion zurück:

    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. Sie legen einen Standardparameter fest .

    Verwenden Sie dazu einfach diesen einfachen Ausdruck

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

Das Idiom name = name or "Jack" funktioniert wegen or bei Lua-Kurzschlüssen. Wenn das Element auf der linken Seite eines or etwas anderes als nil oder false , wird die rechte Seite niemals ausgewertet. Wenn dagegen sayHello ohne Parameter aufgerufen wird, ist name gleich nil und die Zeichenfolge "Jack" wird dann dem name zugewiesen. (Beachten Sie, dass dieses Idiom daher nicht funktioniert, wenn der boolesche Wert false ein vernünftiger Wert für den betreffenden Parameter ist.)

Mehrere Ergebnisse

Funktionen in Lua können mehrere Ergebnisse zurückgeben.

Zum Beispiel:

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

Beim Aufrufen einer Funktion müssen Sie zum Speichern dieser Werte die folgende Syntax verwenden:

local a, b, c = triple(5)

Was in diesem Fall zu a = b = c = 5 . Es ist auch möglich, zurückgegebene Werte zu ignorieren, indem Sie die Einwegvariable _ an der gewünschten Stelle in einer Liste von Variablen verwenden:

local a, _, c = triple(5)

In diesem Fall wird der zweite zurückgegebene Wert ignoriert. Es ist auch möglich, Rückgabewerte zu ignorieren, indem sie keiner Variablen zugewiesen werden:

local a = triple(5)

Der Variablen a wird der erste Rückgabewert zugewiesen und die verbleibenden zwei werden verworfen.

Wenn eine variable Anzahl von Ergebnissen von einer Funktion zurückgegeben wird, können Sie sie alle in einer Tabelle speichern, indem Sie die darin enthaltene Funktion ausführen:

local results = {triple(5)}

Auf diese Weise kann über die results iteriert werden, um zu sehen, was die Funktion zurückgegeben hat.

Hinweis

Dies kann in einigen Fällen eine Überraschung sein, zum Beispiel:

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

Dies geschieht, weil string.gsub 2 Werte zurückgibt: die angegebene Zeichenfolge, wobei das Vorkommen des Musters ersetzt wurde, und die Gesamtzahl der Übereinstimmungen.

Um dies zu lösen, verwenden Sie entweder eine Zwischenvariable oder put () um den Aufruf herum, z.

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

Dadurch wird nur das erste Ergebnis des Anrufs erfasst und der Rest ignoriert.

Variable Anzahl von Argumenten

Variadische Argumente

Benannte Argumente

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 prüfen

Einige Funktionen funktionieren nur für einen bestimmten Typ von Argumenten:

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

Dies hat mehrere Auswirkungen:

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"

Jetzt können wir die Funktion mit dem gewünschten Parameter aufrufen und das Programm nicht abstürzen.

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

Was ist, wenn wir eine Funktion haben, die etwas mit einer Instanz einer bestimmten Klasse tut? Dies ist schwierig, weil Klassen und Objekte in der Regel Tabellen sind, so dass die type wird Funktion zurückgeben '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ösung: Vergleichen Sie die 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

Verschlüsse

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

typisches Anwendungsbeispiel

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

Fortgeschrittenes Anwendungsbeispiel

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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow