Funkcja Varargs z opcjonalnymi argumentami

Aug 20 2020

Mam skrypt foo.jlz funkcją, która może przyjmować 4 argumenty, z których 2 są opcjonalne. Z łatwością mogę to zrobić za pomocą

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

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

Mogę to nazwać argumentami z terminala za pomocą

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

Ale gdybym chciał podać tylko pierwsze dwa argumenty, aa za bpomocą c=1i d=2nie byłbym w stanie wywołać skryptu za pomocą, $:> julia foo.jl 1 2ponieważ skrypt nie zawiera wywołania funkcji z 2 argumentami. Wokół pracy jest pomiar długości ARGSw foo.jli warunkowo zadzwonić 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

Ale jest to trochę nieporęczne, gdy wykraczamy poza 4 argumenty. Więc przyjrzałem się użyciu zmiennych argumentów, w których mogłem wywołać dowolną liczbę argumentów za pomocą

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

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

nazywając to na wiele sposobów

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

Ale potem nie wiem, jak (lub czy jestem w stanie) ustawić domyślne ustawienie, x...jeśli nie jest dostępne w terminalu. Coś naiwnego function bar(a, b, x...=(1, 2))nie działa. Rozwiązaniem byłoby tutaj ustawienie zmiennych wewnątrz funkcji w zależności od zawartości lub rozmiaru x.... Ale nie wiem, czy istnieje lepszy sposób, aby to zrobić.

Szukam więc sposobu na wywołanie funkcji za pomocą argumentów z terminala, gdzie liczba (w tym przypadku 2) jest wymagana, a reszta jest opcjonalna i ustawiona na wartość domyślną.

Odpowiedzi

2 PrzemyslawSzufel Aug 20 2020 at 07:12

Być może szukasz następującej funkcji:

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

Ta funkcja będzie działać z dowolną liczbą parametrów pod warunkiem, że są co najmniej dwa z nich.

Przetestujmy z następującymi danymi:

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

Zobaczmy, jak to działa:

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

Na koniec zwróć uwagę, że to również jest w porządku:

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

W takim przypadku domyślnie (jeśli nie ma wystarczającej liczby wartości args) a6będzie po prostu jednym elementem, Tuplea jedynym elementem będzie Tuple ("6","7").