這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
續上一篇的思路,解決延遲計算的問題。相關的keyword很容易想到yield。
在C#中的延遲計算介紹可以參考一些文章,例如 “不能不說的C#特性-迭代器(下) yield以及流的延遲計算”
http://www.cnblogs.com/yuyijq/archive/2008/07/19/1246609.html
文章中提到
一、每次只返回一個元素的方法(閱讀者請跳到下文的第二部分)
從一個比較形式化的角度想,需要一個函數,每次調用去除列表最前面的元素,如果列表為空白,返回false。
type iterator func()(bool,interface{})
然後在使用的時候,for迴圈每次都會判斷擷取的bool傳回值為true的話,輸出結果。
for ok, next := iter(); ok; ok, next = iter() { fmt.Println(next) }
定義一個包含上面提到的方法和列表的資料結構
type Query struct{ list []interface{}}
iter是iterator類型的,它的責任是每次只去除列表的頭一個元素,並對空列表的情況做判斷。
func (q *Query)GetIterator() iterator{ i:=0 return func() (bool,interface{}){ if i < len(q.list) { ret := q.list[i] i++ return true,ret } return false,nil }}
下面的方法用於添加資料
func (q *Query)generator(data interface{}){ q.list = append(q.list,data)}
第一次在Go上使用單例模式:once.Do
var m *Queryvar once sync.Oncefunc GeneratorInstance() *Query{ once.Do(func() { m = &Query {} }) return m}
下面開始檢查這種方法
func quips(name string) iterator{ GeneratorInstance().generator("Hi " + name + "!") GeneratorInstance().generator("Hi" + " good day , R u ok?") GeneratorInstance().generator("en.. ok,good day") return GeneratorInstance().GetIterator()}func main() { iter := quips("Yk kang") for ok, next := iter(); ok; ok, next = iter() { fmt.Println(next) }}
執行後會輸出:
Hi Yk kang2!
Hi good day , R u ok?
en.. ok,good day
二、與切片結合,讓筆記“探索一”裡面From().Select()支援延遲計算
其實質就是把From改造成像上文GetIterator的樣子;而Query不儲存list,list由From輸入,Query聲明了返回item的方法
type Iterator func()(item interface{},ok bool)type Query struct{ Iterate func() Iterator}func From(in interface{}) Query{ src := reflect.ValueOf(in) len := src.Len() return Query{ Iterate:func() Iterator{ i:=0 return func() (item interface{},ok bool){ ok = i < len if ok{ item = src.Index(i).Interface() i++ } return } }, }} next := From(userArr).Iterate() for item,ok := next(); ok; item,ok = next() { fmt.Println(item) }
這樣便會正常輸出
{1 A 12}
{2 B 7}
{3 C 15}
而Select方法傳入的參數是selector func (interface{}) interface{},在方法體裡面從From返回的Query的Iterate方法得到item,ok,傳進selector裡面,因此Select方法是Query的
func (q Query) Select(selector func(interface{}) interface{}) Query { return Query{ Iterate: func() Iterator { next := q.Iterate() return func() (item interface{}, ok bool) { var it interface{} it, ok = next() if ok { item = selector(it) } return } }, }}//使用 t := From(userArr).Select(func(c interface{}) interface{}{ return c.(User).Name }) next := t.Iterate() for item,ok := next(); ok; item,ok = next() { fmt.Println(item) }
按照這個函數鏈的邏輯,where方法也可以照搬Select了