Setindex для именованного кортежа - PullRequest
0 голосов
/ 05 ноября 2018

Я пытаюсь написать неизменяемый setindex для именованного кортежа, где для типа имени 100 * * создается новый именованный кортеж, где x.var = y. Что у меня сейчас есть:

function setindex(nt::T,x,v::Val{var}) where {T,var}
  if var ∉ fieldnames(T)
    return x
  else
    typeof(x)(s == var ? y : w for (s,w) in nt)
  end
end

, но моя главная проблема в том, что я не уверен в хорошем способе итерации именованного кортежа для получения пар (name,value).

Ответы [ 2 ]

0 голосов
/ 05 ноября 2018

Это версия @generated. Сгенерированный код очень прост и стабилен.

julia> @generated function setindex(x::NamedTuple,y,v::Val)
         k = first(v.parameters)
         k ∉ x.names ? :x : :( (x..., $k=y) )
       end

julia> @code_warntype setindex((a=2, b=3), 4, Val(:b))
Body::NamedTuple{(:a, :b),Tuple{Int64,Int64}}
2 1 ─ %1 = (Base.getfield)(x, :a)::Int64                                                               │╻╷╷   macro expansion
  │   %2 = %new(NamedTuple{(:a, :b),Tuple{Int64,Int64}}, %1, y)::NamedTuple{(:a, :b),Tuple{Int64,Int64}}│┃││╷  merge
  └──      return %2                                                                                   ││    

julia> @code_warntype setindex((a=2, b=3), 4, Val(:c))
Body::NamedTuple{(:a, :b),Tuple{Int64,Int64}}
2 1 ─     return x
0 голосов
/ 05 ноября 2018

Вы можете использовать pairs, который дает итератор для пар ключ-значение, или использовать fieldnames с типом T и получить доступ к значению с помощью nt[name] или (используйте keys с именованной переменной кортежа такой же путь). Я думаю, что вы предпочитаете pairs.

function setindex(nt::T,y,v::Val{var}) where {T,var}
  if var ∉ fieldnames(T)
    return nt
  else
    T(s == var ? y : w for (s,w) in pairs(nt))
  end
end

или

function setindex(nt::T,y,v::Val{var}) where {T,var}
  if var ∉ fieldnames(T)
    return nt
  else
    T(k == var ? y : nt[k] for k in fieldnames(T))
  end
end
...