La raison en est que les arguments de mots clés éclaboussés ne sont pas stockés par défaut dans un tuple nommé. Nous pouvons voir comment ils sont stockés comme suit:
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}}}
Ainsi, les kwargs éclaboussés sont stockés à la place comme une sorte d'objet itérateur. Cependant, nous pouvons facilement convertir cet kwargs
itérateur en NamedTuple comme ceci: (;kwargs...)
puis y accéder de la manière attendue, de sorte que votre exemple se traduira par
julia> f(args...; kwargs...) = (;kwargs...).x
f (generic function with 1 method)
julia> f(x=1, y=2)
1
Bien sûr, la façon la plus idiomatique de le faire serait d'écrire la fonction à la place
julia> f(args...; x, kwargs...) = x
f (generic function with 1 method)
julia> f(x=1, y=2)
1
mais cela suppose que vous connaissez le nom x
auquel vous souhaitez accéder ( ) au moment où vous écrivez la fonction.
Une brève note: si nous revenons à notre exemple de g(;kwargs...) = kwargs
, nous pouvons demander les noms de champs de l'objet itérateur qui a été renvoyé comme suit:
julia> g(x=1, y=2) |> typeof |> fieldnames
(:data, :itr)
Hm, quel est ce data
champ?
julia> g(x=1, y=2).data
(x = 1, y = 2)
Ah! donc nous pouvons réellement obtenir les kwargs en tant que tuple nommé en utilisant cela, c'est-à f(;kwargs...) = kwargs.data.x
- dire que cela fonctionnerait, mais je ne recommanderais pas cette approche car elle semble s'appuyer sur un comportement non documenté, il peut donc s'agir d'un simple détail d'implémentation qui n'est pas garanti d'être stable à travers les versions de julia.