This is a creation in Article, where the information may have evolved or changed.
Preliminary idea, I would like to have a general design, what LINQ is, this part first is not elegant.
type User struct{ Id int Name string Birthday time.Time} From(userArr).Where(func(c interface{}) bool{ return c.Birthday > FormatBirthday("1989-01-17") }).Select(func(c interface{}) interface{} { return c.Name })
Assuming that From,where,select returns are queryable a struct, the value inside the queryable is interface{} in order to achieve a similar generic effect;
type Queryable struct { values []interface{}}
The From method constructs this queryable
func From(input []interface{}) Queryable{ return Queryable{ values: input, }}
The Where method, passing a method for comparison, and Golang without lambda (for example, X=>x.a > 100), is replaced with an anonymous function, which causes the Where method to be independent of the specific type, and this anonymous method returns bool A method chain is formed with the queryable returned from.
func (in Queryable) Where(condition func(interface{})(bool)) (r Queryable){ for _,i := range in.values{ ok := condition(i) if ok { r.values = append(r.values,i) } } return r}
The Select method, similar to where, but the return value is not bool, but queryable.
func (in Queryable) Select(sel func(interface{}) interface{}) (r Queryable){ for _,i := range in.values{ r.values = append(r.values,sel(i)) } return r}
If you need to combine a new combination of data, you need an anonymous type.
.Select(func(s interface{}) interface{} { return struct{ Id int Name string}{s.(User).Id, s.(User).Name} })
This basically realizes the mode of the from P in list where P.a > P.id Select, and one less.
Aside from LINQ, Golang the sort of a (temporarily only 1 field) field of an array of specific user types, which is required to implement the Len,less,swap method for this user type, combined with interface{}, it is easy to think of the following structure
type SortableQuery struct{ values []interface{}}func (list SortableQuery) Len() int{ return len(list.values)}func (list SortableQuery) Swap(i,j int){ list.values[i], list.values[j] = list.values[j], list.values[i]}//当写到Less方法的时候要考虑OrderBy方法的设计func (list SortableQuery) Less(i,j int) bool
Think about what we're going to do. The method is to sort the array by a field of the intrinsic element, which is probably
OrderBy(func(o interface) SortableQuery) SortableQuery{ return o.(User).Id}
This means that the method to be passed in is a method: F.
F (Values[i]) obtains the above code O. (User). Id, but this return value is indeterminate, possibly a string, and temporarily implementing the two case of int and string
func (in Queryable) OrderByDesc2(f func(interface{}) interface{}) (r SortableQuery) { less := func(i,j int) bool{ switch reflect.ValueOf(f(in.values[i])).Kind(){ case reflect.Int: o1 := f(in.values[i]).(int) o2 := f(in.values[j]).(int) return o1 > o2 case reflect.String: o1 := f(in.values[i]).(string) o2 := f(in.values[j]).(string) return strings.Compare(o1,o2) == 1 default: return false } return false; } r.less = less r.values = in.values sort.Sort(r) return r}
In addition, if you do not want to wrap the type of changes into the ORDERBYDESC function, you can sort.less the method as user input, in the method of the order of the implementation; For the time being, this flexibility is a bit higher.
Now leave some questions, such as delay calculation, to be continued ...
Finally, consider the implementation of open source
Github-ahmetalpbalkan/go-linq:. NET linq-like query methods for Go