Причина цього відбувається в тому, що аргументовані аргументи ключових слів за замовчуванням не зберігаються у названому кортежі. Ми можемо бачити, як вони зберігаються так:
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}}}
Таким чином, заплетені кварги замість цього зберігаються як якийсь об’єкт ітератора. Однак ми можемо легко перетворити цей kwargs
ітератор в NamedTuple так: (;kwargs...)
і потім отримати доступ до нього так, як ми очікували, щоб ваш приклад перетворився на
julia> f(args...; kwargs...) = (;kwargs...).x
f (generic function with 1 method)
julia> f(x=1, y=2)
1
Звичайно, більш ідіоматичним способом зробити це було б замість цього записати функцію як
julia> f(args...; x, kwargs...) = x
f (generic function with 1 method)
julia> f(x=1, y=2)
1
але це передбачає, що ви знаєте ім'я, до якого ви хочете отримати доступ ( x
) під час написання функції.
Короткий посилання: Якщо ми повернемося до нашого прикладу g(;kwargs...) = kwargs
, ми можемо запитати імена полів об’єкта ітератора, який було повернуто так:
julia> g(x=1, y=2) |> typeof |> fieldnames
(:data, :itr)
Гм, що це за data
поле?
julia> g(x=1, y=2).data
(x = 1, y = 2)
Ага! тому ми можемо насправді отримати кворгів як названий кортеж, використовуючи це, тобто f(;kwargs...) = kwargs.data.x
працював би, але я б не рекомендував цей підхід, оскільки він, мабуть, покладається на недокументовану поведінку, тому це може бути просто деталізацією щодо впровадження, яка не гарантує стабільності. у версіях Джулії.