Función varargs con argumentos opcionales

Aug 20 2020

Tengo un script foo.jlcon una función que puede tomar 4 argumentos, 2 de los cuales son opcionales. Puedo hacer esto fácilmente con

function bar(a, b, c=1, d=2)
    println(a, b, c, d)
end

bar(ARGS[1], ARGS[2], ARGS[3], ARGS[4])

Puedo llamar a esto con argumentos desde la terminal con

$:> julia foo.jl 1 2 3 4
1234

Pero si quisiera especificar solo los dos primeros argumentos ay b, con c=1y d=2, no podría llamar al script con $:> julia foo.jl 1 2ya que el script no contiene una llamada a función con 2 argumentos. Una solución alternativa es medir la longitud de ARGSin foo.jly llamar condicionalmente bar:

if length(ARGS) == 2
    bar(ARGS[1], ARGS[2])
elseif length(ARGS) == 3
    bar(ARGS[1], ARGS[2], ARGS[3])
else
    bar(ARGS[1], ARGS[2], ARGS[3], ARGS[4])
end

Pero esto es un poco voluminoso cuando se pasa de 4 argumentos. Así que miré el uso de argumentos variables, donde podría llamar a un número arbitrario de argumentos con

function bar(a, b, x...)
    println(a, b, x)
end

bar(ARGS[1], ARGS[2], ARGS[3:end])

llamando a esto de múltiples maneras

$:> julia foo.jl 1 2 12(String[],) $:> julia foo.jl 1 2 3 4
12(["3", "4"],)
$:> julia foo.jl 1 2 3 4 5 6
12(["3", "4", "5", "6"],)

Pero entonces no sé cómo (o si puedo) establecer un valor predeterminado para x...si no se proporciona en la terminal. Algo ingenuo como function bar(a, b, x...=(1, 2))no funciona. Una solución aquí sería establecer las variables dentro de la función según el contenido o el tamaño de x.... Pero no sé si hay una mejor manera de hacer esto.

Así que estoy buscando una forma de llamar a una función usando argumentos de la terminal, donde se requiere un número (2 en este caso), mientras que el resto son opcionales y están configurados por defecto.

Respuestas

2 PrzemyslawSzufel Aug 20 2020 at 07:12

Quizás esté buscando la siguiente función:

function flexiargs(a1,a2,a3="3",a4="4",a5="5",a6...)
    println((a1,a2,a3,a4,a5,a6))
end
flexiargs(args::AbstractVector)=flexiargs(args...)

Esta función funcionará con cualquier número de parámetros siempre que haya al menos dos de ellos.

Probemos con los siguientes datos:

args0=["one","two"]
args1=["one","two","three","four"];
args2=vcat(args,"five","six","seven") 

Vamos a ver cómo funciona:

julia> flexiargs(args0)
("one", "two", "3", "4", "5", ())

julia> flexiargs(args1)
("one", "two", "three", "four", "5", ())

julia> flexiargs(args2)
("one", "two", "three", "four", "five", ("six", "seven"))

Finalmente, tenga en cuenta que esto también está bien:

function flexiargs(a1,a2,a3="3",a4="4",a5="5",a6...=("6","7"))
    println((a1,a2,a3,a4,a5,a6))
end
flexiargs(args::AbstractVector)=flexiargs(args...)

En ese caso, de forma predeterminada (si no hay suficientes valores args) a6, será simplemente un elemento, Tuplesiendo el único elemento un Tuple ("6","7").