Skip to content

Commit

Permalink
Add slices.NonNil. (#14)
Browse files Browse the repository at this point in the history
bobg authored May 18, 2024
1 parent 9680c2c commit 83d5429
Showing 4 changed files with 57 additions and 3 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -3,8 +3,8 @@ module github.com/bobg/go-generics/v3
go 1.22

require (
github.com/mattn/go-sqlite3 v1.14.12
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
github.com/mattn/go-sqlite3 v1.14.22
golang.org/x/sync v0.7.0
)

require github.com/google/go-cmp v0.6.0 // indirect
require github.com/google/go-cmp v0.6.0
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -2,5 +2,9 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
32 changes: 32 additions & 0 deletions slices/nonnil_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package slices

import (
"fmt"
"reflect"
"testing"
)

func TestNonNil(t *testing.T) {
cases := []struct {
inp []int
want []int
}{{
inp: nil,
want: []int{},
}, {
inp: []int{},
want: []int{},
}, {
inp: []int{1, 2, 3},
want: []int{1, 2, 3},
}}

for i, c := range cases {
t.Run(fmt.Sprintf("case_%d", i+1), func(t *testing.T) {
got := NonNil(c.inp)
if !reflect.DeepEqual(got, c.want) {
t.Errorf("got %v, want %v", got, c.want)
}
})
}
}
18 changes: 18 additions & 0 deletions slices/slices.go
Original file line number Diff line number Diff line change
@@ -386,3 +386,21 @@ func (k keyedSorter[S, T]) Swap(i, j int) {
k.keys.Swap(i, j)
k.slice[i], k.slice[j] = k.slice[j], k.slice[i]
}

// NonNil converts a nil slice to a non-nil empty slice.
// It returns other slices unchanged.
//
// A nil slice is usually preferable,
// since it is equivalent to an empty slice in almost every way
// and does not have the overhead of an allocation.
// (See https://dave.cheney.net/2018/07/12/slices-from-the-ground-up.)
// However, there are some corner cases where the difference matters,
// notably when marshaling to JSON,
// where an empty slice marshals as the array []
// but a nil slice marshals as the non-array `null`.
func NonNil[S ~[]T, T any](s S) S {
if s == nil {
return S{}
}
return s
}

0 comments on commit 83d5429

Please sign in to comment.