【ReactiveX】基于Golang pmlpml/RxGo程序包的二次开发
基于Golang pmlpml/RxGo程序包的二次开发【阅读时间:约20分钟】
- 一、ReactiveX & RxGo介绍
- 1.ReactiveX
- 2.RxGo
- 二、系统环境&项目介绍
- 1.系统环境
- 2.项目的任务要求
- 三、具体程序设计及Golang代码实现
- 1.程序设计
- 2.filteringOperator数据结构、op函数与newFilterObservable函数
- 3. Debounce函数
- 4. Distinct函数
- 5. ElementAt函数
- 6. Filter函数
- 7. First函数
- 8. IgnoreElements函数
- 9. Last函数
- 10. Sample函数
- 11. Skip函数
- 12. SkipLast函数
- 13. Take函数
- 14. TakeLast函数
- 四、程序测试
- 1.封装并使用程序包
- 2.功能测试
- 3.单元测试
- 五、中文 api 文档
- 六、完整代码
- 七、References
一、ReactiveX & RxGo介绍
1.ReactiveX
ReactiveX是Reactive Extensions的缩写,一般简写为Rx,最初是LINQ的一个扩展,由微软的架构师Erik Meijer领导的团队开发,在2012年11月开源,Rx是一个编程模型,目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流,Rx库支持.NET、JavaScript和C++,Rx近几年越来越流行了,现在已经支持几乎全部的流行编程语言了,Rx的大部分语言库由ReactiveX这个组织负责维护,比较流行的有RxJava/RxJS/Rx.NET,社区网站是 reactivex.io。中文文档
2.RxGo
Go 语言的 RxGo 看上去就像 go 入门不久的人写的,很怪异。 但 RxJava 库写的很好。
pmlpml/RxGo 模仿 Java 版写了 Go 版本新实现,已基本实现了 Creating Observables 和 Transforming Observables 两类算子。
二、系统环境&项目介绍
1.系统环境
操作系统:CentOS7
硬件信息:使用virtual box配置虚拟机(内存3G、磁盘30G)
编程语言:GO 1.15.2
2.项目的任务要求
阅读 ReactiveX 文档。请在 pmlpml/RxGo 基础上,
- 修改、改进它的实现
- 或添加一组新的操作,如 filtering
该库的基本组成:
rxgo.go 给出了基础类型、抽象定义、框架实现、Debug工具等
generators.go 给出了 sourceOperater 的通用实现和具体函数实现
transforms.go 给出了 transOperater 的通用实现和具体函数实现
三、具体程序设计及Golang代码实现
1.程序设计
在本次二次开发中,笔者选择的是第二种实现,即添加一组filtering操作。
在filtering中,我们可以看到该算子的定义及操作如下:
Filtering Observables: Operators that selectively emit items from a source Observable.
Debounce— only emit an item from an Observable if a particular timespan has passed without it emitting another itemDistinct— suppress duplicate items emitted by an ObservableElementAt— emit only item n emitted by an ObservableFilter— emit only those items from an Observable that pass a predicate testFirst— emit only the first item, or the first item that meets a condition, from an ObservableIgnoreElements— do not emit any items from an Observable but mirror its termination notificationLast— emit only the last item emitted by an ObservableSample— emit the most recent item emitted by an Observable within periodic time intervalsSkip— suppress the first n items emitted by an ObservableSkipLast— suppress the last n items emitted by an ObservableTake— emit only the first n items emitted by an ObservableTakeLast— emit only the last n items emitted by an Observable
2.filteringOperator数据结构、op函数与newFilterObservable函数
首先直接借鉴pmlpml/RxGo中的transforms.go文件,完善filteringOperator数据结构、op函数与newFilterObservable函数如下:
// filtering node implementation of streamOperator
type filteringOperator struct {opFunc func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool)
}//op op函数
func (sop filteringOperator) op(ctx context.Context, o *Observable) {// must hold defintion of flow resourcs here, such as chan etc., that is allocated when connected// this resurces may be changed when operation routine is running.in := o.pred.outflowout := o.outflow//fmt.Println(o.name, "operator in/out chan ", in, out)// Schedulergo func() {end := falsefor x := range in {if end {break}// can not pass a interface as parameter (pointer) to gorountion for it may change its value outside!temp := reflect.ValueOf(x)// send an error to stream if the flip not accept errorerr, ok := x.(error)if ok && !o.flip_accept_error {o.sendToFlow(ctx, err, out)continue}if sop.opFunc(ctx, o, temp, out) {end = true}}if o.flip != nil {buffer := (reflect.ValueOf(o.flip))for i := 0; i < buffer.Len(); i++ {o.sendToFlow(ctx, buffer.Index(i).Interface(), out)}}o.closeFlow(out)}()
}//newFilterObservable 新建一个Filter Observabl
func (parent *Observable) newFilterObservable(name string) (o *Observable) {//new Observableo = newObservable()o.Name = name//chain Observablesparent.next = oo.pred = parento.root = parent.root//set optionso.buf_len = BufferLenreturn o
}
3. Debounce函数
Debounce函数用于按时间防抖动,借鉴transforms.go文件的实现方式,Observable.operator等于具体的算子操作即可,其具体代码实现如下:
var count = 0
var tempTime time.Duration//Debounce 按时间防抖动
func (parent *Observable) Debounce(timespan time.Duration) (o *Observable) {tempTime = timespano = parent.newFilterObservable("debounce")o.flip_accept_error = trueo.flip_sup_ctx = truecount = 0o.operator = debounceOpreturn o
}var debounceOp = filteringOperator{opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {count++go func() {tempCount := counttime.Sleep(tempTime)select {case <-ctx.Done():returndefault:if tempCount == count {o.sendToFlow(ctx, item.Interface(), out)}}}()return false},
}
4. Distinct函数
Distinct函数用于过滤掉重复出现的元素,借鉴transforms.go文件的实现方式,Observable.operator等于具体的算子操作即可,其具体代码实现如下:
var tempMap map[string]bool//Distinct 过滤掉重复出现的元素
func (parent *Observable) Distinct() (o *Observable) {o = parent.newFilterObservable("distinct")o.flip_accept_error = trueo.flip_sup_ctx = truetempMap = map[string]bool{}o.operator = distinctOpreturn o
}var distinctOp = filteringOperator{opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {itemStr := fmt.Sprintf("%v", item)_, ok := tempMap[itemStr]if !ok {tempMap[itemStr] = trueo.sendToFlow(ctx, item.Interface(), out)}return false},
}
5. ElementAt函数
ElementAt函数用于取第几个元素,借鉴transforms.go文件的实现方式,Observable.operator等于具体的算子操作即可,其具体代码实现如下:
var tempNum int//ElementAt 取第几个元素
func (parent *Observable) ElementAt(num int) (o *Observable) {tempNum = numo = parent.newFilterObservable("elementAt")o.flip_accept_error = trueo.flip_sup_ctx = truecount = 0o.operator = elementAtOpreturn o
}var elementAtOp = filteringOperator{opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {if count == tempNum {o.sendToFlow(ctx, item.Interface(), out)return true}count++return false},
}
6. Filter函数
Filter函数用于过滤出特定的数据,此处在transforms.go文件中已定义该操作,直接将其复制到filtering.go文件中即可,另外此处笔者为了避免函数冲突,将transforms.go中的filter函数改为了filter2函数。Observable.operator等于具体的算子操作即可,其具体代码实现如下:
// Filter `func(x anytype) bool` filters items in the original Observable and returns
// a new Observable with the filtered items.
func (parent *Observable) Filter(f interface{}) (o *Observable) {// check validation of ffv := reflect.ValueOf(f)inType := []reflect.Type{typeAny}outType := []reflect.Type{typeBool}b, ctx_sup := checkFuncUpcast(fv, inType, outType, true)if !b {panic(ErrFuncFlip)}o = parent.newTransformObservable("filter")o.flip_accept_error = checkFuncAcceptError(fv)o.flip_sup_ctx = ctx_supo.flip = fv.Interface()o.operator = filterOperaterreturn o
}var filterOperater = transOperater{func(ctx context.Context, o *Observable, x reflect.Value, out chan interface{}) (end bool) {fv := reflect.ValueOf(o.flip)var params = []reflect.Value{x}rs, skip, stop, e := userFuncCall(fv, params)var item interface{} = rs[0].Interface()if stop {end = truereturn}if skip {return}if e != nil {item = e}// send dataif !end {if b, ok := item.(bool); ok && b {end = o.sendToFlow(ctx, x.Interface(), out)}}return
}}
7. First函数
First函数用于完成时返回第一个元素,借鉴transforms.go文件的实现方式,Observable.operator等于具体的算子操作即可,其具体代码实现如下:
//First 完成时返回第一个元素
func (parent *Observable) First() (o *Observable) {o = parent.newFilterObservable("first")o.flip_accept_error = trueo.flip_sup_ctx = trueo.operator = firstOpreturn o
}var firstOp = filteringOperator{opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {o.sendToFlow(ctx, item.Interface(), out)return true},
}
8. IgnoreElements函数
函数用于,借鉴transforms.go文件的实现方式,Observable.operator等于具体的算子操作即可,其具体代码实现如下:
9. Last函数
Last函数用于完成时返回最后一个元素,借鉴transforms.go文件的实现方式,Observable.operator等于具体的算子操作即可,其具体代码实现如下:
//Last 完成时返回最后一个元素
func (parent *Observable) Last() (o *Observable) {o = parent.newFilterObservable("last")o.flip_accept_error = trueo.flip_sup_ctx = trueo.operator = lastOpreturn o
}var lastOp = filteringOperator{opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {o.flip = append([]interface{}{}, item.Interface())return false},
}
10. Sample函数
Sample函数用于定期发射Observable最近发射的数据项,借鉴transforms.go文件的实现方式,Observable.operator等于具体的算子操作即可,其具体代码实现如下:
var tempSample chan interface{}//Sample 定期发射Observable最近发射的数据项
func (parent *Observable) Sample(sample chan interface{}) (o *Observable) {tempSample = sampleo = parent.newFilterObservable("sample")o.flip_accept_error = trueo.flip_sup_ctx = trueo.operator = sampleOPreturn o
}var sampleOP = filteringOperator{opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {var latest interface{} = nillatest = item.Interface()go func() {tempEnd := truefor tempEnd {select {case <-ctx.Done():tempEnd = truecase <-tempSample:if latest != nil {if o.sendToFlow(ctx, latest, out) {tempEnd = false}latest = nil}}}}()return false},
}
11. Skip函数
Skip函数用于跳过前n个数据,借鉴transforms.go文件的实现方式,Observable.operator等于具体的算子操作即可,其具体代码实现如下:
//Skip 跳过前n个数据
func (parent *Observable) Skip(num int) (o *Observable) {tempNum = numo = parent.newFilterObservable("skip")o.flip_accept_error = trueo.flip_sup_ctx = truecount = 0o.operator = skipOpreturn o
}var skipOp = filteringOperator{opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {count++if count > tempNum {o.sendToFlow(ctx, item.Interface(), out)}return false},
}
12. SkipLast函数
SkipLast函数用于跳过最后n个数据,借鉴transforms.go文件的实现方式,Observable.operator等于具体的算子操作即可,其具体代码实现如下:
var tempLasts []interface{}//SkipLast 跳过最后n个数据
func (parent *Observable) SkipLast(num int) (o *Observable) {tempNum = numo = parent.newFilterObservable("skipLast")o.flip_accept_error = trueo.flip_sup_ctx = truecount = 0o.operator = skipLastOpreturn o
}var skipLastOp = filteringOperator{opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {//var lasts []interface{}if count == tempNum {o.sendToFlow(ctx, tempLasts[0], out)tempLasts = tempLasts[1:]} else {count++}tempLasts = append(tempLasts, item.Interface())return false},
}
13. Take函数
Take函数用于取前n个数据,借鉴transforms.go文件的实现方式,Observable.operator等于具体的算子操作即可,其具体代码实现如下:
//Take 取前n个数据
func (parent *Observable) Take(num int) (o *Observable) {tempNum = numo = parent.newFilterObservable("take")o.flip_accept_error = trueo.flip_sup_ctx = truecount = 0o.operator = takeOpreturn o
}var takeOp = filteringOperator{opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {count++if count > tempNum {return true}o.sendToFlow(ctx, item.Interface(), out)return false},
}14. TakeLast函数
TakeLast函数用于取最后n个数据,借鉴transforms.go文件的实现方式,Observable.operator等于具体的算子操作即可,其具体代码实现如下:
var tempLasts2 []interface{}//TakeLast 取最后n个数据
func (parent *Observable) TakeLast(num int) (o *Observable) {tempNum = numo = parent.newFilterObservable("takeLast")o.flip_accept_error = trueo.flip_sup_ctx = truecount = 0o.operator = takeLastOpreturn o
}var takeLastOp = filteringOperator{opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {count++if count <= tempNum {tempLasts2 = append(tempLasts2, item.Interface())} else {tempLasts2 = tempLasts2[1:]tempLasts2 = append(tempLasts2, item.Interface())}o.flip = tempLasts2return false},
}
四、程序测试
1.封装并使用程序包
在项目rxgo的目录下,执行如下指令:
go build
在其他路径下建立main.go,并调用rxgo库即可。
2.功能测试
功能测试主要从用户角度测试程序包的功能,步骤如下:
创建main.go文件,内容如下(数值可自定义):
package mainimport ("fmt""time""github.com/user/rxgo"
)func main() {fmt.Print("Debounce: ")rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).Debounce(2).Subscribe(func(x int) {fmt.Print(x)fmt.Print(" ")})fmt.Println()fmt.Println()fmt.Print("Distinct: ")rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).Distinct().Subscribe(func(x int) {fmt.Print(x)fmt.Print(" ")})fmt.Println()fmt.Println()fmt.Print("ElementAt 3: ")rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).ElementAt(3).Subscribe(func(x int) {fmt.Print(x)fmt.Print(" ")})fmt.Println()fmt.Println()fmt.Print("First: ")rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).First().Subscribe(func(x int) {fmt.Print(x)fmt.Print(" ")})fmt.Println()fmt.Println()//filterfmt.Print("Filter value < 4: ")res := []int{}rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).Filter(func(x int) bool {return x < 4}).Subscribe(func(x int) {res = append(res, x)})for i := range res {fmt.Print(res[i])fmt.Print(" ")}fmt.Println()fmt.Println()fmt.Print("IgnoreElements: ")rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).IgnoreElements().Subscribe(func(x int) {fmt.Print(x)})fmt.Println()fmt.Println()fmt.Print("Last: ")rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).Last().Subscribe(func(x int) {fmt.Print(x)fmt.Print(" ")})fmt.Println()fmt.Println()fmt.Print("Sample: ")observableP := make(chan interface{})go func() {rxgo.Just(1, 2).Map(func(x int) int {switch x {case 1:time.Sleep(10 * time.Millisecond)case 2:time.Sleep(5 * time.Millisecond)default:time.Sleep(10 * time.Millisecond)}return x}).Subscribe(func(x int) {observableP <- x})}()rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).Map(func(x int) int {time.Sleep(3 * time.Millisecond)return x}).Sample(observableP).Subscribe(func(x int) {fmt.Print(x)fmt.Print(" ")})fmt.Println()fmt.Println()fmt.Print("Skip 2: ")rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).Skip(2).Subscribe(func(x int) {fmt.Print(x)fmt.Print(" ")})fmt.Println()fmt.Println()fmt.Print("SkipLast 2: ")rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).SkipLast(2).Subscribe(func(x int) {fmt.Print(x)fmt.Print(" ")})fmt.Println()fmt.Println()fmt.Print("Take 4: ")rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).Take(4).Subscribe(func(x int) {fmt.Print(x)fmt.Print(" ")})fmt.Println()fmt.Println()fmt.Print("TakeLast 3: ")rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).TakeLast(3).Subscribe(func(x int) {fmt.Print(x)fmt.Print(" ")})fmt.Println()fmt.Println()}
运行结果:

由此可知程序包的功能测试结果正确,符合的程序包中关于filtering操作的定义。
3.单元测试
单元测试主要从程序员角度,对程序包的具体函数进行测试。
建立filtering_test.go文件,对程序包的每个函数进行单元测试,此处同样借鉴pmlpml/RxGo中的transform_test文件,内容如下:
package rxgo_testimport ("testing""github.com/stretchr/testify/assert""github.com/user/rxgo"
)func TestDebounce(t *testing.T) {res := []int{}ob := rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).Map(func(x int) int {return x}).Debounce(1)ob.Subscribe(func(x int) {res = append(res, x)})assert.Equal(t, []int{1}, res, "Debounce Test Errorr")
}func TestDistinct(t *testing.T) {res := []int{}ob := rxgo.Just(1, 8, 3, 4, 2, 0, 2, 6).Map(func(x int) int {return x}).Distinct()ob.Subscribe(func(x int) {res = append(res, x)})assert.Equal(t, []int{1, 8, 3, 4, 2, 0, 6}, res, "Distinct Test Errorr")
}func TestElementAt(t *testing.T) {res := []int{}ob := rxgo.Just(1, 8, 3, 4, 2, 0, 6).Map(func(x int) int {return x}).ElementAt(2)ob.Subscribe(func(x int) {res = append(res, x)})assert.Equal(t, []int{3}, res, "SkipLast Test Errorr")
}func TestFirst(t *testing.T) {res := []int{}ob := rxgo.Just(1, 8, 3, 4, 2, 0, 6).Map(func(x int) int {return x}).First()ob.Subscribe(func(x int) {res = append(res, x)})assert.Equal(t, []int{1}, res, "First Test Errorr")
}func TestIgnoreElements(t *testing.T) {res := []int{}ob := rxgo.Just(1, 8, 3, 4, 2, 0, 6).Map(func(x int) int {return x}).IgnoreElements()ob.Subscribe(func(x int) {res = append(res, x)})assert.Equal(t, []int{}, res, "IgnoreElementsTest Errorr")
}func TestLast(t *testing.T) {res := []int{}ob := rxgo.Just(1, 8, 3, 4, 2, 0, 6).Map(func(x int) int {return x}).Last()ob.Subscribe(func(x int) {res = append(res, x)})assert.Equal(t, []int{6}, res, "Last Test Errorr")
}func TestSkip(t *testing.T) {res := []int{}ob := rxgo.Just(1, 8, 3, 4, 2, 0, 6).Map(func(x int) int {return x}).Skip(3)ob.Subscribe(func(x int) {res = append(res, x)})assert.Equal(t, []int{4, 2, 0, 6}, res, "Skip Test Errorr")
}func TestSkipLast(t *testing.T) {res := []int{}ob := rxgo.Just(1, 8, 3, 4, 2, 0, 6).Map(func(x int) int {return x}).SkipLast(3)ob.Subscribe(func(x int) {res = append(res, x)})assert.Equal(t, []int{1, 8, 3, 4}, res, "SkipLast Test Errorr")
}func TestTake(t *testing.T) {res := []int{}ob := rxgo.Just(1, 8, 3, 4, 2, 0, 6).Map(func(x int) int {return x}).Take(4)ob.Subscribe(func(x int) {res = append(res, x)})assert.Equal(t, []int{1, 8, 3, 4}, res, "Take Test Errorr")
}func TestTakeLast(t *testing.T) {res := []int{}ob := rxgo.Just(1, 8, 3, 4, 2, 0, 6).Map(func(x int) int {return x}).TakeLast(4)ob.Subscribe(func(x int) {res = append(res, x)})assert.Equal(t, []int{4, 2, 0, 6}, res, "TakeLast Test Errorr")
}结果如下(出于篇幅考虑,部分省略,用…代替):
[henryhzy@localhost rxgo]$ go test -v
=== RUN TestDebounce
--- PASS: TestDebounce (0.00s)
=== RUN TestDistinct
--- PASS: TestDistinct (0.00s)
=== RUN TestElementAt
--- PASS: TestElementAt (0.00s)
=== RUN TestFirst
--- PASS: TestFirst (0.00s)
=== RUN TestIgnoreElements
--- PASS: TestIgnoreElements (0.00s)
=== RUN TestLast
--- PASS: TestLast (0.00s)
=== RUN TestSkip
--- PASS: TestSkip (0.00s)
=== RUN TestSkipLast
--- PASS: TestSkipLast (0.00s)
=== RUN TestTake
--- PASS: TestTake (0.00s)
=== RUN TestTakeLast
--- PASS: TestTakeLast (0.00s)
...
...
ok github.com/user/rxgo 0.005s
[henryhzy@localhost rxgo]$
五、中文 api 文档
首先安装godoc如下:
git clone https://github.com/golang/tools $GOPATH/src/golang.org/x/tools
go build golang.org/x/tools
在项目rxgo所在目录下,执行如下指令:
go install
go doc
godoc -url="pkg/github.com/user/rxgo" > API.html
由此可知程序包的单元测试结果正确,符合的程序包中关于filtering操作的定义。
六、完整代码
具体代码可见gitee仓库:gitee
七、References
- 课程博客
- ReactiveX官网
相关文章:

python dataframe 中位数_python下的Pandas中DataFrame基本操作(一),基本函数整理
pandas作者Wes McKinney 在【PYTHON FOR DATA ANALYSIS】中对pandas的方方面面都有了一个权威简明的入门级的介绍,但在实际使用过程中,我发现书中的内容还只是冰山一角。谈到pandas数据的行更新、表合并等操作,一般用到的方法有concat、join、…

对输入框以及选择框集体的数据检验
对于一个档案输入框,有很多输入框是需要输入数据的,但有时候我们会在输入的时候遗留一些必填的项,如果不做数据校验,这时候点击保存按钮,就悲剧了,报错不说,我们前面填写的数据也就没有了。 所以…

CentOS Docker安装配置部署Golang web helloworld
目录【阅读时间:约5分钟】一、Docker简介二、Docker的安装与配置【CentOS环境】三、Docker部署Golang web helloworld四、Docker与虚拟机的区别五、吐槽一、Docker简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移…

[CareerCup] 2.4 Partition List 划分链表
2.4 Write code to partition a linked list around a value x, such that all nodes less than x come before all nodes greater than or equal to x. LeetCode上的原题,请参见我之前的博客Partition List 划分链表。

一条命令下载google壁纸,含错误解决方法
该命令是从google图片搜索上搜索wallpaper的大尺寸图片,匹配其中的jpg文件进行下载。 #!/bin/bash for i in {1..10}; do for url in $(wget -O- -U "" "http://images.google.com/images?imgszxxlarge&hlen&qwallpaper&saN&s…

git config —global_Git多用户配置
备注:如下的操作,Windows系统建议在Git bash工具里操作。如下操作的原理,建议查阅官方文档。Git - Reference1.取消全局设置的用户信息。Git命令:$ git config --global --unset user.name $ git config --global --unset user.em…

中级实训总结报告
目录【阅读时间:约30分钟】中级实训总结报告姓名:隐藏敏感信息 学号:隐藏敏感信息一、阶段1:项目启动1、Vi/Vim2、Java3、Ant4、Junit5、SonarQube6、 编译运行BugRunner二、阶段2:基本任务1. part2的工作(…

PHP解决方案@黑名单过滤
为什么80%的码农都做不了架构师?>>> 方案解决目标:对一些黑名单进行过滤处理 function is_spam($text, $file, $split :, $regex false){ $handle fopen($file,rb); $contents fread($handle, filesize($file)); fclose($handle); $lines …

Ubuntu 12.04下玩转终端管理器Byobu
简介 很多Linux高手都喜欢使用screen命令,screen命令可以使你轻松地使用一个终端控制其他终端。尽管screen本身是一个非常有用的工具,byobu作为screen的增强版本,比screen更加好用而且美观,并且提供有用的信息和快捷的热键。 想象…

python字典排序方法_Python字典的排序方法一则
今天需要对Python的字典进行排序,以获得有效的时间序列,采用了如下方法: 首先生成一个示例字典: >>> range_a random.sample(range(0, 10), 10) >>> range_b random.sample(range(10, 20), 10) >>> …

encodeURI 和 encodeURIComponent
保留字符 (reserved characters):这类字符是URI中的保留关键字符,它们用于分割URI中的各个部分。这些字符是:";" | "/" | "?" | ":" | "" | "&&quo…

基于Golang的简单web服务程序开发——CloudGo
基于Golang的简单web服务程序开发——CloudGo【阅读时间:约10分钟】一、概述二、系统环境&项目介绍1.系统环境2.项目的任务要求(1)基本要求(2)扩展要求三、具体程序设计及Golang代码实现1.预先准备2.CloudGoClient…

Android Studio创建项目
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010046908/article/details/47000873 创建项目 首先,先指出Android Studio中的两个概念。 Project和 Module。在Android Studio中, Project的真实含义…
Weiss的数据结构与算法分析(C++版)源码编译说明
最近尝试编译Weiss的那本数据结构与算法分析(C版)提供的源代码时,遇到一些问题,特记录如下:考虑到该书提供的代码是使用模板技术较多,这在提供简洁代码的同时,也给源码的编译带来了一些问题。因…

latex 中文_【小白向】LaTeX 中文入门
注:本文尚未撰写完毕,先暂存一下~(2020/06/27)参考学习路线[1]如何从零开始,入门 LaTeX? 孟晨 1. 卸载 CTeX 套装,安装 TeX Live原因及教程见:TeX Live 下载及安装说明2. 看完:一份其实很短的 L…

物联网兴起 嵌入式系统安全日益受关注
随着越来越多设备连接到互联网,专家们担心嵌入式系统将给企业带来严重安全风险,而很多企业还没有意识到这种风险或者无法缓解这种风险…… 随着越来越多设备连接到互联网,专家们担心嵌入式系统将给企业带来严重安全风险,而很多企业…

【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析
目录【阅读时间:约10分钟】一.概述二.对比: gorilla/mux与net/http DefaultServeMux三.简单使用四.源码简析1.NewRouter函数2.HandleFunc函数设置路由的HTTP方法设置路由的域名限制HTTP 方案设置路径前缀和子路由3.PathPrefix函数五.References一.概述 gorilla/mux…

FileMaker中的腳本觸發器學習筆記
脚本触发器 **脚本触发器是始终绑定到用户布局接口。对于数据表或者字段。只有在而已接口才能触发。**如果某一个布局或者对象上包含触发器,则其右下角会有触发器图标**当触发一个事件时,有且仅有一个触发器会被执行.布局级别的触发器**ONRECORDLOAD :加…

vim学习笔记(四)
下面是我的最近更新,差点删除。 下面的笔记摘自vimtutor。<CR>表示回车 删除命令 在normal模式下: de 删除一个单词,不包含空格 dw 删除一个单词,包含空格 dd 删除当前行 1,10d 删除指定行,第1到10行 ndd…

文件和缓存项目依赖
文件和缓存项目依赖 要创建缓存依赖,你需要创建一个 CacheDependency 对象并在添加依赖的缓存项目时使用它。例如,下面的代码创建一个缓存项目,它在一个 XML 文件被修改、删除、覆盖时自动从缓存中移除: CacheDependency prodDepe…

python函数的基础知识_Python入门基础知识点(函数进阶)
动态参数: 动态接收位置参数: def eat(*args): #在形参位置,*叫做聚合 print(我想吃,args) eat(大米饭,中米饭,小米饭) #收到的结果是一个tuple元祖 动态接收参数的时候要注意: 动态参数必须在位置参数后面,否则: def …

【CentOS】利用Kubeadm部署Kubernetes (K8s)
【CentOS】利用Kubeadm部署Kubernetes (K8s)【阅读时间:约10分钟】一、概述二、系统环境&项目介绍1.系统环境2.项目的任务要求三、具体实验流程1 系统准备2 安装常用包3 使用aliyun源安装docker-ce4 安装kubectl、kubelet、kubeadm5 初始…
HttpClient4.4 登录知乎(详细过程)
引言 HttpClient是java语言下一个支持http协议的客户端编程工具包,它实现了HTTP协议的所有方法,但是不支持JS渲染。我们在做一些小玩意时,有可能需要登录某些网站获取信息,那么HttpClient就是你的好帮手,废话不多说&am…

vim学习笔记(一)
:vertical sfind 垂直分隔窗口(vsf),但是两个窗口的内容完全相同。在编辑的时候,内容也完全相同,如果要关闭一个窗口,输入:exit即可:buffers 显示整个缓冲区列表ndG 删除从当前行到指定n行中的…

Retrofit源码研究
2016-05-06 15:35:27 最近抽空研究了一下Retrofit源码,包括API使用、源码结构、使用到的设计模式、SDK的架构设计、作者设计/实现思路等,会形成一系列文章。 以前Retrofit还是1.9的时候,简单的写过一篇文章,简单研究下Retrofit&am…

wpf窗口向左向上_PaperWM:GNOME 下的平铺窗口管理
我使用 Gnome 已有很长时间了,但是我仍然有点想念平铺窗口管理器。六个月前,一个朋友告诉我有关 PaperWM 的消息,它使你可以在 Gnome 中平铺窗口!我立即安装了它,并从那时起我一直在使用它。-- Julia Evans(作者)当我开…

Docker的安装、镜像源更换与简单应用
Docker的安装、镜像源更换与简单应用【阅读时间:约20分钟】一、概述二、系统环境&项目介绍1.系统环境2.项目的任务要求三、Docker的安装四、Docker的简单应用1. 运行第一个容器2. Docker基本操作3. MySQL与容器化3.1 拉取MySQL镜像3.2 构建docker镜像3.3 MySQL容…

vim学习笔记(三)
1.vim的配置文件在哪里?在normal模式下输入:echo $VIMVim的主配置文件为vimrc文件,它分为两个版本:global和personal,其中前者一般在/usr/share/vim/vimrc,后者一般在~/.vimrc,它是一个隐藏文件找到home目录的方法:ech…

python 学术_Python
前几天实验室一个师兄给我一个质谱结果,让帮忙做下go的功能富集,数据格式大概是这样的:由于之前做go和kegg时都是跑流程,像这种针对性的go富集还没做过,说到底,还是由于自己手上缺少数据,没有属…
Hive的Security配置
为了更好地使用好Hive,我将《Programming Hive》的Security章节取出来,翻译了一下。 Hive还是支持相当多的权限管理功能,满足一般数据仓库的使用。 Hive由一个默认的设置来配置新建文件的默认权限。 Xml代码 <property> <name>…