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
ByOrdinal
assumes the copier loops all source fields and copy them to the corresponding destination with the ordinal order. ByName
strategy 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
->targetName
sourceName->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:
WithStringMarshaller
orRegisterDefaultStringMarshaller()
RegisterDefaultConverters
RegisterDefaultCopiers
And so on.
How is this guide?
Last updated on