@@ -198,9 +198,14 @@ function type2dict(dt)
198
198
end
199
199
200
200
"""
201
+ reconstruct(pp; kws...
202
+ reconstruct(T::Type, pp; kws...)
203
+
201
204
Make 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.
204
209
205
210
Note: this is not very performant. Check Setfield.jl for a faster &
206
211
nicer implementation.
@@ -213,34 +218,56 @@ julia> struct A
213
218
b
214
219
end
215
220
216
- julia> a = A(3,4)
221
+ julia> x = A(3,4)
217
222
A(3, 4)
218
223
219
- julia> b = reconstruct(a , b=99)
224
+ julia> reconstruct(x , b=99)
220
225
A(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)
221
237
```
222
238
"""
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))
229
249
end
230
- return pp
231
250
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
236
258
push! (args, pop! (di, n, getfield (pp, n)))
237
259
end
238
- length (di)!= 0 && error (" Fields $(keys (di)) not in type $T " )
239
- return pp isa NamedTuple ? T (Tuple (args)) : T (args... )
240
260
end
241
- end
242
- reconstruct (pp; kws... ) = reconstruct (pp, kws)
261
+ length (di)!= 0 && error (" Fields $(keys (di)) not in type $T " )
243
262
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
244
271
245
272
# ##########################
246
273
# Keyword constructors with @with_kw
0 commit comments