Dies ist eine alte Version des Dokuments!
Inhaltsverzeichnis
Funktionen
Durch Funktionen können Programme in kleine, wiederverwertbare Teile partitioniert werden. Diese Teil-Programme sind normalerweise in sich geschlossen und erfüllen einen bestimmten Aspekt des gesamten Programms.
Für einen Drucker beispielsweise könnte man folgende Funktionen definieren: „Hole Papier“, „Bewege Papier“, „Leite Tinte zum Druckkopf“, „Bewege Druckkopf“, „Verarbeite Bilddaten“. Jede einzelne dieser Funktionen würde für sich genommen kein Bild ausdrucken können. Wenn alle diese Funktionen jedoch korrekt benutzt werden und zusammenarbeiten können, kann erfolgreich gedruckt werden.
In diesem Beispiel dienen Funktionen also dazu
- Den Vorgang „Drucken“ in kleine logische Prozesse zu teilen
- Einem Prozess einen bestimmten Namen zu geben
- Jeden Prozess unabhängig von den anderen benutzen zu können
- Jeden Prozess immer genau gleich ablaufen zu lassen
Jede Funktion kann außerdem Eingabewerte (Parameter) entgegen nehmen. Das bedeutet, dass sich die gleiche Funktion basierend auf sich verändernden Eingabewerten unterschiedlich verhält. Die Druckerfunktion „Bewege Druckkopf“ könnte beispielsweise Parameter für die Koordinaten erhalten, an die sich der Druckkopf bewegen soll.
Funktionen werden mit dem Schlüsselwort function eingeleitet und deren Ende mit end deklariert. Die Namen der Parameter werden in Klammern hinter function angegeben. Innerhalb der Funktion können die Parameter unter dem gegebenen Namen benutzt werden. Alles Weitere folgt genau den Regeln der Definition von Variablen. Dazu zählen auch die Vorgaben, welche Namen für Funktionen erlaubt sind.
-- Definiere eine "Ausgangsposition" für den Druckkopf PrintheadPositionX = 0 PrintheadPositionY = 0 -- Für die Parameter wählen wir in unseren Beispiel immer Namen, die mit einem Unterstrich -- beginnen. Dadurch ist im Code immer sofort ersichtlich, bei welchen Variablen es sich um -- Parameter handelt MovePrinthead = function(_PositionX, _PositionY) PrintheadPositionX = _PositionX PrintheadPositionY = _PositionY end
Falls du schon einmal mit anderen Programmiersprachen gearbeitet hast, ist diese Schreibweise möglicherweise ungewohnt. Lua bietet daher auch eine alternative Schreibweise an, die genau die gleiche Funktion definiert:
-- Dieser Code ist nur eine andere Schreibweise für das Beispiel oben PrintheadPositionX = 0 PrintheadPositionY = 0 -- Das Schlüsselwort function steht nun vorne, die Parameter in Klammern hinter dem -- Funktionsnamen function MovePrinthead(_PositionX, _PositionY) PrintheadPositionX = _PositionX PrintheadPositionY = _PositionY end
Die Funktion MovePrinthead wird folgendermaßen aufgerufen:
-- Bewege Druckkopf an Position X=100, Y=200 MovePrinthead(100, 200)
Im Folgenden wollen wir nun einige Beispiele geben und weitere Anwendungsfälle von Funktionen betrachten.
Hinweis: Unsere Beispiele in diesem und den folgenden Kapiteln können besser nachvollzogen werden, wenn man die Programmzeilen nebenbei ausprobieren kann. Dazu kann man diese Webseite hier verwenden:
Um dabei bei der Ausgabe ein Ergebnis zu sehen, kann man die Funktion print
verwenden. Will man beispielsweise die Variable PrintheadPositionX
ansehen, kann man
MovePrinthead(100, 200) print(PrintheadPositionX)
schreiben. Wenn die Variable einen anderen Namen hat, muss man diesen dementsprechend austauschen.
Funktionen mit Rückgabewert
Es gibt noch eine andere „Art“ von Funktionen. Im Fall oben haben wir die Funktion, die den Druckkopf steuert, aufgerufen und die Funktion hat Veränderungen im Drucker verursacht (ein sogenannter Seiteneffekt).
Alternativ dazu gibt es auch Funktionen, die einen Wert berechnen sollen und diesen in eine Variable zurückgeben. Dazu wird das Schlüsselwort return verwendet.
Als einfaches Beispiel berechnen wir hier die Quadratwurzel einer Zahl und speichern diese in einer Variable:
Number1 = 64 function Sqrt(_X) return _X^0.5 end Result = Sqrt(Number1)
Beachte hier wieder die Reihenfolge, in der die Zuweisung Result
geschieht: Zuerst wird die rechte Seite Sqrt(Number1)
ausgewertet. Das bedeutet, die Funktion Sqrt
wird mit dem Parameter Number1
aufgerufen. Die Funktion gibt ihr Ergebnis mit return zurück. Dieses wird dann in Result
abgespeichert.
Eine Funktion, die einen Rückgabewert ausgibt, ist nicht auf ein einziges return beschränkt. Wir bauen die Funktion, die das Minimum aus drei verschiedenen Zahlen berechnet ( Verzweigungen), in eine Funktion mit Rückgabewert um:
function MinOfThree(_Number1, _Number2, _Number3) if _Number1 < _Number2 then if _Number1 < _Number3 then return _Number1 else return _Number3 end else if _Number2 < _Number3 then return _Number2 else return _Number3 end end end Minimum = MinOfThree(3, 7, 1) -- 1
Achtung: Wenn man mit return einen Ausgabewert zurückgibt, können danach keine weiteren Instruktionen folgen, da die Funktion bei return immer zuende ist. Jede weitere Instruktion darunter wird zu einem Syntaxfehler führen!
Funktionen ohne Parameter
Natürlich braucht nicht jede Funktion Parameter. Beispielsweise könnte es eine Funktion geben, die unseren Druckkopf von oben auf seine Ausgangsposition zurücksetzt. Die würde dann so aussehen:
function ResetPrinthead() PrintheadPositionX = 0 PrintheadPositionY = 0 end -- Beachte beim Aufruf, dass auch ohne Parameter die Klammern dahinter gebraucht werden! ResetPrinthead()
Interaktion mehrerer Funktionen
Um ein etwas komplexeres Beispiel zu geben, wie mehrere Funktionen miteinander interagieren zu lassen, wollen wir mehrere Funktionen verwenden, um die Euklidische Distanz in zwei Dimensionen zu berechnen.
function SquaredDifference(_X, _Y) return (_X-_Y)^2 end function Sqrt(_X) return _X^0.5 end function EuclideanDistance(_X1, _Y1, _X2, _Y2) Difference1 = SquaredDifference(_X1, _X2) Difference2 = SquaredDifference(_Y1, _Y2) return Sqrt(Difference1 + Difference2) end Distance = EuclideanDistance(2, 4, 5, 8) -- 5
Zum besseren Verständnis von Funktionen kann es helfen, dieses Beispiel Schritt für Schritt durchzurechnen und sich davon zu überzeugen, dass tatsächlich die gewünschte Funktion berechnet wird. In welcher Reihenfolge werden die einzelnen Rechenschritte vollzogen?
TODOS für zweite Runde:
- Komposition mehrerer Funktionen
- Rekursive Funktionen
- Mehrere Rückgabewerte
- return nil?