Go 實現Linq的探索-1

初步想法,我希望有一個大概的設計,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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,759評論 18 399
  • 50個常用的sql語句Student(S#,Sname,Sage,Ssex) 學生表Course(C#,Cname...
    哈哈海閱讀 1,248評論 0 7
  • 應用程序還需要操作存儲在其他數據源(如SQL數據庫或XML文件)中的數據,甚至通過Web服務訪問它們。傳統上,查詢...
    CarlDonitz閱讀 606評論 0 0
  • 我去過的地方很少,并非沒有時間,而是我很宅。一個人,一部手機,一臺電腦就是我的全部。父母離異給了我很多說不出口的傷...
    小盧同志閱讀 317評論 1 3
  • 這個標題上我突出了“日本人”,并不是要帶有民族色彩來評價這本書。而是因為,日本人其實并不擅長談判。可能是因為日本人...
    天舒閱讀 578評論 0 2