Il motivo per cui ciò accade è che gli argomenti di parole chiave splattate non sono memorizzati in una tupla nominata per impostazione predefinita. Possiamo vedere come sono memorizzati in questo modo:
julia> g(;kwargs...) = kwargs
g (generic function with 1 method)
julia> g(a=1)
pairs(::NamedTuple) with 1 entry:
:a => 1
julia> g(a=1) |> typeof
Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:a,),Tuple{Int64}}}
Quindi i kwarg splattati vengono invece memorizzati come una sorta di oggetto iteratore. Tuttavia, possiamo facilmente convertire kwargs
quell'iteratore in una NamedTuple in questo modo: (;kwargs...)
e quindi accedervi come ci aspetteremmo, quindi il tuo esempio si tradurrebbe in
julia> f(args...; kwargs...) = (;kwargs...).x
f (generic function with 1 method)
julia> f(x=1, y=2)
1
Ovviamente, il modo più idiomatico per farlo sarebbe invece scrivere la funzione come
julia> f(args...; x, kwargs...) = x
f (generic function with 1 method)
julia> f(x=1, y=2)
1
ma questo presuppone che tu conosca il nome a cui vuoi accedere ( x
) nel momento in cui scrivi la funzione.
Un breve sidenote: se torniamo al nostro esempio di g(;kwargs...) = kwargs
, possiamo chiedere i nomi dei campi dell'oggetto iteratore che è stato restituito in questo modo:
julia> g(x=1, y=2) |> typeof |> fieldnames
(:data, :itr)
Hm, che cos'è questo data
campo?
julia> g(x=1, y=2).data
(x = 1, y = 2)
Aha! quindi possiamo effettivamente ottenere i kwarg come tupla nominata usando quello, cioè f(;kwargs...) = kwargs.data.x
funzionerebbe, ma non consiglierei questo approccio poiché sembra basarsi su comportamenti privi di documenti, quindi potrebbe essere un semplice dettaglio di implementazione che non è garantito essere stabile attraverso le versioni di julia.