初步想法,我希望有一個大概的設計,Linq是什么,這部分先不考究。
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
})
假設From,Where,Select返回都是Queryable 一個struct;為了實現類似泛型的效果,Queryable 里面的值是interface{};
type Queryable struct {
values []interface{}
}
From方法 構建這個Queryable
func From(input []interface{}) Queryable{
return Queryable{
values: input,
}
}
Where方法,傳遞一個用于比較的方法,而Golang沒有lambda(例如 x=>x.A > 100),就用匿名函數代替,使得Where方法跟具體類型無關,此匿名方法返回bool;跟From返回的Queryable組成一條方法鏈。
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
}
Select方法,跟Where類似,但返回值不是bool,而是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
}
如果需要組合一個新的數據組合,需要匿名類型。
.Select(func(s interface{}) interface{} {
return struct{
Id int
Name string}{s.(User).Id, s.(User).Name}
})
這樣就大致實現了 from p in list where p.A > 100 select p.Id的模式了,還少了一個orderby。
撇開Linq不談,Golang對由特定用戶類型組成的數組的某個(暫時僅僅1個字段)字段的排序,是需要為此用戶類型實現Len,Less,Swap方法的,結合interface{},就很容易想到以下結構
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
想想我們要實現OrderBy方法是讓數組按內在元素的某個字段排序,使用的時候大概是
OrderBy(func(o interface) SortableQuery) SortableQuery{
return o.(User).Id
}
也就是說OrderBy的方法要傳入一個方法:f。
f(values[i]) 獲得上面代碼的o.(User).Id,但這個返回值是不確定的,可能是string,暫時先實現int和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
}
另外,如果不想把類型的變化封裝到OrderByDesc函數,可以sort.less方法作為用戶輸入,在orderby方法里面實現;暫時認為這樣靈活度是更高一點。
現在留下一些問題,例如延遲計算,待續。。。
最后,參考一下開源的實現
GitHub - ahmetalpbalkan/go-linq: .NET LINQ-like query methods for Go