Skip to content

Instantly share code, notes, and snippets.

@chiro-hiro
Last active June 18, 2023 05:18
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chiro-hiro/66e028ad4879d104f29a464c7f16157e to your computer and use it in GitHub Desktop.
Save chiro-hiro/66e028ad4879d104f29a464c7f16157e to your computer and use it in GitHub Desktop.
first() and last() safe access in Golang

I'm pretty sure, Golang is a good language to learn and do development. I find out Golang doesn't support some popular safe slice access.

package main

import (
	"fmt"
	"reflect"
)

func main() {
	data := make([]string, 3)
	data[0] = "1"
	data[1] = "2"
	data[2] = "3"
	fmt.Println(data[0])
}

It wouldn't a good idea to access empty slice or nil value, you might be messed with some complicated code like this:

	if data != nil && reflect.TypeOf(data).Kind() == reflect.Slice && len(data) > 0 {
		fmt.Println(data[0])
	} else {
		fmt.Println("Oops! this isn't good.")
	}

It's munch easier to write safe code:

package main

import (
	"fmt"
	"reflect"
)

func safeAccess(data interface{}, index int) (val reflect.Value) {
	if data == nil || reflect.TypeOf(data).Kind() != reflect.Slice {
		return
	}
	tmp := reflect.ValueOf(data)
	tmpLen := tmp.Len()
	if tmpLen > 0 && index < 0 {
		val = tmp.Index(tmpLen - 1)
	} else if tmpLen > 0 && index < tmpLen {
		val = tmp.Index(index)
	}
	return
}

func first(data interface{}) (val reflect.Value) {
	return safeAccess(data, 0)
}

func last(data interface{}) (val reflect.Value) {
	return safeAccess(data, -1)
}

func main() {
	data := make([]string, 3)
	data[0] = "value 0"
	data[1] = "value 1"
	data[2] = "value 2"
	var ei interface{}
	f := first(data)
	l := last(data)
	s := safeAccess(data, 99)
	n := first(nil)
	i := first(ei)
	if f.IsValid() {
		fmt.Printf("f is equal to \"%s\", type is <%T>\n", f.String(), f.String())
	}
	if l.IsValid() {
		fmt.Printf("l is equal to \"%s\", type is <%T>\n", l.String(), l.String())
	}
	if !s.IsValid() {
		fmt.Println("s should be invalid!")
	}
	if !n.IsValid() {
		fmt.Println("n should be invalid!")
	}
	if !i.IsValid() {
		fmt.Println("i should be invalid!")
	}
}

Try it and enjoy ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment