Skip to content

optimize copying slice when toValue and fromValue are different types#238

Open
tujun233 wants to merge 1 commit intojinzhu:masterfrom
tujun233:master
Open

optimize copying slice when toValue and fromValue are different types#238
tujun233 wants to merge 1 commit intojinzhu:masterfrom
tujun233:master

Conversation

@tujun233
Copy link
Copy Markdown

@tujun233 tujun233 commented Nov 4, 2025

Hi !

when using copier, I found a problem that when dst and src are different type slice, existing code will perform two deep-copy for one element in a slice (from -> dest and dest -> to).

image image

when I perform a deepcopy from []*model.XXX to []*business.XXX, the second picture shows that the fromValue of next stack becomes a business.XXX. It will affect the speed of copying. dest is already deepcopy of from, so I think directly using .set is ok.

@tujun233
Copy link
Copy Markdown
Author

tujun233 commented Nov 4, 2025

Status: Open.
#237
@jinzhu

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to speed up slice copying when source and destination slices have different element types by avoiding a redundant second deep-copy pass for each element.

Changes:

  • Simplifies slice element assignment in copier() by directly Set-ing the computed dest into to[i] when types are assignable.
  • Removes the set(...)/copier(...) fallback previously used when overwriting an existing slice element.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread copier.go
Comment on lines 433 to 439
if isSlice && to.Kind() == reflect.Slice {
if dest.Addr().Type().AssignableTo(to.Type().Elem()) {
if to.Len() < i+1 {
to.Set(reflect.Append(to, dest.Addr()))
} else {
isSet, err := set(to.Index(i), dest.Addr(), opt.DeepCopy, converters)
if err != nil {
return err
}
if !isSet {
// ignore error while copy slice element
err = copier(to.Index(i).Addr().Interface(), dest.Addr().Interface(), opt)
if err != nil {
continue
}
}
to.Index(i).Set(dest.Addr())
}
Comment thread copier.go
Comment on lines 433 to 445
if isSlice && to.Kind() == reflect.Slice {
if dest.Addr().Type().AssignableTo(to.Type().Elem()) {
if to.Len() < i+1 {
to.Set(reflect.Append(to, dest.Addr()))
} else {
isSet, err := set(to.Index(i), dest.Addr(), opt.DeepCopy, converters)
if err != nil {
return err
}
if !isSet {
// ignore error while copy slice element
err = copier(to.Index(i).Addr().Interface(), dest.Addr().Interface(), opt)
if err != nil {
continue
}
}
to.Index(i).Set(dest.Addr())
}
} else if dest.Type().AssignableTo(to.Type().Elem()) {
if to.Len() < i+1 {
to.Set(reflect.Append(to, dest))
} else {
isSet, err := set(to.Index(i), dest, opt.DeepCopy, converters)
if err != nil {
return err
}
if !isSet {
// ignore error while copy slice element
err = copier(to.Index(i).Addr().Interface(), dest.Interface(), opt)
if err != nil {
continue
}
}
to.Index(i).Set(dest)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants