Zdefiniuj wartości domyślne argumentów funkcji

86

W wiki Lua znalazłem sposób na zdefiniowanie domyślnych wartości brakujących argumentów:

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

Czy to jedyny sposób? Wygląda na to, że styl PHP myfunction (a,b=7,c=5)nie działa. Nie żeby sposób Lua nie działał, po prostu zastanawiam się, czy to jedyny sposób, aby to zrobić.

ripat
źródło

Odpowiedzi:

86

Jeśli potrzebujesz nazwanych argumentów i wartości domyślnych, takich jak PHP lub Python, możesz wywołać swoją funkcję za pomocą konstruktora tabeli:

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

(Widać to w wielu miejscach w Lua, na przykład w zaawansowanych formach modułów protokołu LuaSocket i konstruktorów w IUPLua ).

Sama funkcja mogłaby mieć taki podpis:

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

Wszelkie wartości brakujące w tabeli parametrów zostaną pobrane z __indextabeli w jej metatabeli (zobacz dokumentację dotyczącą metatabeli ).

Oczywiście bardziej zaawansowane style parametrów są możliwe przy użyciu konstruktorów tabel i funkcji - możesz napisać wszystko, czego potrzebujesz. Na przykład tutaj jest funkcja, która konstruuje funkcję, która pobiera tabele nazwanych lub pozycyjnych argumentów z tabeli definiującej nazwy parametrów i wartości domyślne oraz funkcję pobierającą zwykłą listę argumentów.

Jako funkcja niezwiązana z językiem, takie wywołania można zmienić, aby zapewnić nowe zachowania i semantykę:

  • Zmienne można sprawić, aby akceptowały więcej niż jedną nazwę
  • Zmienne pozycyjne i zmienne słów kluczowych mogą być przeplatane - a zdefiniowanie obu może dać pierwszeństwo jednej z nich (lub spowodować błąd)
  • Można tworzyć zmienne bez pozycji zawierające tylko słowa kluczowe, a także bezimienne, zawierające tylko pozycje
  • Dość rozwlekłą konstrukcję tabeli można wykonać, analizując ciąg
  • Lista argumentów może być użyta dosłownie, jeśli funkcja jest wywoływana z czymś innym niż 1 tabela

Niektóre przydatne funkcje do pisania translatorów argumentów to unpack(przejście do wersji table.unpack5.2), setfenv(przestarzałe w wersji 5.2 z nową _ENVkonstrukcją) i select(które zwraca pojedynczą wartość z podanej listy argumentów lub długość listy z '#').

Stuart P. Bentley
źródło
AI właśnie zacząłem używać lua. Na razie postaram się to uprościć, ale Twój post zawiera wiele informacji. Może się później przydać. Dzięki.
ripat
1
W większości przypadków należy zachować prostotę. Interfejsy metaparametrów są naprawdę potrzebne tylko w przypadku obiektów z dużą liczbą opcjonalnych atrybutów (takich jak obiekty UI).
Stuart P. Bentley
Myślę, że ta odpowiedź jest tą, która rozwiązuje pytania, a nie ta, która jest obecnie oznaczona jako zaakceptowana. Dzięki za oświecenie :)
Cofnij
1
Należy zauważyć, że x or defaultwyrażenie użyte również w tej odpowiedzi nie jest tak naprawdę prawdziwym odpowiednikiem wartości domyślnych parametrów, ale tylko uproszczonym obejściem, które działa tylko wtedy, gdy oba nili falsesą niepoprawnymi wartościami parametrów. Powiedzmy, że domyślnym parametrem boolowskim xjest, truea obiekt wywołujący przekazuje jawne false. Następnie x or truedaje true, mimo że falsezostał wyraźnie przekazany. Byłaby lepsza wersja if x == nil then x = default end, która jest również bardziej czytelna; jednak nadal nie obsługuje jawnych nilargumentów.
Jesper
Och, hej, to jest teraz akceptowana odpowiedź! Ładny. (Dla porządku, i żeby umieścić komentarz @ Undo w kontekście, odpowiedź jpjacobs poniżej była akceptowaną odpowiedzią przez bardzo długi czas: prawie dostałem nad nią drugą odznakę Populist .)
Stuart P. Bentley
46

Moim zdaniem nie ma innego sposobu. To tylko mentalność Lua: bez fanaberii i poza odrobiną cukru syntaktycznego, bez zbędnych sposobów robienia prostych rzeczy.

jpjacobs
źródło
10
Tej odpowiedzi całkowicie obala poniższa odpowiedź Stuarta P. Bentleya, w której funkcja jest wywoływana za pomocą konstruktora tabeli. To jedna z mocnych stron Lua: chociaż nie ma wielu dodatków, podstawowe elementy składowe Lua pozwalają robić nieograniczone rzeczy, naprawdę niezwykłe ze względu na niewielki rozmiar i prostotę języka.
Colin D Bennett
@ColinDBennett Dzięki za zabranie głosu: wydaje się, że OP przeczytał Twój komentarz i tego grudnia odpowiednio zmienił zaakceptowaną odpowiedź. (A teraz jest to "odpowiedź Stuarta P. Bentleya powyżej", dla jasności: mrugnięcie :)
Stuart P. Bentley
21

Technicznie rzecz biorąc, jest b = b == nil and 7 or b(co powinno być używane w przypadku, gdy falsejest to prawidłowa wartość, ponieważ wynosi false or 77), ale prawdopodobnie nie tego szukasz.

Stuart P. Bentley
źródło
1
Jeśli nie sprawdzasz false, prostszym sposobem jest umieszczenie zmiennej jako pierwszej, a domyślnej jako ostatniej. b = b or 7
Rebs
2
Ponieważ OP wspomniał o tym w swoim pytaniu, doszedłem do wniosku, że byłoby to zbędne (pytanie dotyczyło sposobów definiowania zmiennych domyślnych innych niż b = b or 7 ).
Stuart P. Bentley
6

Jedyny sposób, który do tej pory ma sens, to zrobić coś takiego:

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
źródło