deepcopy
Copy object deeply
Usages
deepcopy
eventdeep.New, eventdeep.MakeClone and eventdeep.DeepCopy are main entries.
By default, DeepCopy() will copy and merge source into destination object. That means, a map or a slice will be
merged
deeply, same to a struct.
New(opts...) gives a most even scalable interface
than DeepCopy, it returns a new DeepCopier different to DefaultCopyController and you can make call
to DeepCopier.DeepCopy(old, new, opts...).
In copy-n-merge mode, copying [2, 3] to [3, 7] will get [3, 7, 2].
Getting Started
Here is a basic sample code:
Customizing The Field Extractor
For the unconventional deep copy, we can copy field to field via a source extractor.
You need a target struct at first.
Customizing The Target Setter
As a contrary, you might specify a setter to handle the setting action on copying struct and/or map.
NOTE that the feature is only fit for copying on/between struct and/or map.
If you really wanna customize the setter for primitives or others, concern to implement a ValueCopier or ValueConverter.
ByOrdinal or ByName
evendeep enumerates fields in struct/map/slice with two strategies: ByOrdinal and ByName.
- Default
ByOrdinalassumes the copier loops all source fields and copy them to the corresponding destination with the ordinal order. ByNamestrategy assumes the copier loops all target fields, and try copying value from the coressponding source field by its name.
When a name conversion rule is defined in a struct field tag, the copier will look for the name and copy value to, even
if it's in ByOrdinal mode.
Customizing A Converter
The customized Type/Value Converter can be applied on transforming the data from source. For more information take a
look ValueConverter
and ValueCopier. Its take effects on checking the value
type of target or source, or both of them.
Instead of WithValueConverters / WithValueCopiers for each times invoking New(), you might register yours once by
calling RegisterDefaultConverters / RegisterDefaultCopiers into global registry.
Zero Target Fields If Equals To Source
When we compare two Struct, the target one can be clear to zero except a field value is not equal to source field. This
feature can be used for your ORM codes: someone loads a record as a golang struct variable, and make some changes, and
invoking eventdeep.DeepCopy(originRec, &newRecord, eventdeep.WithORMDiffOpt), the changes will be kept in newRecord
and the others unchanged fields be cleanup at last.
The codes are:
Keep The Target Value If Source Is Empty
Sometimes we would look for a do-not-modify copier, it'll keep the value of target fields while the corresponding source
field is empty (zero or nil). Use eventdeep.WithOmitEmptyOpt in the case.
String Marshalling
While copying struct, map, slice, or other source to target string, the builtin toStringConverter will be launched.
And the default logic includes marshaling the structural source to string, typically json.Marshal.
This marshaller can be customized: RegisterStringMarshaller and WithStringMarshaller enable it:
The default marshaler is a wraper to json.MarshalIndent.
Specify CopyMergeStrategy via struct Tag
Sample struct is (use copy as key):
Name conversions
copy tag has form: nameConversion[,strategies...]. nameConversion gives a target field Name to define a name
conversion strategy, or - to ignore the field.
nameConversion has form:
-: field is ignoredtargetName->targetNamesourceName->targetName
Spaces besides of -> are allowed.
Copier will check target field tag at first, and following by a source field tag checking.
You may specify converting rule at either target or source side, Copier assume the target one is prior.
NOTE: nameConversion is fully functional only for cms.ByName mode. It get partial work in cms.ByOrdinal mode (
default mode).
TODO: In cms.ByOrdinal (*) mode, a name converter can be applied in copying field to field.
Sample codes
The test gives a sample to show you how the name-conversion and member function work together:
Strategy Names
The available tag names are (Almost newest, see its in flags/cms/copymergestrategy.go):
| Tag name | Flags | Detail |
|---|---|---|
- | cms.Ignore | field will be ignored |
std (*) | cms.Default | reserved |
must | cms.Must | reserved |
cleareq | cms.ClearIfEqual | set zero if target equal to source |
keepneq | cms.KeepIfNotEq | don't copy source if target not equal to source |
clearinvalid | cms.ClearIfInvalid | if target field is invalid, set to zero value |
noomit (*) | cms.NoOmit | |
omitempty | cms.OmitIfEmpty | if source field is empty, keep destination value |
omitnil | cms.OmitIfNil | |
omitzero | cms.OmitIfZero | |
noomittarget (*) | cms.NoOmitTarget | |
omitemptytarget | cms.OmitIfTargetEmpty | if target field is empty, don't copy from source |
omitniltarget | cms.OmitIfTargetNil | |
omitzerotarget | cms.OmitIfTargetZero | |
slicecopy | cms.SliceCopy | copy elem by subscription |
slicecopyappend | cms.SliceCopyAppend | and append more |
slicemerge | cms.SliceMerge | merge with order-insensitive |
mapcopy | cms.MapCopy | copy elem by key |
mapmerge | cms.MapMerge | merge map deeply |
| ... |
*: the flag is on by default.
Notes About DeepCopy()
Many settings are accumulated in multiple calling on DeepCopy(), such as converters, ignoreNames, and so on. The
underlying object is DefaultCopyController.
To get a fresh clean copier, New() or NewFlatDeepCopier() are the choices. BTW,
sometimes evendeep.ResetDefaultCopyController() might be helpful.
The only exception is copy-n-merge strategies. There flags are saved and restored on each calling on DeepCopy().
Notes About Global Settings
Some settings are global and available to both of DeepCopy() and New().CopyTo(), such as:
WithStringMarshallerorRegisterDefaultStringMarshaller()RegisterDefaultConvertersRegisterDefaultCopiers
And so on.
How is this guide?
Last updated on