2012-07-02 10 views
5

Zamiast długiej listy argumentów w moich definicji funkcji, wolę zdać kilka parametrów stałych i tabelę „dodatkowe params” tak:LUA: Poszukujesz wydajne i bezbłędne środki przypisywania domyślnych argumentów

function:doit(text, params) 
end 

To miło, ponieważ pozwala mi dodawać nowe nazwane parametry później bez zrywania starych połączeń.

Problem mam przeżywa występuje przy próbie wymuszenia wartości domyślne dla niektórych params:

function:doit(text, params) 
    local font  = params.font or native.systemBold 
    local fontSize = params.fontSize or 24 
    local emboss = params.emboss or true 

    -- ... 

end 

Powyższy kod działa poprawnie we wszystkich przypadkach, z wyjątkiem gdzie przeszły w „false” na wytłaczanie :

doit("Test text", { fontSize = 32, emboss = false }) 

Powyższy kod spowoduje, że wytłoczenie zostanie ustawione na true, gdy naprawdę chcę mieć wartość false.

Aby było jasne, chcę, aby pierwsza wartość nie-NIL została przypisana do płaskorzeźby, zamiast tego otrzymuję pierwszą nie-fałszywą i nie-NIL.

Aby zwalczyć ten problem Napisałem kawałek kodu, aby znaleźć pierwszą wartość non-NIL w tabeli i do powrotu, że:

function firstNotNil(...) 
    for i = 1, #arg do 
     local theArg = arg[i] 
     if(theArg ~= nil) then return theArg end 
    end 
    return nil 
end 

Za pomocą tej funkcji chciałbym ponownie napisać zadanie etapie wytłaczania jako to:

local emboss = firstNotNil(params.emboss, true) 

Teraz to na pewno działa, ale wydaje się tak nieefektywne i przesadzone. Mam nadzieję, że istnieje bardziej zwarty sposób robienia tego.

Uwaga: znalazłem ten rubinowy konstrukt, który wyglądał obiecująco i mam nadzieję lua ma coś podobnego:

[c,b,a].detect { |i| i > 0 } -- Assign first non-zero in order: c,b,a 
+0

Czy sprawdziłeś [to poprzednie pytanie] (http://stackoverflow.com/questions/6022519/define-default-values-for-function-arguments) na podobny temat? – hugomg

+0

"Wydaje się tak nieefektywne" Czy masz rzeczywiste dane profilowania, aby to poprzeć, czy jest to jedna z tych rzeczy, których nie powinieneś się martwić? –

Odpowiedz

8

Lua oceniają wartości jednego z argumentów (czyli wartość nie jest zmuszany do Boolean), dzięki czemu może uzyskać odpowiednik potrójnego operatora C, mówiąc: a and b or c. W twoim przypadku, chcesz używać a jeśli to nie nil i b inaczej, więc a == nil and b or a:

local emboss = (params.emboss == nil) and true or params.emboss 

Nie tak bardzo jak wcześniej, ale chcesz tylko trzeba to zrobić dla parametrów logicznych.


[ciach - kod Lua]

Teraz, to na pewno działa, ale wydaje się tak nieefektywne i przesadzony.

Uwaga: znalazłem ten rubinowy konstrukt, który wyglądał obiecująco i mam nadzieję lua ma coś podobnego:

[C, B, A] .detect {| i | i> 0} - Przydziel pierwsze niezerowe w kolejności: c, b, a

Twoja funkcja Lua nie jest już zbyt wysoka lub nieefektywna. Konstrukcja Ruby jest bardziej zwięzła, jeśli chodzi o tekst źródłowy, ale semantyka nie różni się znacząco od firstNotNil(c,b,a). Obie konstrukcje kończą tworzenie obiektu listy, zainicjują go zestawem wartości, uruchamiając go za pomocą funkcji przeszukującej liniowo listę.

W Lua można pominąć tworzenie obiektu listy za pomocą wyrażenia vararg z select:

function firstNotNil(...) 
    for i = 1, select('#',...) do 
     local theArg = select(i,...) 
     if theArg ~= nil then return theArg end 
    end 
    return nil 
end 

Mam nadzieję, że jest bardziej zwarty sposób to zrobić.

Jedynym sposobem, aby to zrobić, jest skrócenie nazwy funkcji. ;)

+0

+1 za korzystanie z wybierz. Nie wiedziałem nawet o tej funkcji. –

+0

@Mud, pierwsze rozwiązanie 'local emboss = (params.emboss ~ = zero) i params.emboss lub true' nie zadziała, jeśli' params.emboss' jest 'false'. wartość 'emboss' zostanie ustawiona na' true', co nie jest tym, czego chce Ed. Rozwiązanie @ brando powinno działać. –

+0

@PaulKulchenko, masz rację ... to nie [praca] (http://ideone.com/JaOWN). – user46874

4

Jeśli naprawdę chcesz to zrobić w jednej linii, trzeba coś takiego to za wartość domyślna prawdziwej:

local emboss = params.emboss or (params.emboss == nil) 

to nie jest bardzo czytelny, ale to działa. (params.emboss == zero) zwraca wartość prawda, gdy parametr params.emboss nie jest ustawiony (gdy potrzebna jest wartość domyślna), w przeciwnym razie jest to wartość false. Tak więc, gdy params.emboss jest fałszywe, instrukcja jest fałszywa, a gdy jest prawdziwa, to wyrażenie jest prawdziwe (true lub false = true).

przypadku niewywiązania fałszywego, czego próbowali początkowo będzie działać: operatory relacyjne

local emboss = params.emboss or false 
Powiązane problemy