2012-07-02 11 views
5

Invece di usare lunghe liste di argomenti nelle mie definizioni di funzioni, preferisco passare un paio di parametri fissi e un tavolo di 'params aggiuntive' in questo modo:LUA: Alla ricerca di mezzi efficaci e senza errori di assegnazione argomenti di default

function:doit(text, params) 
end 

Questo è bello in quanto consente di aggiungere nuovi parametri denominati in seguito senza interrompere le chiamate precedenti.

Il problema che sto vivendo si verifica quando si tenta di forzare i valori di default per alcuni dei 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 

Il codice di cui sopra funziona bene in tutti i casi, tranne quando sono passato a 'false' per rilievo :

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

Il codice sopra riportato farà sì che il rilievo venga impostato su true quando volevo veramente che fosse falso.

Per essere chiari, quello che voglio è che il primo valore non NIL venga assegnato a rilievo, invece sto ricevendo un primo non-falso e non-NIL.

Per combattere questo problema ho scritto un piccolo pezzo di codice per trovare il primo valore non NIL in una tabella e di ritornare che:

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

Usando questa funzione avrei riscrivere l'assegnazione rilievo come segue:

local emboss = firstNotNil(params.emboss, true) 

Ora, questo funziona certamente, ma sembra così inefficiente e sopra le righe. Spero che ci sia un modo più compatto per farlo.

Si prega di notare: Ho trovato questo rubino costrutto che sembrava promettente e spero Lua ha qualcosa di simile:

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

Hai estratto [questa domanda precedente] (http://stackoverflow.com/questions/6022519/define-default-values-for-function-arguments) su un argomento simile? – hugomg

+0

"sembra così inefficiente" Hai dati di profilazione effettivi per eseguire il backup, o è solo una di quelle cose di cui non dovresti davvero preoccuparti? –

risposta

8

di Lua restituiscono il valore di uno degli operandi (cioè il valore non è costretto a booleano) in modo da può ottenere l'equivalente dell'operatore ternario di C dicendo a and b or c. Nel tuo caso, si desidera utilizzare a se non è nil e b altrimenti, in modo a == nil and b or a:

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

Non bella come prima, ma si sarebbe solo bisogno di farlo per i parametri booleani.


[omissis - codice Lua]

Ora, questo funziona certamente, ma sembra così inefficiente e sopra le righe.

Si prega di notare: Ho trovato questo rubino costrutto che sembrava promettente e spero Lua ha qualcosa di simile:

[c, b, a] .detect {| i | i> 0} - Assegnare primo non-zero in ordine: c, b, a

La funzione Lua non più over-the-top o inefficienti è. Il costrutto Ruby è più succinto, in termini di testo di origine, ma la semantica non è molto diversa da firstNotNil(c,b,a). Entrambi i costrutti finiscono per creare un oggetto lista, inizializzarlo con un insieme di valori, eseguendolo tramite una funzione che ricerca linearmente l'elenco.

In Lua si potrebbe saltare la creazione dell'oggetto elenco utilizzando l'espressione vararg con select:

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

Sto sperando che ci sia un modo più compatto di fare questo.

L'unico modo per farlo sarebbe quello di abbreviare il nome della funzione. ;)

+0

+1 per l'uso di select. Non sapevo nemmeno di quella funzione. –

+0

@Mud, la prima soluzione 'local emboss = (params.emboss ~ = nil) e params.emboss o true' non funzionerà se' params.emboss' è 'false'. Il valore 'emboss' sarà impostato su' true', che non è quello che Ed vuole. la soluzione di @ brando dovrebbe funzionare –

+0

@PaulKulchenko, hai ragione ... non funziona [http://ideone.com/JaOWN]. – user46874

4

Se davvero si vuole farlo in una sola riga, avrete bisogno di qualcosa di simile questo per un valore di default di vera:

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

non è molto leggibile, ma funziona. (params.emboss == nil) restituisce true quando params.emboss non è impostato (quando è necessario un valore predefinito), altrimenti è falso. Quindi, quando params.emboss è falso, l'affermazione è falsa e, quando è vera, l'affermazione è vera (true o false = true).

Per un default di falsa, quello che si è tentato in origine avrebbe funzionato: operatori relazionali

local emboss = params.emboss or false 
Problemi correlati