1、简介
ReactiveX是Reactive Extensions的缩写,一般简写为Rx,最初是LINQ的一个扩展,由微软的架构师Erik Meijer领导的团队开发,在2012年11月开源,Rx是一个编程模型,目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流,Rx库支持.NET、JavaScript和C++,Rx近几年越来越流行了,现在已经支持几乎全部的流行编程语言了,Rx的大部分语言库由ReactiveX这个组织负责维护,比较流行的有RxJava/RxJS/Rx.NET,社区网站是 reactivex.io。中文文档
2、课程任务
阅读 ReactiveX 文档。请在 pmlpml/RxGo 基础上,
- 修改、改进它的实现
- 或添加一组新的操作,如 filtering
该库的基本组成:
rxgo.go
给出了基础类型、抽象定义、框架实现、Debug工具等
generators.go
给出了 sourceOperater 的通用实现和具体函数实现
transforms.go
给出了 transOperater 的通用实现和具体函数实现
filtering操作的实现
首先,filtering 有如下功能:
- Debounce — only emit an item from an Observable if a particular timespan has passed without it emitting another item
- Distinct — suppress duplicate items emitted by an Observable
- ElementAt — emit only item n emitted by an Observable
- Filter — emit only those items from an Observable that pass a predicate test
- First — emit only the first item, or the first item that meets a condition, from an Observable
- IgnoreElements — do not emit any items from an Observable but mirror its termination notification
- Last — emit only the last item emitted by an Observable
- Sample — emit the most recent item emitted by an Observable within periodic time intervals
- Skip — suppress the first n items emitted by an Observable
- SkipLast — suppress the last n items emitted by an Observable
- Take — emit only the first n items emitted by an Observable
- TakeLast — emit only the last n items emitted by an Observable
其中Filter这一功能老师在transforms.go
里面已经实现了,因此在这里我们也不需要再去实现。
首先,结构体filteringOperator可以直接从transforms.go
里照搬过去,改改名字。
type filteringOperator struct {
opFunc func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{
}) (end bool)
}
op大抵也是照搬过去的,只是有些许改变:
func (ftop filteringOperator) op(ctx context.Context, o *Observable) {
in := o.pred.outflow
out := o.outflow
//fmt.Println(o.name, "operator in/out chan ", in, out)
var wg sync.WaitGroup
go func() {
end := false
for x := range in {
if end {
break
}
// can not pass a interface as parameter (pointer) to gorountion for it may change its value outside!
xv := reflect.ValueOf(x)
// send an error to stream if the flip not accept error
if e, ok := x.(error); ok && !o.flip_accept_error {
o.sendToFlow(ctx, e, out)
continue
}
// scheduler
switch threading := o.threading; threading {
case ThreadingDefault:
if ftop.opFunc(ctx, o, xv, out) {
end = true
}
case ThreadingIO:
fallthrough
case ThreadingComputing:
wg.Add(1)
go func() {
defer wg.Done()
if ftop.opFunc(ctx, o, xv, out) {
end = true
}
}()
default:
}
}
if o.flip != nil {
buffer := (reflect.ValueOf(o.flip))
if buffer.Kind() != reflect.Slice {
panic("flip is not buffer")
}
for i := 0; i < buffer.Len(); i++ {
o.sendToFlow(ctx, buffer.Index(i).Interface(), out)
}
}
wg.Wait() //waiting all go-routines completed
o.closeFlow(out)
}()
}
前面一部分都是相同的,只是改改变量名,值得注意的是,后续会有Last/TakeLast操作,需要一个缓存来实现,这里就直接通过Observable里面的flip来完成。
func (parent *Observable) Debounce(timespan time.Duration) (o *Observable) {
o = parent.newFilterObservable("debounce")
o.flip_accept_error = true
o.flip_sup_ctx = true
count := 0
o.operator = filteringOperator{
opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{
}) (end bool) {
count++
go func() {
tempCount := count
time.Sleep(timespan)
select {
case <-ctx.Done():
return
default:
if tempCount == count {
o.sendToFlow(ctx, item.Interface(), out)
}
}
}()
return false
},
}
return o
}
Debounce的功能就是消除抖动,在这里,我就简单地用一个go程+一个延时函数来实现,若是过了这一段时间还没有新的item到来(在这里表现为count并未改变),再把之前的那个item输出出去。
func (parent *Observable) Distinct() (o *Observable) {
o = parent.newFilterObservable("distinct")
o.flip_accept_error = true
o.flip_sup_ctx = true
m := map[string]bool{
}
o.operator = filteringOperator{
opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{
}) (end bool) {
itemStr := fmt.Sprintf("%v", item)
if _, ok := m[itemStr]; !ok {
m[itemStr] = true
o.sendToFlow(ctx, item.Interface(), out)
}
return false
},
}
return o
}
Distinct就是将重复的数据过滤掉,这里我用一个map来判断当前数据是否是之前就出现过了。通过fmt.Sprintf来将item转化为相应的String,或许也可以通过json
来完成,上一次作业实现的对象序列化也可以派上用场了。
func (parent *Observable) ElementAt(num int) (o *Observable) {
o = parent.newFilterObservable("elementAt.n")<