Função Varargs com argumentos opcionais

Aug 20 2020

Eu tenho um script foo.jlcom uma função que pode receber 4 argumentos, 2 dos quais são opcionais. Eu posso fazer isso facilmente com

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

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

Posso chamar isso com argumentos do terminal com

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

Mas se eu quisesse especificar apenas os dois primeiros argumentos ae b, com c=1e d=2, não seria capaz de chamar o script com, $:> julia foo.jl 1 2pois o script não contém uma chamada de função com 2 argumentos. Um em torno do trabalho é medir o comprimento ARGSem foo.jle condicionalmente chamar 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

Mas isso é um pouco pesado ao passar de 4 argumentos. Então, olhei para usar argumentos variáveis, onde poderia chamar um número arbitrário de argumentos com

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

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

chamando isso de várias maneiras

$:> 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"],)

Mas eu não sei como (ou se posso) definir um padrão para x...caso não seja fornecido no terminal. Algo ingênuo como function bar(a, b, x...=(1, 2))não funciona. Uma solução aqui seria definir as variáveis ​​dentro da função dependendo do conteúdo ou tamanho de x.... Mas não sei se existe uma maneira melhor de fazer isso.

Portanto, estou procurando uma maneira de chamar uma função usando argumentos do terminal, onde um número (2 neste caso) é necessário, enquanto o resto é opcional e definido como padrão.

Respostas

2 PrzemyslawSzufel Aug 20 2020 at 07:12

Talvez você esteja procurando a seguinte função:

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 função funcionará com qualquer número de parâmetros, desde que haja pelo menos dois deles.

Vamos testar com os seguintes dados:

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

Vamos ver como isso 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, observe que isso também está OK:

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...)

Nesse caso, por padrão (se não houver valores suficientes args) a6, será simplesmente um elemento Tuplecom o único elemento sendo um Tuple ("6","7").