还在为 Go 中繁琐 if-else 逻辑的烦恼 那就用 vowlink 来解决
我是 LEE,老李,一个在 IT 行业摸爬滚打 17 年的技术老兵。
在开始今天的话题之前,我想先从这段代码开始今天的内容分享。在日常的开发过程中,我们经常遇到需要在业务逻辑代码中使用 if-else 语句。
然而,随着业务的增长,这种 if-else 逻辑代码往往会变得越来越复杂,逻辑判断也会变得越来越多,导致代码的可读性和可维护性下降。因此,我们需要考虑如何优化这种 if-else 逻辑代码。
举个例子,假设我们正在使用 gin 框架开发一个 web service,需要根据不同的请求参数来执行不同的逻辑来更改数据库中的数据。在这种情况下,我们通常会使用 if-else 语句来实现这个功能。
funcUpdateData(c*gin.Context){
varreqstruct{
IDint`json:"id"`
Namestring`json:"name"`
}
//解析请求参数,将请求参数绑定到结构体中
iferr:=c.ShouldBindJSON(err!=nil{
c.JSON(http.StatusBadRequest,gin.H{"error":err.Error()})
return
}
//解析出的参数有效性检查,当然这里已经很多库实现了参数校验,这里只是举例
ifreq.ID==0{
c.JSON(http.StatusBadRequest,gin.H{"error":"idisrequired"})
return
}
ifreq.Name==""{
c.JSON(http.StatusBadRequest,gin.H{"error":"nameisrequired"})
return
}
//根据请求参数执行不同的逻辑,根据结果返回不同的响应
ifresult,err:=db.UpdateName(req.ID,req.Name);err!=nil{
c.JSON(http.StatusInternalServerError,gin.H{"error":err.Error()})
return
}else{
c.JSON(http.StatusOK,gin.H{"message":"success","result":result})
}
}
这段代码展示了在使用 gin 框架开发 Handle 时常见的逻辑。然而,随着业务的增长,其中的 if-else 逻辑代码变得越来越复杂,逻辑判断也变得越来越多,导致代码的可读性和可维护性下降。
值得注意的是,c.ShouldBindJSON(&req) 的输出作为 db.UpdateName(req.ID, req.Name) 的输入,中间经过大量的 if-else 逻辑代码进行参数校验和错误处理。我们可以整理思路,将从 req 到 c.JSON 的逻辑视为一条具有多个可控分支的路径。
另外,我们再看一个例子:这段代码展示了一个经典的嵌套 if-else 逻辑代码(地域嵌套)。如果在其中发现了无法预料的错误,将会带来很大的困扰。
funcdoSomething(dataStruct)error{
company:=data.Commpay
ifcompany.Name=="hw"{
techGroup:=company.TechGroup
iftechGroup.Type=="electronic"{
groupType:=techGroup.GroupType
ifgroupType.Level=="A"{
groupResearch:=groupType.Research
ifgroupResearch.Product=="phone"{
proVersion:=groupResearch.Version
ifproVersion.Version=="1"{
//dosomething
}else{
//dosomething
}
}else{
//dosomething
}
}else{
//dosomething
}
}else{
//dosomething
}
}
}
在 Golang 中,由于缺乏像 try 和 catch 这样的语法结构,我们通常使用 if-else 逻辑代码来实现参数校验、错误处理和业务逻辑等多种功能。
然而,这种做法往往导致代码变得复杂,逻辑判断增多,可读性和可维护性下降。
那么,如何利用 Golang 的函数式编程来简化 if-else 逻辑代码呢?让我们开始今天的故事。
事件背景2023 年底,一位同事向我求助,他在开发业务逻辑时遇到了频繁的错误,并且花费了整个周末都无法解决问题。
我询问了他具体的情况,他说问题出现在一个复杂的 if-else 逻辑代码中,其中的逻辑判断过多,导致代码变得复杂难以理解,他不知道从何处着手进行优化。我表示愿意帮助他,并开始对代码进行审查。
经过仔细查看,我发现他的代码确实是一个典型的 if-else 逻辑代码,其中的逻辑判断过多,导致代码复杂且难以维护。我告诉他,他需要对代码进行优化。他认可这一点,但是不知道如何下手。
我们进行了一段时间的讨论,通过大量的断点调试和代码追踪,最终发现了一个逻辑判断错误,导致了后续大量嵌套的 if-else 逻辑代码无法执行。
为了解决这个问题,我决定从零开始编写一个 Golang 的通用库,用于优化复杂的 if-else 逻辑代码。
这个库将提供链式调用、处理结果前后依赖、错误处理、兜底处理以及多种调用链之间的竞争等功能,以帮助开发人员优化复杂的逻辑判断流程。
通过反复的调研发现 JavaScript 中的 Promise 对于处理这样的操作非常方便,因此我决定借鉴 Promise 的概念,实现一个类似于 Promise 的函数式编程库,用于优化复杂的 if-else 逻辑代码。
于是,vowlink 诞生了。
痛点分析如前文所述,随着业务的增长,复杂的 if-else 逻辑代码会变得越来越复杂,逻辑判断也会增多,导致代码的可读性和可维护性下降。为了解决这个问题,我们需要考虑优化这种逻辑代码的方法。
以下是需要解决的问题和痛点:
代码复杂:反复编写 if-else 逻辑代码导致代码复杂,难以理解。代码重复:逻辑判断代码重复导致代码冗余,难以维护。逻辑混乱:逻辑判断代码嵌套导致逻辑混乱,难以阅读。风险未知:逻辑判断代码存在潜在风险,导致系统不稳定,难以维护。为了解决以上问题,我们需要具备以下特点的工具:
简单易用:工具易于上手,学习成本低。高效执行:工具能够快速、高效地处理各种逻辑控制任务。逻辑控制:工具提供逻辑控制功能,简化复杂的逻辑判断。错误处理:工具提供错误处理功能,处理各种错误信息。兜底处理:工具提供兜底处理功能,处理最终的逻辑。竞争关系:工具提供处理多种调用链之间竞争关系的功能。项目介绍vowlink : https://github.com/shengyanli1982/vowlink
1111.pngvowlink 是一个基于 Golang 的函数式编程库,旨在优化复杂的 if-else 逻辑代码。它借鉴了 JavaScript 中 Promise 的概念,并提供了链式调用、处理结果前后依赖、错误处理、兜底处理以及多种调用链之间的竞争等功能。
vowlink 不是要取代 Golang 的 if-else 的写法,而是提供一种优化的选项,没有非黑即白。这里需要强调下:因为每一个开发者的习惯不同,这个库可能不适合你,但并不意味着 vowlink 不好。它是经过其他开发者的测试和试用后才开源的。
vowlink 的目标是提供一个简单易用的 Golang 库,用于优化复杂的逻辑控制流程,以提高代码的可读性和可维护性。
vowlink 提供以下功能来优化代码逻辑:
链式调用: 通过链式调用方式简化复杂的 if-else 逻辑代码。处理前后依赖: 使用 Then().Then() 方法处理结果前后依赖,上次执行结果作为下一次执行的输入。错误处理: 使用 Catch() 方法处理错误信息,提高代码的可读性。兜底处理: 使用 Finally() 方法处理最终的逻辑,如资源释放等。调用链竞争: 使用 Race()、All()、Any() 和 AllSettled() 方法处理多种调用链之间的竞争关系。在 vowlink 的世界中,每个 vow 都类似于 JavaScript 的 Promise,它可以表示异步操作的结果或状态。vow 具有三种状态:Pending、Fulfilled 和 Rejected。一旦 vow 的状态发生改变,它将保持不变,与 JavaScript 的 Promise 的状态相同。
vow 与 Race()、All()、Any() 和 AllSettled() 函数没有必然的关联,它们可以独立运行。然而,在 vowlink 中,它们是一家人,都是 vow 的一种表现形式。简单来说,Race()、All()、Any() 和 AllSettled() 函数是更高级的容器,用于处理多个 vow 之间的竞争、并行和串行操作。
基于 vow 的特性,vowlink 提供了一系列函数,使开发者能够更方便地编写逻辑判断流程。同时,结合 Race()、All()、Any() 和 AllSettled() 函数,可以处理多个调用链之间的竞争关系。在大多数情况下,vowlink 可以替代复杂的 if-else 逻辑代码,提高代码的可读性和可维护性。
尽管在 GitHub 上可以找到许多类似的库,但我发现这些库要么功能过于复杂,要么功能过于简单,要么代码过于复杂,要么代码过于简单。因此,我决定从零开始,自己动手实现一个轻量级的函数式逻辑控制库,这就是 vowlink。
设计初衷:
轻量化:vowlink 是一个精简的库,代码量少,易于使用。简单易用:vowlink 提供简洁的接口,只需几行代码即可完成任务处理逻辑编写。高效执行:vowlink 执行效率高,能够快速、高效地处理各种逻辑控制任务。状态机设计 为了让 vowlink 简单易用且高效执行,它的架构设计必须简洁可靠。
由于 vowlink 在某种程度上可以被视为 JavaScript 中 Promise 的实现,因此 vowlink 的状态机设计也参考了 JavaScript 中 Promise 的状态机设计。
Promise 流程图vow-link-1.pngPromise 状态定义PromiseState 是一个枚举类型,它定义了 Promise 的三种状态:Pending、Fulfilled 和 Rejected。
//定义 Promise 的三种状态:Pending、Fulfilled 和 Rejected
//DefinethethreestatesofaPromise:Pending,Fulfilled,andRejected
const(
// Pending 代表一个 Promise 的 pending 状态,即 Promise 还在等待结果,既没有完成也没有被拒绝。
//Pendingrepresentsthependingstateofapromise,whichmeansthePromiseisstillwaitingfortheresult,neitherfulfillednorrejected.
PendingPromiseState=iota
// Fulfilled 代表一个 Promise 的 fulfilled 状态,即 Promise 已经完成,有一个确定的结果值。
//Fulfilledrepresentsthefulfilledstateofapromise,whichmeansthePromiseisfulfilledandhasadefiniteresultvalue.
Fulfilled
// Rejected 代表一个 Promise 的 rejected 状态,即 Promise 已经被拒绝,有一个确定的错误原因。
//Rejectedrepresentstherejectedstateofapromise,whichmeansthePromiseisrejectedandhasadefinitereasonfortheerror.
Rejected
)
Promise 结构体定义Promise 是一个结构体,它代表一个 Promise。内部结构也非常的简单,由状态,结果和错误信息组成。
// Promise 是一个结构体,它代表一个 Promise。Promise 是一种编程模式,用于处理异步操作。
//PromiseisastructthatrepresentsaPromise.APromiseisaprogrammingpatternforhandlingasynchronousoperations.
typePromisestruct{
// state 是 Promise 的状态,它可以是 Pending、Fulfilled 或 Rejected。
//stateisthestateofthePromise,itcanbePending,Fulfilled,orRejected.
statePromiseState
// value 是 Promise 的值,当 Promise 被 resolve 时,这个值会被设置。
//valueisthevalueofthePromise,thisvaluewillbesetwhenthePromiseisresolved.
valueinterface{}
// reason 是 Promise 被拒绝的原因,当 Promise 被 reject 时,这个值会被设置。
//reasonisthereasonthePromisewasrejected,thisvaluewillbesetwhenthePromiseisrejected.
reasonerror
}
接口设计 vowlink 的接口设计简洁明了,通过链式调用方式将内部的多个方法串联起来,实现逻辑控制。
方法接口vowlink 提供了几个简洁易用的方法接口:
Then: 用于处理成功的逻辑,类似于处理 if 逻辑代码中的 if err == nil 后的操作。Catch: 用于处理失败的逻辑,类似于处理 if 逻辑代码中的 if err != nil 后的操作。Finally: 用于处理最终的逻辑,类似于处理 if 逻辑代码中的 defer 后的操作。GetValue: 用于获取当前处理结果。GetReason: 用于获取当前处理的错误信息。在提供的接口方法中,Then、Catch、Finally 方法是执行方法,而 GetValue 和 GetReason 方法是结果方法。
GetValue 和 GetReason 方法获取的结果是在 Then、Catch、Finally 方法执行完成后的结果。
返回结果当使用 vowlink 执行一个函数的逻辑控制时,经过多次判断和处理后,最终会返回一个新的 Promise 结构体,其中包含函数的执行结果和错误信息。可以通过 GetValue 和 GetReason 方法获取结果和错误信息。
举个例子:
funcmain(){
//创建一个新的Promise
//CreateanewPromise
result:=vl.NewPromise(func(resolvefunc(interface{},error),rejectfunc(interface{},error)){
//这个promise直接解析为"helloworld"
//Thispromiseisdirectlyresolvedto"helloworld"
resolve("helloworld",nil)
})
//从promise中获取值并打印
//Getthevaluefromthepromiseandprintit
fmt.Println(result.GetValue())
}
使用示例 以下示例展示了如何使用 vowlink 优化 if-else 逻辑代码。通过创建两个不同状态的 vow,一个成功的 vow 和一个失败的 vow,然后使用 Then 方法处理成功的逻辑,使用 Catch 方法处理失败的逻辑。
最后,使用 GetValue 和 GetReason 方法获取结果和错误信息。
更多的示例,可以参考 vowlink 项目中的 examples 目录里面的示例代码。那里面已经基本覆盖了常见的用法。
举个例子:
packagemain
import(
"fmt"
vl"github.com/shengyanli1982/vowlink"
)
funcmain(){
// vowlink 像一个链条,你可以在链条上添加更多的 then()来在 promise 解析后做更多的事情。
//vowlinkislikeachain,youcanaddmorethen()tothechaintodomorethingsafterthepromiseisresolved.
result:=vl.NewPromise(func(resolvefunc(interface{},error),rejectfunc(interface{},error)){
//这个promise直接解析为"helloworld"
//Thispromiseisdirectlyresolvedto"helloworld"
resolve("helloworld",nil)
}).Then(func(valueinterface{})(interface{},error){
//在Then方法中,我们将解析的值加上"vowlink!!"
//IntheThenmethod,weappend"vowlink!!"totheresolvedvalue
returnvalue.(string)+"vowlink!!",nil
},func(errerror)(interface{},error){
//如果promise被拒绝,我们将返回一个新的错误信息"rejected."
//Ifthepromiseisrejected,wereturnanewerrormessage"rejected."
returnnil,fmt.Errorf("rejected.")
})
//从promise中获取值并打印
//Getthevaluefromthepromiseandprintit
fmt.Println("Resolve:",result.GetValue())
//这是一个被拒绝的promise
//Thisisarejectedpromise
result=vl.NewPromise(func(resolvefunc(interface{},error),rejectfunc(interface{},error)){
//这个promise被拒绝,原因是"error"
//Thispromiseisrejectedwiththereason"error"
reject(nil,fmt.Errorf("error"))
}).Then(func(valueinterface{})(interface{},error){
//如果promise被解析,我们将解析的值加上"vowlink"
//Ifthepromiseisresolved,weappend"vowlink"totheresolvedvalue
returnvalue.(string)+"vowlink",nil
},func(errerror)(interface{},error){
//如果promise被拒绝,我们将返回一个新的错误信息"rejected."
//Ifthepromiseisrejected,wereturnanewerrormessage"rejected."
returnnil,fmt.Errorf("rejected.")
})
//从promise中获取拒绝的原因并打印
//Getthereasonfortherejectionfromthepromiseandprintit
fmt.Println("Rejected:",result.GetReason().Error())
}
输出结果:
$gorundemo.go
Resolve:helloworldvowlink!!
Rejected:rejected.
总结vowlink 是一个轻量级的库,用于对函数进行逻辑控制。它的设计简单、易用且高效,使得开发人员能够以较低的学习成本快速上手。
通过使用 vowlink,我们能够标准化重试操作,并实现逻辑代码的多处复用。这大大减少了重复编写代码的时间,提高了开发质量。使用 vowlink,整个项目的代码看起来更加清爽、简洁而不简单。
如果您有任何问题或建议,请在 vowlink 的 GitHub 上提出 issue。我将尽快回复您的问题。
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线