Definieren Sie Standardwerte für Funktionsargumente

84

Im Lua-Wiki habe ich eine Möglichkeit gefunden, Standardwerte für fehlende Argumente zu definieren:

function myfunction(a,b,c)
    b = b or 7
    c = c or 5
    print (a,b,c)
end

Ist das der einzige Weg? Der PHP-Stil myfunction (a,b=7,c=5)scheint nicht zu funktionieren. Nicht dass der Lua-Weg nicht funktioniert, ich frage mich nur, ob dies der einzige Weg ist, dies zu tun.

ripat
quelle

Antworten:

85

Wenn Sie benannte Argumente und Standardwerte wie PHP oder Python möchten, können Sie Ihre Funktion mit einem Tabellenkonstruktor aufrufen:

myfunction{a,b=3,c=2}

(Dies ist an vielen Stellen in Lua zu beobachten, beispielsweise in den fortgeschrittenen Formen der Protokollmodule und Konstruktoren von LuaSocket in IUPLua .)

Die Funktion selbst könnte eine folgende Signatur haben:

function myfunction(t)
    setmetatable(t,{__index={b=7, c=5}})
    local a, b, c =
      t[1] or t.a, 
      t[2] or t.b,
      t[3] or t.c
    -- function continues down here...
end

Alle in der Parametertabelle fehlenden Werte werden aus der __indexTabelle in ihrer Metatabelle übernommen (siehe Dokumentation zu Metatabellen ).

Natürlich sind erweiterte Tabellenstile mithilfe von Tabellenkonstruktoren und -funktionen möglich. Sie können alles schreiben, was Sie benötigen. Zum Beispiel, hier ist eine Funktion , die eine Funktion konstruiert , die Namen-oder-Positions Argument Tabellen aus einer Tabelle eine reguläres Argument unter Liste definieren , die Parameternamen und Standardwerte und eine Funktion übernimmt.

Als Funktion auf Nicht-Sprachebene können solche Aufrufe geändert werden, um neue Verhaltensweisen und Semantiken bereitzustellen:

  • Variablen können so eingestellt werden, dass sie mehr als einen Namen akzeptieren
  • Positionsvariablen und Schlüsselwortvariablen können eingestreut werden - und die Definition beider Variablen kann entweder Vorrang haben (oder einen Fehler verursachen).
  • Positionslose Variablen nur mit Schlüsselwörtern sowie namenlose Positionsvariablen können erstellt werden
  • Die ziemlich ausführliche Tabellenkonstruktion könnte durch Parsen einer Zeichenfolge erfolgen
  • Die Argumentliste kann wörtlich verwendet werden, wenn die Funktion mit einer anderen Tabelle als 1 aufgerufen wird

Einige nützliche Funktionen zum Schreiben von Argumentübersetzern sind unpack(Verschieben table.unpackin 5.2), setfenv(in 5.2 mit der neuen _ENVKonstruktion veraltet ) und select(die einen einzelnen Wert aus einer bestimmten Argumentliste oder die Länge der Liste mit zurückgeben '#').

Stuart P. Bentley
quelle
AI hat gerade angefangen, lua zu verwenden. Ich werde es für die Zeit einfach halten, aber Ihr Beitrag ist sehr informativ. Könnte später nützlich sein. Vielen Dank.
Ripat
1
In den meisten Fällen ist es der richtige Weg, es einfach zu halten. Metaparameter-Schnittstellen sind nur für Objekte mit einer großen Anzahl optionaler Attribute (z. B. UI-Objekte) wirklich erforderlich.
Stuart P. Bentley
Ich denke, diese Antwort ist diejenige, die die Fragen löst, nicht die, die derzeit als akzeptiert markiert ist. Danke für die Erleuchtung :)
Rückgängig machen
1
Es sollte beachtet werden, dass der x or defaultAusdruck, der auch in dieser Antwort verwendet wird, nicht wirklich den Standardwerten der Parameter entspricht, sondern nur eine vereinfachte Problemumgehung, die nur funktioniert, wenn beide nilund falseungültige Parameterwerte sind. Angenommen, der Standardwert für einen booleschen Parameter xist trueund der Aufrufer übergibt einen expliziten Wert false. Dann x or truegibt true, obwohl falseexplizit übergeben wurde. Eine bessere Version wäre if x == nil then x = default end, die auch besser lesbar ist; Es kann jedoch immer noch keine expliziten nilArgumente verarbeiten.
Jesper
Oh, hey, das ist jetzt die akzeptierte Antwort! Nett. (Für die Aufzeichnung und um den Kommentar von @ Undo in einen Zusammenhang zu bringen, war die Antwort von jpjacobs unten die akzeptierte Antwort für eine sehr lange Zeit: Ich habe fast ein zweites populistisches Abzeichen darüber bekommen.)
Stuart P. Bentley
45

Meiner Meinung nach gibt es keinen anderen Weg. Das ist nur die Lua-Mentalität: kein Schnickschnack und bis auf etwas syntaktischen Zucker keine überflüssigen Methoden, um einfache Dinge zu tun.

jpjacobs
quelle
10
Diese Antwort wird durch die folgende Antwort von Stuart P. Bentley, in der die Funktion mit einem Tabellenkonstruktor aufgerufen wird, vollständig widerlegt. Dies ist eine der Stärken von Lua: Obwohl es nicht viel Schnickschnack gibt, können Sie mit den Grundbausteinen von Lua grenzenlose Dinge tun, die für die geringe Größe und Einfachheit der Sprache wirklich bemerkenswert sind.
Colin D Bennett
@ColinDBennett Vielen Dank für Ihr Wort: Es scheint, dass das OP Ihren Kommentar gelesen und im Dezember die akzeptierte Antwort entsprechend geändert hat. (Und jetzt ist es "Stuart P. Bentleys Antwort oben", der Klarheit halber: zwinker :)
Stuart P. Bentley
21

Technisch gesehen gibt es b = b == nil and 7 or b(was verwendet werden sollte, wenn falseein gültiger Wert false or 7mit 7 bewertet wird), aber das ist wahrscheinlich nicht das, wonach Sie suchen.

Stuart P. Bentley
quelle
1
Wenn Sie nicht nach suchen false, ist es einfacher, die Variable zuerst und die Standardeinstellung zuletzt zu setzen. b = b or 7
Rebs
2
Da das OP dies in seiner Frage erwähnte, hielt ich es für überflüssig zu erwähnen (die Frage betraf Möglichkeiten, andere Standardvariablen als zu definieren b = b or 7).
Stuart P. Bentley
6

Der einzige Weg, den ich bisher gefunden habe, der Sinn macht, ist, so etwas zu tun:

function new(params)
  params = params or {}
  options = {
    name = "Object name"
  }

  for k,v in pairs(params) do options[k] = v end

  some_var = options.name
end

new({ name = "test" })
new()
NineBlindEyes
quelle