feat: Add FromAnySlice (#133)

* feat: adding FromAnySlice helper
This commit is contained in:
Samuel Berthe
2022-05-10 15:43:34 +02:00
committed by GitHub
parent c03bb1dcf3
commit e0853ca970
8 changed files with 133 additions and 68 deletions

View File

@@ -2,6 +2,13 @@
@samber: I sometimes forget to update this file. Ping me on [Twitter](https://twitter.com/samuelberthe) or open an issue in case of error. We need to keep a clear changelog for easier lib upgrade.
## 1.21.0 (2022-05-10)
Adding:
- lo.ToAnySlice
- lo.FromAnySlice
## 1.20.0 (2022-05-02)
Adding:

View File

@@ -77,7 +77,6 @@ Supported helpers for slices:
- Reject
- Count
- CountBy
- ToInterfaceSlice
Supported helpers for maps:
@@ -144,13 +143,18 @@ Supported search helpers:
- Sample
- Samples
Other functional programming helpers:
Conditional helpers:
- Ternary (1 line if/else statement)
- If / ElseIf / Else
- Switch / Case / Default
Type manipulation helpers:
- ToPtr
- ToSlicePtr
- ToAnySlice
- FromAnySlice
- Empty
- Coalesce
@@ -636,14 +640,6 @@ slice := lo.ReplaceAll(in, -1, 42)
// []int{0, 1, 0, 1, 2, 3, 0}
```
### ToAnySlice
Returns a slice with all elements mapped to any type
```go
elements := lo.ToAnySlice[int]([]int{1, 5, 1})
// []any{1, 5, 1}
```
### Keys
Creates an array of the map keys.
@@ -1336,6 +1332,27 @@ ptr := lo.ToSlicePtr[string]([]string{"hello", "world"})
// []*string{"hello", "world"}
```
### ToAnySlice
Returns a slice with all elements mapped to `any` type.
```go
elements := lo.ToAnySlice[int]([]int{1, 5, 1})
// []any{1, 5, 1}
```
### FromAnySlice
Returns an `any` slice with all elements mapped to a type. Returns false in case of type conversion failure.
```go
elements, ok := lo.FromAnySlice[string]([]any{"foobar", 42})
// []string{}, false
elements, ok := lo.FromAnySlice[string]([]any{"foobar", "42"})
// []string{"foobar", "42"}, true
```
### Empty
Returns an empty value.

View File

@@ -216,11 +216,7 @@ func Sample[T any](collection []T) T {
func Samples[T any](collection []T, count int) []T {
size := len(collection)
// put values into a map, for faster deletion
cOpy := make([]T, 0, size)
for _, v := range collection {
cOpy = append(cOpy, v)
}
cOpy := append([]T{}, collection...)
results := []T{}

View File

@@ -1,32 +0,0 @@
package lo
// ToPtr returns a pointer copy of value.
func ToPtr[T any](x T) *T {
return &x
}
// ToSlicePtr returns a slice of pointer copy of value.
func ToSlicePtr[T any](collection []T) []*T {
return Map(collection, func(x T, _ int) *T {
return &x
})
}
// Empty returns an empty value.
func Empty[T any]() T {
var t T
return t
}
// Coalesce returns the first non-empty arguments. Arguments must be comparable.
func Coalesce[T comparable](v ...T) (result T, ok bool) {
for _, e := range v {
if e != result {
result = e
ok = true
return
}
}
return
}

View File

@@ -406,12 +406,3 @@ func Replace[T comparable](collection []T, old T, new T, n int) []T {
func ReplaceAll[T comparable](collection []T, old T, new T) []T {
return Replace[T](collection, old, new, -1)
}
// ToAnySlice returns a slice with all elements mapped to any type
func ToAnySlice[T any](collection []T) []any {
result := make([]any, len(collection))
for i, item := range collection {
result[i] = item
}
return result
}

View File

@@ -455,15 +455,3 @@ func TestReplaceAll(t *testing.T) {
is.Equal([]int{42, 1, 42, 1, 2, 3, 42}, out1)
is.Equal([]int{0, 1, 0, 1, 2, 3, 0}, out2)
}
func TestToAnySlice(t *testing.T) {
is := assert.New(t)
in1 := []int{0, 1, 2, 3}
in2 := []int{}
out1 := ToAnySlice(in1)
out2 := ToAnySlice(in2)
is.Equal([]any{0, 1, 2, 3}, out1)
is.Equal([]any{}, out2)
}

58
type_manipulation.go Normal file
View File

@@ -0,0 +1,58 @@
package lo
// ToPtr returns a pointer copy of value.
func ToPtr[T any](x T) *T {
return &x
}
// ToSlicePtr returns a slice of pointer copy of value.
func ToSlicePtr[T any](collection []T) []*T {
return Map(collection, func(x T, _ int) *T {
return &x
})
}
// ToAnySlice returns a slice with all elements mapped to `any` type
func ToAnySlice[T any](collection []T) []any {
result := make([]any, len(collection))
for i, item := range collection {
result[i] = item
}
return result
}
// FromAnySlice returns an `any` slice with all elements mapped to a type.
// Returns false in case of type conversion failure.
func FromAnySlice[T any](in []any) (out []T, ok bool) {
defer func() {
if r := recover(); r != nil {
out = []T{}
ok = false
}
}()
result := make([]T, len(in))
for i, item := range in {
result[i] = item.(T)
}
return result, true
}
// Empty returns an empty value.
func Empty[T any]() T {
var t T
return t
}
// Coalesce returns the first non-empty arguments. Arguments must be comparable.
func Coalesce[T comparable](v ...T) (result T, ok bool) {
for _, e := range v {
if e != result {
result = e
ok = true
return
}
}
return
}

View File

@@ -24,6 +24,46 @@ func TestToSlicePtr(t *testing.T) {
is.Equal(result1, []*string{&str1, &str2})
}
func TestToAnySlice(t *testing.T) {
is := assert.New(t)
in1 := []int{0, 1, 2, 3}
in2 := []int{}
out1 := ToAnySlice(in1)
out2 := ToAnySlice(in2)
is.Equal([]any{0, 1, 2, 3}, out1)
is.Equal([]any{}, out2)
}
func TestFromAnySlice(t *testing.T) {
is := assert.New(t)
is.NotPanics(func() {
out1, ok1 := FromAnySlice[string]([]any{"foobar", 42})
out2, ok2 := FromAnySlice[string]([]any{"foobar", "42"})
is.Equal([]string{}, out1)
is.False(ok1)
is.Equal([]string{"foobar", "42"}, out2)
is.True(ok2)
})
}
func TestEmpty(t *testing.T) {
is := assert.New(t)
//nolint:unused
type test struct {
foobar string
}
is.Empty(Empty[string]())
is.Empty(Empty[int64]())
is.Empty(Empty[test]())
is.Empty(Empty[chan string]())
}
func TestCoalesce(t *testing.T) {
is := assert.New(t)