I am a bit concerned about style (functions, variable names, spacings, etc.). I am also not sure about whether I should return error or panic. What do you think?
//SortStructs sorts user-made structs, given that "a" is a pointer to slice of structs
//and key's type (which is name of a field by which struct would be sorted) is one of the basic GO types
//which will be sorted in ascending order when asc is true and the other way around, fields must be exported
func SortStructs(a interface{}, key string, asc bool) error {
var (
fName string
fPos int
valSlice []reflect.Value
)
if a == nil {
return errors.New("mysort: given interface is empty")
}
structSlicePointer := reflect.ValueOf(a)
if structSlicePointer.Kind() != reflect.Ptr {
return errors.New("mysort: given interface is not pointer")
} else if structSlicePointer.Elem().Kind() != reflect.Slice {
return errors.New("mysort: given interface is not pointer to slice")
}
//append single structs here
for i := 0; i < structSlicePointer.Elem().Len(); i++ {
valSlice = append(valSlice, structSlicePointer.Elem().Index(i))
}
if valSlice[0].Kind() != reflect.Struct {
return errors.New("mysort: interface is not a struct")
}
//search for key here
sl := valSlice[0]
for ; fPos < sl.NumField(); fPos++ { //range over fields and search for match with key
fName = sl.Type().Field(fPos).Name
if fName == key {
break
}
}
if fPos == sl.NumField() && fName != key {
return errors.New("mysort: key not found")
} else if !basicGoType(sl.FieldByName(key)) {
return errors.New("mysort: key is not a basic go type")
}
sortReflect(valSlice, 0, len(valSlice)-1, key, asc)
return nil
}
func basicGoType(a reflect.Value) bool {
return a.Kind() == reflect.Bool ||
a.Kind() == reflect.Int || a.Kind() == reflect.Int8 || a.Kind() == reflect.Int16 || a.Kind() == reflect.Int32 || a.Kind() == reflect.Int64 ||
a.Kind() == reflect.Uint || a.Kind() == reflect.Uint8 || a.Kind() == reflect.Uint16 || a.Kind() == reflect.Uint32 || a.Kind() == reflect.Uint64 ||
a.Kind() == reflect.Complex64 || a.Kind() == reflect.Complex128 || a.Kind() == reflect.Float32 || a.Kind() == reflect.Float64 || a.Kind() == reflect.String
}
func aLessThanBReflect(a reflect.Value, b reflect.Value) bool {
switch a.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
int1 := a.Int()
int2 := b.Int()
return int1 < int2
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
uint1 := a.Uint()
uint2 := b.Uint()
return uint1 < uint2
case reflect.Bool:
bool1 := a.Bool()
bool2 := b.Bool()
return !bool1 && bool2
case reflect.Float32, reflect.Float64:
float1 := a.Float()
float2 := b.Float()
return float1 < float2
case reflect.Complex64, reflect.Complex128:
complex1 := a.Complex()
complex2 := b.Complex()
if real(complex1) == real(complex2) {
return imag(complex1) < imag(complex2)
}
return real(complex1) < real(complex2)
case reflect.String:
str1 := a.String()
str2 := b.String()
return str1 < str2
}
return false
}
//This is Hoare partition scheme adapted for this code
func partitionReflect(a []reflect.Value, low, high int, key string, asc bool) int {
pivot := a[int((high+low)/2)]
low -= 1
high += 1
for {
if asc {
low += 1
for a[low].FieldByName(key) != pivot.FieldByName(key) && aLessThanBReflect(a[low].FieldByName(key), pivot.FieldByName(key)) {
low += 1
}
high -= 1
for a[high].FieldByName(key) != pivot.FieldByName(key) && !aLessThanBReflect(a[high].FieldByName(key), pivot.FieldByName(key)) {
high -= 1
}
} else {
low += 1
for a[low].FieldByName(key) != pivot.FieldByName(key) && !aLessThanBReflect(a[low].FieldByName(key), pivot.FieldByName(key)) {
low += 1
}
high -= 1
for a[high].FieldByName(key) != pivot.FieldByName(key) && aLessThanBReflect(a[high].FieldByName(key), pivot.FieldByName(key)) {
high -= 1
}
}
if low >= high {
return high
}
//allocate memory for struct and copy a[low]'s value here
//couldn't do temp := a[low].Interface() because it shared 1 memory adress
temp := reflect.New(a[low].Type()).Interface()
temp = a[low].Interface()
a[low].Set(a[high])
a[high].Set(reflect.ValueOf(temp))
}
}
func sortReflect(a []reflect.Value, low, high int, key string, asc bool) {
if low < high {
p := partitionReflect(a, low, high, key, asc)
sortReflect(a, low, p, key, asc)
sortReflect(a, p+1, high, key, asc)
}
}
```
sort.Slice, like this. \$\endgroup\$