v1.16.12
Added: * slicesx: ** Last ** LastIndex
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
/*
|
||||||
|
Package slicesx aims to extend functionality of the stdlib [slices] module.
|
||||||
|
*/
|
||||||
|
package slicesx
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package slicesx
|
||||||
|
|
||||||
|
/*
|
||||||
|
Last returns the last item/element in slice s.
|
||||||
|
|
||||||
|
e will be the nil/zero value of the slice element type
|
||||||
|
if the slice length is 0.
|
||||||
|
*/
|
||||||
|
func Last[S ~[]E, E any](s S) (e E) {
|
||||||
|
|
||||||
|
var idx int = LastIndex(s)
|
||||||
|
|
||||||
|
if idx < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e = s[idx]
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
LastIndex returns the index of the last element in slice s.
|
||||||
|
|
||||||
|
If s is empty, idx will be -1.
|
||||||
|
If s is nil, idx will be -2.
|
||||||
|
*/
|
||||||
|
func LastIndex[S ~[]E, E any](s S) (idx int) {
|
||||||
|
|
||||||
|
var l int = len(s)
|
||||||
|
|
||||||
|
idx = -2
|
||||||
|
if s != nil {
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
if l == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = l - 1
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
package slicesx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLast(t *testing.T) {
|
||||||
|
|
||||||
|
var v any
|
||||||
|
var e any
|
||||||
|
var intSl []int
|
||||||
|
var strSl []string
|
||||||
|
var boolSl []bool
|
||||||
|
var anySl []any
|
||||||
|
|
||||||
|
/*
|
||||||
|
int
|
||||||
|
*/
|
||||||
|
// nil
|
||||||
|
v = Last(intSl)
|
||||||
|
e = 0
|
||||||
|
if v != e {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
|
||||||
|
}
|
||||||
|
// empty
|
||||||
|
intSl = make([]int, 0)
|
||||||
|
v = Last(intSl)
|
||||||
|
if v != e { // still expect 0
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
|
||||||
|
}
|
||||||
|
// populated
|
||||||
|
intSl = []int{0, 1, 2, 3}
|
||||||
|
v = Last(intSl)
|
||||||
|
e = 3
|
||||||
|
if v != e {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
string
|
||||||
|
*/
|
||||||
|
// nil
|
||||||
|
v = Last(strSl)
|
||||||
|
e = ""
|
||||||
|
if v != e {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
|
||||||
|
}
|
||||||
|
// empty
|
||||||
|
strSl = make([]string, 0)
|
||||||
|
v = Last(strSl)
|
||||||
|
if v != e { // still expect ""
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
|
||||||
|
}
|
||||||
|
// populated
|
||||||
|
strSl = []string{"a", "b", "c"}
|
||||||
|
v = Last(strSl)
|
||||||
|
e = "c"
|
||||||
|
if v != e {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
bool
|
||||||
|
*/
|
||||||
|
// nil
|
||||||
|
v = Last(boolSl)
|
||||||
|
e = false
|
||||||
|
if v != e {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
|
||||||
|
}
|
||||||
|
// empty
|
||||||
|
boolSl = make([]bool, 0)
|
||||||
|
v = Last(boolSl)
|
||||||
|
if v != e { // still expect false
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
|
||||||
|
}
|
||||||
|
// populated
|
||||||
|
boolSl = []bool{true, false, true, false, true}
|
||||||
|
v = Last(boolSl)
|
||||||
|
e = true
|
||||||
|
if v != e {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
any/interface{}
|
||||||
|
*/
|
||||||
|
// nil
|
||||||
|
v = Last(anySl)
|
||||||
|
e = nil
|
||||||
|
if v != e {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
|
||||||
|
}
|
||||||
|
// empty
|
||||||
|
anySl = make([]any, 0)
|
||||||
|
v = Last(anySl)
|
||||||
|
if v != e { // still expect nil
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
|
||||||
|
}
|
||||||
|
// populated
|
||||||
|
anySl = []any{3, true, "foo", "bar"}
|
||||||
|
v = Last(anySl)
|
||||||
|
e = "bar"
|
||||||
|
if v != e {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
this test only runs in Go 1.26+;
|
||||||
|
which lets you new() on values instead of just types.
|
||||||
|
|
||||||
|
commented out until req bumps to 1.26+ in go.mod.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
func TestLastPtr(t *testing.T) {
|
||||||
|
|
||||||
|
var v any
|
||||||
|
var i *int
|
||||||
|
var s *string
|
||||||
|
var b *bool
|
||||||
|
var ptrIntSl []*int
|
||||||
|
var ptrStrSl []*string
|
||||||
|
var ptrBoolSl []*bool
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// int
|
||||||
|
//
|
||||||
|
// nil
|
||||||
|
v = Last(ptrIntSl)
|
||||||
|
i = nil
|
||||||
|
if v != i {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, i, i)
|
||||||
|
}
|
||||||
|
// empty
|
||||||
|
ptrIntSl = make([]*int, 0)
|
||||||
|
v = Last(ptrIntSl)
|
||||||
|
if v != i { // still expect nil
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, i, i)
|
||||||
|
}
|
||||||
|
// populated
|
||||||
|
ptrIntSl = []*int{new(0), new(1), new(2), new(3)}
|
||||||
|
v = Last(ptrIntSl)
|
||||||
|
i = ptrIntSl[len(ptrIntSl)-1]
|
||||||
|
if v != i {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, i, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// string
|
||||||
|
//
|
||||||
|
// nil
|
||||||
|
v = Last(ptrStrSl)
|
||||||
|
if v != s {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, s, s)
|
||||||
|
}
|
||||||
|
// empty
|
||||||
|
ptrStrSl = make([]*string, 0)
|
||||||
|
v = Last(ptrStrSl)
|
||||||
|
if v != s { // still expect nil
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, s, s)
|
||||||
|
}
|
||||||
|
// populated
|
||||||
|
ptrStrSl = []*string{new("a"), new("b"), new("c")}
|
||||||
|
v = Last(ptrStrSl)
|
||||||
|
s = ptrStrSl[len(ptrStrSl)-1]
|
||||||
|
if v != s {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, s, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// bool
|
||||||
|
//
|
||||||
|
// nil
|
||||||
|
v = Last(ptrBoolSl)
|
||||||
|
if v != b {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, b, b)
|
||||||
|
}
|
||||||
|
// empty
|
||||||
|
ptrBoolSl = make([]*bool, 0)
|
||||||
|
v = Last(ptrBoolSl)
|
||||||
|
if v != b { // still expect nil
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, b, b)
|
||||||
|
}
|
||||||
|
// populated
|
||||||
|
ptrBoolSl = []*bool{new(true), new(false), new(true), new(false), new(true)}
|
||||||
|
v = Last(ptrBoolSl)
|
||||||
|
b = ptrBoolSl[len(ptrBoolSl)-1]
|
||||||
|
if v != b {
|
||||||
|
t.Errorf("%T %#v, expected %T %#v", v, v, b, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func TestLastIndex(t *testing.T) {
|
||||||
|
|
||||||
|
var e int
|
||||||
|
var v int
|
||||||
|
var s []string
|
||||||
|
|
||||||
|
e = -2
|
||||||
|
v = LastIndex(s)
|
||||||
|
if e != v {
|
||||||
|
t.Errorf("Got %d, expected %d", v, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
e = -1
|
||||||
|
s = make([]string, 0)
|
||||||
|
v = LastIndex(s)
|
||||||
|
if e != v {
|
||||||
|
t.Errorf("Got %d, expected %d", v, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
e = 0
|
||||||
|
s = []string{"a"}
|
||||||
|
v = LastIndex(s)
|
||||||
|
if e != v {
|
||||||
|
t.Errorf("Got %d, expected %d", v, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
e = 1
|
||||||
|
s = []string{"a", "b"}
|
||||||
|
v = LastIndex(s)
|
||||||
|
if e != v {
|
||||||
|
t.Errorf("Got %d, expected %d", v, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
e = 2
|
||||||
|
s = []string{"a", "b", "c"}
|
||||||
|
v = LastIndex(s)
|
||||||
|
if e != v {
|
||||||
|
t.Errorf("Got %d, expected %d", v, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -636,7 +636,7 @@ pre.rouge .gs {
|
|||||||
<div class="details">
|
<div class="details">
|
||||||
<span id="author" class="author">Brent Saner</span><br>
|
<span id="author" class="author">Brent Saner</span><br>
|
||||||
<span id="email" class="email"><a href="mailto:bts@square-r00t.net">bts@square-r00t.net</a></span><br>
|
<span id="email" class="email"><a href="mailto:bts@square-r00t.net">bts@square-r00t.net</a></span><br>
|
||||||
<span id="revdate">Last rendered 2026-07-13 19:17:39 -0400</span>
|
<span id="revdate">Last rendered 2026-07-14 03:02:23 -0400</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="toc" class="toc2">
|
<div id="toc" class="toc2">
|
||||||
<div id="toctitle">Table of Contents</div>
|
<div id="toctitle">Table of Contents</div>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<span id="author" class="author">Brent Saner</span>
|
<span id="author" class="author">Brent Saner</span>
|
||||||
<span id="email" class="email"><bts@square-r00t.net></span>
|
<span id="email" class="email"><bts@square-r00t.net></span>
|
||||||
<span id="revdate">Last rendered 2026-07-13 19:17:43 -0400</span>
|
<span id="revdate">Last rendered 2026-07-14 03:02:27 -0400</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user