Skip to content

Instantly share code, notes, and snippets.

@tmthrgd
Created December 8, 2016 10:39
Show Gist options
  • Save tmthrgd/119904fa57cf504f4ddd3f65eca55af8 to your computer and use it in GitHub Desktop.
Save tmthrgd/119904fa57cf504f4ddd3f65eca55af8 to your computer and use it in GitHub Desktop.
A slice function for Golang templates (text/template and html/template).
func slice(item interface{}, indices ...interface{}) (interface{}, error) {
v := reflect.ValueOf(item)
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.String:
case reflect.Invalid:
return nil, errors.New("index of untyped nil")
default:
return nil, fmt.Errorf("can't index item of type %s", v.Type())
}
if len(indices) == 0 {
return nil, fmt.Errorf("too few arguments, accepted 2..3 but got 1")
}
index := reflect.ValueOf(indices[0])
var i int64
switch index.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i = index.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
i = int64(index.Uint())
case reflect.Invalid:
return nil, fmt.Errorf("cannot index slice/array with nil")
default:
return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
}
if i < 0 || i >= int64(v.Len()) {
return nil, fmt.Errorf("index out of range: %d", i)
}
switch len(indices) {
case 1:
return v.Slice(int(i), v.Len()).Interface(), nil
case 2:
index1 := reflect.ValueOf(indices[1])
var j int64
switch index1.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
j = index1.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
j = int64(index1.Uint())
case reflect.Invalid:
return nil, fmt.Errorf("cannot index slice/array with nil")
default:
return nil, fmt.Errorf("cannot index slice/array with type %s", index1.Type())
}
if j < 0 || j >= int64(v.Len()) {
return nil, fmt.Errorf("index out of range: %d", j)
}
if i > j {
return nil, fmt.Errorf("invalid index %d:%d", i, j)
}
return v.Slice(int(i), int(j)).Interface(), nil
default:
return nil, fmt.Errorf("too many arguments, accepted 2..3 but got %d", 1+len(indices))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment