2011-08-25 18 views
19

Estoy intentando crear una función de impresión de depuración que toma un identificador de archivo como primer argumento. En primer lugar, escribo una función como esta:En Lua, ¿cuál es la forma correcta de manejar varargs que contiene nil?

function fprint (f, ...) 
    for i, v in ipairs{...} do 
     f:write(tostring(v)) 
     f:write("\t") 
    end 
    f:write("\n") 
end 

Esta función funciona siempre y cuando no paso nil valor en argumentos. Pero si llamo esto con un nil, no imprime el valor nil y el resto de los argumentos.

fprint(io.stderr, 1, 2, nil, 3) 
=> prints only 1 and 2 

Entonces, ¿cuál es la forma correcta de resolver este problema?

Respuesta

26

En realidad, es fácil de manejar nil valores en varargs, todo lo que necesita es usar la función select, que funciona incluso con nil (cuenta el número real de parámetros). La siguiente modismo es tan útil que es una función de biblioteca núcleo table.pack en Lua 5.2:

function table.pack(...) 
    return { n = select("#", ...), ... } 
end 

El número de argumentos se almacena en el campo n, por lo que con el fin de iterar a través de ellos sólo tiene que utilizar esto:

function vararg(...) 
    local args = table.pack(...) 
    for i=1,args.n do 
     -- do something with args[i], careful, it might be nil! 
    end 
end 
+1

¡Dulce! No sabía sobre 'seleccionar'. – torus

+2

Una adición muy útil es que ya no se puede 'descomprimir 'la tabla. Para desempaquetar use: 'local tbl = {n = select (" # ", ...), ...}; print (unpack (tbl, 1, tbl.n)); ' – Aidiakapi

+0

Esta respuesta fue discutida en detalle en la wiki oficial: http://lua-users.org/wiki/VarargTheSecondClassCitizen –

2

Como mejor que sé, no hay manera independiente de fácil aplicación para conocer la longitud de una matriz que contiene nil entradas desde la operación # puede apuntar a cualquier posición que es seguido por un nil, pero esto es una solución depende de la implementación rápida que imprimirá el nil.

function fprint (f, ...) 
    local parm={...} 
    for i=1,#parm do 
     f:write(tostring(parm[i])) 
     f:write("\t") 
    end 
    f:write("\n") 
end 

En lugar de la retransmisión en #, puede ser complicado (y por lo tanto independiente de la implementación) ya que usted sabe la tabla parm es una matriz y usar algo como esto:

function last_index(array) 
    local max = 0 
    for k, _ in pairs(array) do 
    max = math.max(max, k) 
    end 
    return max 
end 

function fprint (f, ...) 
    local parm={...} 
    for i=1,last_index(parm) do 
     f:write(tostring(parm[i])) 
     f:write("\t") 
    end 
    f:write("\n") 
end 

Si se puede omitir el nil valores y el orden no es importante, entonces cambiar a pairs sería mucho más fácil.

+0

Gracias! Intentaré cambiar a pares. – torus

+0

Obviamente, la respuesta de Michael es la mejor, incluso la hice +1, pero ¿hay alguna otra razón para el voto negativo? – BMitch

+0

No. He subido dos de las dos respuestas :) – torus

Cuestiones relacionadas