@@ -198,9 +198,14 @@ function type2dict(dt)
198198end
199199
200200"""
201+ reconstruct(pp; kws...
202+ reconstruct(T::Type, pp; kws...)
203+
201204Make a new instance of a type with the same values as the input type
202- except for the fields given in the AbstractDict second argument or as
203- keywords. Works for types, Dicts, and NamedTuples.
205+ except for the fields given in the keyword args. Works for types, Dicts,
206+ and NamedTuples. Can also reconstruct to another type, which is probably
207+ mostly useful for parameterised types where the parameter changes on
208+ reconstruction.
204209
205210Note: this is not very performant. Check Setfield.jl for a faster &
206211nicer implementation.
@@ -213,34 +218,56 @@ julia> struct A
213218 b
214219 end
215220
216- julia> a = A(3,4)
221+ julia> x = A(3,4)
217222A(3, 4)
218223
219- julia> b = reconstruct(a , b=99)
224+ julia> reconstruct(x , b=99)
220225A(3, 99)
226+
227+ julia> struct B{T}
228+ a::T
229+ b
230+ end
231+
232+ julia> y = B(sin, 1)
233+ B{typeof(sin)}(sin, 1)
234+
235+ julia> reconstruct(B, y, a=cos) # note reconstruct(y, a=cos) errors!
236+ B{typeof(cos)}(cos, 1)
221237```
222238"""
223- function reconstruct (pp:: T , di) where T
224- if pp isa AbstractDict
225- pp = deepcopy (pp)
226- for (k,v) in di
227- ! haskey (pp, k) && error (" Field $k not in type $T " )
228- pp[k] = v
239+ reconstruct (pp:: T , di) where T = reconstruct (T, pp, di)
240+ reconstruct (pp; kws... ) = reconstruct (pp, kws)
241+ reconstruct (T:: Type , pp; kws... ) = reconstruct (T, pp, kws)
242+ function reconstruct (:: Type{T} , pp, di) where T
243+ di = ! isa (di, AbstractDict) ? Dict (di) : copy (di)
244+ ns = if T<: AbstractDict
245+ if pp isa AbstractDict
246+ keys (pp)
247+ else
248+ fieldnames (typeof (pp))
229249 end
230- return pp
231250 else
232- di = ! isa (di, AbstractDict) ? Dict (di) : copy (di)
233- ns = fieldnames (T)
234- args = []
235- for (i,n) in enumerate (ns)
251+ fieldnames (T)
252+ end
253+ args = []
254+ for (i,n) in enumerate (ns)
255+ if pp isa AbstractDict
256+ push! (args, pop! (di, n, pp[n]))
257+ else
236258 push! (args, pop! (di, n, getfield (pp, n)))
237259 end
238- length (di)!= 0 && error (" Fields $(keys (di)) not in type $T " )
239- return pp isa NamedTuple ? T (Tuple (args)) : T (args... )
240260 end
241- end
242- reconstruct (pp; kws... ) = reconstruct (pp, kws)
261+ length (di)!= 0 && error (" Fields $(keys (di)) not in type $T " )
243262
263+ if T<: AbstractDict
264+ return T (zip (ns,args))
265+ elseif T <: NamedTuple
266+ return T (Tuple (args))
267+ else
268+ return T (args... )
269+ end
270+ end
244271
245272# ##########################
246273# Keyword constructors with @with_kw
0 commit comments