【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>…