Benutzer-Werkzeuge

Webseiten-Werkzeuge


scripting:tutorials:level1:variable_scope

Dies ist eine alte Version des Dokuments!


Lokale und Globale Variablen

Bisher sind wir von folgendem ausgegangen: Alle Variablen, die wir definieren, sind vom Zeitpunkt der Definition an immer verfügbar. Für die Variablen in den gegebenen Beispielen stimmt das auch.

Der Grund dafür ist, dass alle Variablen, die man ohne Weiteres in Lua definiert, global sind. Das bedeutet, man kann an jeder Stelle im Code ihren Inhalt abfragen oder verändern. Das hat einige Nachteile:

  • Mehr Speicherverbrauch: Jede globale Variable wird immer im Speicher bleiben, weil sie jederzeit abrufbar sein muss. Wenn man ein Zwischenergebnis in einer globalen Variable speichert, die man danach nie wieder verwendet, hat man Speicherplatz verschwendet
  • Schlechtere Übersicht: Für jede globale Variable musst du dir merken, was du darin abgespeichert hast. Wenn du viele Variablen brauchst, bleiben unter Umständen keine sinnvollen Namen mehr übrig, die du ihnen geben kannst
  • Langsamere Laufzeit: Der Zugriff auf globale Variablen ist in Lua langsamer als auf Variablen, die nicht global sind
  • Schwer auffindbare Skriptfehler: Bei vielen globalen Variablen kann es irgendwann passieren, dass du den Überblick verlierst. Unter Umständen überschreibst du dann versehentlich eine Variable, obwohl du den Inhalt darin noch brauchst

Zum letzten der genannten Punkte wollen wir ein Beispiel geben. Angenommen, du hast dir eine Funktion geschrieben, die einen String produziert, der dem Spieler mitteilen kann, welchen Schwierigkeitsgrad er ausgewählt hat. Die Funktion kann so aussehen:

function GetDifficultyString(_Difficulty)
    Information = "Du hast die "
    if _Difficulty == 1 then
        Information = Information.."leichte "
    elseif _Difficulty == 2 then
        Information = Information.."mittlere "
    elseif _Difficulty == 3 then
        Information = Information.."schwierige "
    end
    Information = Information.."Variante gewählt!"
    return Information
end

Diese Funktion würde für sich genommen einwandfrei funktionieren. Gehen wir nun weiterhin davon aus, dass du einen String definiert hast, der dem Spieler irgendwann angezeigt werden soll und der einen Hinweis zum Aufenthaltsort einer Schatztruhe beinhaltet.

Information = "Der Bürgermeister erwähnte, dass es in der Nähe der alten Sägemühle vor kurzem "..
              "einen Erdrutsch gab. Vielleicht habt Ihr dort Glück."

Auch an diesem Text gibt es für sich genommen nichts auszusetzen. Werden diese beiden allerdings in einer bestimmten Reihenfolge kombiniert, kann das zu unerwünschtem Verhalten führen:

Information = "Der Bürgermeister erwähnte, dass es in der Nähe der alten Sägemühle vor kurzem "..
              "einen Erdrutsch gab. Vielleicht habt Ihr dort Glück."
 
-- hier könnte dein Skript stehen
 
-- Bis hier her ist "Information" nicht verändert worden. Der Hinweis zur Schatztruhe besteht also noch.
-- Mit folgendem Aufruf allerdings verändert sich der "Information"-String. Es wird aus dem Aufruf der
-- Funktion nicht ersichtlich, dass er das tut, was diese Art Fehler schwer zu finden macht
DifficultyString = GetDifficultyString(2)
 
-- Ab hier enthält "Information" keinen Hinweis mehr, sondern die Beschreibung des Schwierigkeitsgrades

Dass der Name Information, wenn er global definiert ist, „verbraucht“ wird (also nicht für andere Zwecke benutzt werden kann, ohne überschrieben zu werden), beschränkt sich nicht nur auf andere Strings. Angenommen, du hast außerdem eine Funktion definiert, die ebenfalls Information heißt:

function Information()
    -- mit der Funktion "Message" können im Spiel Texte im linken oberen Eck eingeblendet werden, die nach einiger
    -- Zeit von selbst wieder verschwinden
    Message("Du spielst gerade meine Karte in der Version 1.06!")
end
 
-- hier könnte dein Skript stehen
 
-- Bis hier her ist "Information" nicht verändert worden. Die Funktion kann also problemlos aufgerufen werden.
-- Mit dem folgenden Aufruf wird die Funktion allerdings mit einem String überschrieben:
DifficultyString = GetDifficultyString(2)
 
-- der folgende Aufruf wird nun zu einem Fehler führen, da "Information" nicht länger eine Funktion ist:
Information()

In beiden Beispielen entsteht das Problem dadurch, dass die Variable Information in der Funktion GetDifficultyString nur zur Berechnung eines Ergebnisses gebraucht wird, danach aber nicht mehr. Da sie global definiert ist, überschreibt sie aber andere, wichtige Variablen. Um das zu verhindern, wollen wir lokale Variablen verwenden. Lokale Variablen sind nur in einem bestimmten Bereich im Skript gültig und werden dann automatisch verworfen. Um zu verstehen, in welchen Bereichen eine lokale Variable gültig ist, wollen wir zunächst beschreiben, was Blöcke sind.


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:

https://www.lua.org/demo.html

Um dabei bei der Ausgabe ein Ergebnis zu sehen, kann man die Funktion print verwenden. Will man beispielsweise die Variable Information ansehen, kann man

print(Information)

schreiben. Wenn die Variable einen anderen Namen hat, muss man diesen dementsprechend austauschen.


Blöcke


Lokale Variablen


Verwendungszwecke

TODO: Beispielhaft Use Cases für lokale und globale Variablen (Anzahl Schatztruhen vs Zwischenergebnisse). TODO: Funktionen sind normalerweise immer global TODO: Parameter in Funktionen sind immer lokal

scripting/tutorials/level1/variable_scope.1684769012.txt.gz · Zuletzt geändert: 2023/05/22 15:23 von fritz_98