Maison > Article > développement back-end > Programmation de flux minimaliste en Golang
Les inconvénients apportés par la méthode de codage procédurale traditionnelle sont évidents. Nous avons souvent cette expérience du code qui n'a pas été maintenu pendant un certain temps ou du code d'autres personnes qui met soudainement beaucoup de temps à revenir et à comprendre l'idée originale. cette fois, s'il existe un document ou une annotation bien rédigé, cela peut prendre moins de temps, mais même ainsi, de nombreuses relations d'appel doivent être confirmées à plusieurs reprises avant d'apporter des modifications.
Ce qui suit est un morceau de pseudo-code décrivant la méthode de codage procédural :
func A(){ B() C() } func B(){ do something D() } func C(){ do something } func D(){ do something } func main(){ A() }
Comparez la méthode d'écriture du style de streaming :
NewStream(). Next(A). Next(B). Next(D). Next(C). Go()
Lorsque la relation d'appel de code de style procédural est complexe, les programmeurs doivent agir avec prudence et prudence. avec le style streaming, le code est relativement propre et la structure principale est claire, ce qui présente des avantages évidents, en particulier lorsqu'il s'agit de changements d'exigences.
Java8 emprunte des expressions lambda pour implémenter un style de programmation de streaming relativement parfait. En tant que langage simple, Golang n'a pas encore de package officiel de style de streaming (il existe peut-être depuis longtemps, peut-être que je suis ignorant), qui est un. pitié. .
J'ai fait référence au code de gorequest et implémenté un package de style streaming relativement courant. Le principe d'implémentation est de former une liste chaînée de tâches. Chaque nœud enregistre le premier nœud, le nœud suivant et le rappel que le nœud doit exécuter. . Une fois la tâche de streaming démarrée, elle sera exécutée une par une à partir du premier nœud. Si une exception est rencontrée, la tâche de streaming sera terminée jusqu'à ce que la dernière soit exécutée, mettant ainsi fin à la chaîne de tâches. Jetons d'abord un coup d'œil au code :
package Stream import ( "errors" "fmt")/** 流式工作原理: 各个任务都过指针链表的方式组成一个任务链,这个任务链从第一个开始执行,直到最后一个 每一个任务节点执行完毕会将结果带入到下一级任务节点中。 每一个任务是一个Stream节点,每个任务节点都包含首节点和下一个任务节点的指针, 除了首节点,每个节都会设置一个回调函数的指针,用本节点的任务执行, 最后一个节点的nextStream为空,表示任务链结束。 **///定回调函数指针的类型type CB func(interface{}) (interface{}, error)//任务节点结构定义type Stream struct { //任务链表首节点,其他非首节点此指针永远指向首节点 firstStream *Stream //任务链表下一个节点,为空表示任务结束 nextStream *Stream //当前任务对应的执行处理函数,首节点没有可执行任务,处理函数指针为空 cb CB }/** 创建新的流 **/func NewStream() *Stream { //生成新的节点 stream := &Stream{} //设置第一个首节点,为自己 //其他节点会调用run方法将从firs指针开始执行,直到next为空 stream.firstStream = stream //fmt.Println("new first", stream) return stream }/** 流结束 arg为流初始参数,初始参数放在End方法中是考虑到初始参数不需在任务链中传递 **/func (this *Stream) Go(arg interface{}) (interface{}, error) { //设置为任务链结束 this.nextStream = nil //fmt.Println("first=", this.firstStream, "second=", this.firstStream.nextStream) //检查是否有任务节点存在,存在则调用run方法 //run方法是首先执行本任务回调函数指针,然后查找下一个任务节点,并调用run方法 if this.firstStream.nextStream != nil { return this.firstStream.nextStream.run(arg) } else { //流式任务终止 return nil, errors.New("Not found execute node.") } } func (this *Stream) run(arg interface{}) (interface{}, error) { //fmt.Println("run,args=", args) //执行本节点函数指针 result, err := this.cb(arg) //然后调用下一个节点的Run方法 if this.nextStream != nil && err == nil { return this.nextStream.run(result) } else { //任务链终端,流式任务执行完毕 return result, err } } func (this *Stream) Next(cb CB) *Stream { //创建新的Stream,将新的任务节点Stream连接在后面 this.nextStream = &Stream{} //设置流式任务链的首节点 this.nextStream.firstStream = this.firstStream //设置本任务的回调函数指针 this.nextStream.cb = cb //fmt.Println("next=", this.nextStream) return this.nextStream }
Ce qui suit est un exemple de streaming, prenant comme exemple le processus du lever le matin à la sortie du travail :
//起床func GetUP(arg interface{}) (interface{}, error) { t, _ := arg.(string) fmt.Println("铃铃.......", t, "###到时间啦,再不起又要迟到了!") return "醒着的状态", nil }//蹲坑func GetPit(arg interface{}) (interface{}, error) { s, _ := arg.(string) fmt.Println(s, "###每早必做的功课,蹲坑!") return "舒服啦", nil }//洗脸func GetFace(arg interface{}) (interface{}, error) { s, _ := arg.(string) fmt.Println(s, "###洗脸很重要!") return "脸已经洗干净了,可以去见人了", nil }//刷牙func GetTooth(arg interface{}) (interface{}, error) { s, _ := arg.(string) fmt.Println(s, "###刷牙也很重要!") return "牙也刷干净了,可以放心的大笑", nil }//吃早饭func GetEat(arg interface{}) (interface{}, error) { s, _ := arg.(string) fmt.Println(s, "###吃饭是必须的(需求变更了,原来的流程里没有,这次加上)") return "吃饱饱了", nil }//换衣服func GetCloth(arg interface{}) (interface{}, error) { s, _ := arg.(string) fmt.Println(s, "###还要增加一个换衣服的流程!") return "找到心仪的衣服了", nil }//出门func GetOut(arg interface{}) (interface{}, error) { s, _ := arg.(string) fmt.Println(s, "###一切就绪,可以出门啦!") return "", nil } func main() { NewStream(). Next(GetUP). Next(GetPit). Next(GetTooth). Next(GetFace). Next(GetEat).//需求变更了后加上的 Next(GetCloth). Next(GetOut). Go("2018年1月28日8点10分") }
D'après le code ci-dessus, le style de codage en streaming est décomposé pour une grande tâche Après avoir été divisé en plusieurs petites tâches, il est très intuitif au niveau du code, et vous n'avez plus à travailler dur pour savoir laquelle est appelée. De plus, il est plus facile de modifier les exigences. Dans l'exemple ci-dessus, le petit-déjeuner n'a pas été implémenté dans la première version. Le client a déclaré qu'il devait manger le matin, sinon il développerait facilement des calculs biliaires. La deuxième version doit être ajoutée. à la position de réponse. Par rapport au codage procédural, c’est beaucoup plus simple.
Pour plus d'articles techniques liés au golang, veuillez visiter la colonne golangtutorial !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!