Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: slices: add a CloneFunc function #58881

Closed
shoenig opened this issue Mar 5, 2023 · 2 comments
Closed

proposal: slices: add a CloneFunc function #58881

shoenig opened this issue Mar 5, 2023 · 2 comments

Comments

@shoenig
Copy link
Contributor

shoenig commented Mar 5, 2023

Related PR: #58865

This proposal is about adding a CloneFunc function to the slices package.
The signature of the function would be, func CloneFunc[S any, R any](s []S, f func(S) R) []R.

There are two motivations for such a function.

  1. Creating a deep copy of a slice

Many structs have something like .Copy or .Clone or .DeepCopy to implement a deep copy mechanism. CloneFunc enables using the slices package to make a copy of slices of such structs by leaving the copy implementation up to the caller.

  1. Creating a conversion of a slice

Often we'll have a struct of one type and wish to create a slice of another type based on the first one. For example, creating a []string of just the .Name field from a []Person. CloneFunc enables the caller to provide a conversion method when creating the new slice.

I've worked with re-implementations of this function a few places, e.g.
https://github.com/hashicorp/nomad/blob/main/helper/funcs.go#L401-L410
https://github.com/shoenig/test/blob/main/internal/util/slices.go#L3-L10

The function is really about streamlining the monotonous implied for-loop. For example say we wish to deep copy,

type F struct {
  M map[string]string
  N []string
  O []*Object
}

The existing slices and maps package enable us to write something like

func (f *F) Copy() *F {
   o := make([]*Object, len(f.O))
   for i:=0; i<len(f.O); i++ {
      o[i] = f.O[i].Copy()
   }
   return &F{
    M: maps.Clone(M),
    N: slices.Clone(N),
    O: o,
  }
}

With the addition of the proposed CloneFunc, this boils down to

func (f *F) Copy() *F {
   return &F{
    M: maps.Clone(M),
    N: slices.Clone(N),
    O: slices.CloneFunc(O, func(o *O) *F { o.Copy() }),
  }
}

And for an example of using CloneFunc to convert a slice, say we have a slice of

type Token struct {
  ID string
  Age time.Duration
  Description string

and we want a slice of just the IDs from the original slice

var result []string
for i:=0; i<len(tokens); i++ {
  result[i] = tokens[i].ID
}

With CloneFunc this becomes

result := slices.CloneFunc(tokens, func(t *Token) string { return t.ID })
@gopherbot gopherbot added this to the Proposal milestone Mar 5, 2023
@wdvxdr1123
Copy link
Contributor

Perhaps slices.Map is a better name.

@seankhliao
Copy link
Member

This was Map in #45955 , declined in #47203 (comment)

@seankhliao seankhliao closed this as not planned Won't fix, can't repro, duplicate, stale Mar 6, 2023
@golang golang locked and limited conversation to collaborators Mar 5, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants