编程规范-控制流程、错误和异常处理

news2024/12/25 9:30:59

前言: \textcolor{Green}{前言:} 前言:

💞这个专栏就专门来记录一下寒假参加的第五期字节跳动训练营
💞从这个专栏里面可以迅速获得Go的知识

今天的笔记是对编程规范的补充,对控制流程、错误和异常处理进行总结。通过这次的学习我们会对接下来的项目编写有很大的好处。

1.2.4 编码规范 - 控制流程

避免嵌套,保持正常流程清晰

如果两个分支中都包含 return 语句,则可以去除冗余的 else。方便后续的维护,else 一般是正常流程,如果需要在正常流程新增判断逻辑,则需要避免分支嵌套

// Bad
if foo {
    return x
} else {
    return nil
}

// Good
if foo {
    return x
}

尽量保持正常代码路径为最小缩进

  • 优先处理错误情况/特殊情况,尽早返回或继续循环来减少嵌套
// Bad
func OneFunc() error {
    err := doSomething()
    if err == nil {
        err := doAnotherThing()
        if err == nil {
            return nil // normal case
        }
    }
}

通过上面的代码发现:

  1. 最常见的正常流程的路径被嵌套在两个 if 条件内
  2. 成功的退出条件是 return nil,必须仔细匹配大括号来发现
  3. 函数最后一行返回一个错误,需要追溯到匹配的左括号,才能了解何时会出发错误
  4. 如果后续正常流程需要增加一步操作,调用新的函数,则又会增加一层嵌套。

尽量保持正常代码路径为最小路径

调整后的代码:从上到下就是正常流程的执行过程。后续想排查问题可以针对具体问题进行错误详细分析。如果想正常流程新增操作,可以放心大胆的在函数中添加新的代码

// Good
func OneFunc() error {
    if err := doSomething(); err != nil {
        return err
    }
    if err := doAnotherThing(); err != nil {
        return err;
    }
    return nil // normal case
}

下面是 go 仓库中的代码案例,也是优先处理 err 情况,保持正常流程的统一。
github中go仓库
在这里插入图片描述

编码规范 - 控制流程总结

  • 线性原理,处理逻辑尽量走直线,避免复杂的嵌套分支
  • 正常流程代码沿着屏幕向下移动

    go 代码不是成功的路径越来越深的嵌套到右边。

  • 提供代码可维护性和可读性

    一个功能可以通过多个功能的线性结合来实现,那么结构就会非常简单。反之用条件分支控制代码、毫无章法的增加状态数等行为会让代码变得难理解,要避免这种情况增加可读性。
    正常流程应该自上而下,简单清晰地进行处理,代码可读性和可维护性都会提高,添加功能也会变得容易。

  • 故障问题大多出现在复杂的条件语句和循环语句中

    在维护这种逻辑时,添加功能就会变成高风险操作,容易遗漏部分条件导致问题。

1.2.5 编码规范 - 错误和异常处理

简单错误

  • 简单地错误是指仅出现一次地错误,且在其他地方不需要捕获该错误
  • 优先使用 errors.New 来创建匿名变量来直接表示简单错误
  • 如果有格式的需求,使用 fmt.Errorf
    在这里插入图片描述

错误的 Wrap 和 Unwrap

  • 错误的 Wrap 实际上提供了一个 error 嵌套另一个 error 的能力,从而生成了一个 error 的跟踪链
  • 在 fmt.Errorf 中使用:%w 关键字来将一个错误关连至错误链中

要注意:GO1.13在 errors 中新增了三个新API和一个新的 format 关键字,分别是 errors.is,errors.As,errors.Unwrap 以及 fmt.Errorf 的 %w。如果项目运行小于Go1.13的版本,需要导入 golang.org/x/xerrors 来使用。
在这里插入图片描述

错误判定

  • 判定一个错误是否为特定错误,使用 errors.Is
  • 不同于使用 == ,使用该方法可以判定错误链上的所有错误是否含有特定的错误。

在这里插入图片描述

错误判定

  • 在错误链上获取特定种类的错误,使用 errors.As

在这里插入图片描述

panic

  • 不建议在业务代码中使用 panic。因为 panic 发生后,会向上传播至调用栈顶。
  • 调用函数不包含 recover 就会造成整个程序崩溃。
  • 若问题可以屏蔽或解决,建议使用 error 代替 panic
  • 特殊:当程序启动发生不可逆转的错误时,可以在 init 或 main 函数中使用 panic。因为在这种情况下,服务启动起来也不会有意义。
    例如:下图中的代码,启动消息队列监听器的逻辑,在创建消费组失败的时候会 panicf,实际打印日志,然后再抛出 panic。
    在这里插入图片描述

recover
由于不能控制所有的代码,避免不了引入其他库,如果是引入库的 bug 导致 panic,影响到自身的逻辑应该如何处理。此时我们应该注意 recover 的生效条件

  • recover 只能被 defer 的函数中使用
  • 嵌套无法生效
  • 只在当前 goroutine 生效
  • defer 的语句是后进先出

在这里插入图片描述

  • 如果需要更多的上下文信息,可以 recover 后在 log 中记录当前的调用栈
    在这里插入图片描述

编码规范-错误和异常处理小结

  • error 尽可能提供简明的上下文信息链,方便定位问题
  • panic 用于真正异常的情况
  • recover 生效范围,在当前 goroutine 的被 defer 的函数中生效

例子

哪种命名方式更好

package time
// A function returns the current local time
// which one is better
func Now() Time
// or
fun NowTime() Time

实际过程中:Now 和 NowTime 返回的是 time.Time类型,使用时我们没有必要协程 time.NowTime 来额外表示时间信息,使用 Now 更简洁

t := time.Now()
t := time.NowTime()

接下来再看

package time
// A function pares a duration string
// such as "300ms", "-1.5h" or "2h45m"
func Parse(s string) (Duration, error)
// or
func ParseDuration(s string) (Duration, error)

看到这里持续时间并不是 time 类型,使用 time.ParseDuration() 返回的是 time.Duration 类型。所以此时在函数命名中体现就是冗余了,所以我们使用 ParseDuration更好

duration := time.Parse(s)
duration := time.ParseDuration(s)

程序的输出是什么

func main() {
    if true {
        defer fmt.Printf("1")
    } else {
        defer fmt.Printf("2")
    }
    defer fmt.Printf("3")
}
  • defer 语句在函数返回前调用
  • 多个 defer 语句是后进先出

最终得到我们的答案:31

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/686839.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ansys Zemax | 内窥镜物镜系统初始结构的优化提升(下)

系统性能提升 根据上篇的内窥镜系统分析,我们可以从四个方面对内窥镜物镜系统进行优化:元件间距、圆锥系数、MTF 值以及畸变值。点击优化-评价函数编辑器以设置具体的评价函数。(联系我们获取文章附件) 首先,用三个 CO…

NXP i.MX 8M Plus工业开发板硬件说明书--下册( 四核ARM Cortex-A53 + 单核ARM Cortex-M7,主频1.6GHz)

前 言 本文档主要介绍创龙科技TLIMX8MP-EVM评估板硬件接口资源以及设计注意事项等内容。 创龙科技TLIMX8MP-EVM是一款基于NXP i.MX 8M Plus的四核ARM Cortex-A53 单核ARM Cortex-M7异构多核处理器设计的高性能工业评估板,由核心板和评估底板组成。ARM Cortex-A5…

【AndroidUI设计】Bottom Navigation Activity中Fragment(碎片)的添加和下层导航图标的修改

文章目录 一、引言二、设计1、添加Fragment&#xff08;1&#xff09;确认需求&#xff08;2&#xff09;创建 <1> 方法一&#xff1a;借助工具快速生成 <2> 方法二&#xff1a;视图&#xff08;图层&#xff09;工具 <3> 方法三&#xff1a;手动…

知网G4《语数外学习》简介及投稿邮箱

知网G4教育专刊《语数外学习》简介及投稿邮箱 《语数外学习》全新改版&#xff0c;分别针对初中三个不同年级&#xff0c;每本仍然兼顾语数外三个学科。改版后的《语数外学习》将密切关注课改和中考改革的进程&#xff0c;与教材同步&#xff0c;在帮中学生朋友释疑疑惑、提高…

DOTA-PEG3-azide,1428146-79-5,DOTA三聚乙二醇叠氮,试剂相关研究说明

DOTA-PEG3-azide&#xff0c;DOTA PEG3 N3&#xff0c;DOTA三聚乙二醇叠氮产品结构式&#xff1a; 产品规格&#xff1a; 1.CAS号&#xff1a;1428146-79-5 2.分子式&#xff1a;C24H44N8O10 3.分子量&#xff1a;604.66 4.包装规格&#xff1a;白色固体 &#xff0c;1g、5g、1…

数据库性能测试

目录 前言&#xff1a; 1.引入数据库驱动包 2.添加数据库配置元件 3、JDBCRequest参数化 4、Variablesnames参数使用方法&#xff1a; 前言&#xff1a; 数据库性能测试是测试数据库系统在各种条件下的性能和稳定性的过程。它可以帮助测试人员识别数据库系统的性能瓶颈&a…

30余名「实在RPA·数字员工」在纳爱斯诞生,在618中服务千万消费者!

积水成渊&#xff0c;聚沙成塔&#xff01;谁在世界数字化大势中不断变革自己&#xff1f; 长期蝉联“中国品牌价值评价”日化行业首位&#xff0c;问鼎中国工业“奥斯卡”大奖的“大国品牌”纳爱斯——当仁不让&#xff01; 纳爱斯是日化行业领军企业&#xff0c;业务覆盖家…

SpringBoot整合MybatisPlus 自动生成controller、mapper、entity、service

首先创建SpringBoot项目 选择依赖 把application的后缀改为.yml&#xff0c;方便些。 pom.xml&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w…

一次完整的性能测试,测试人员需要做什么

目录 前言&#xff1a; 一、 规范性能测试实施流程的意义 二、 性能测试实施流程 1. 需求调研阶段 2. 测试准备阶段 3. 测试执行阶段 4. 测试报告阶段 5. 测试总结阶段 前言&#xff1a; 进行一次完整的性能测试需要经过多个阶段&#xff0c;包括需求分析、测试计划编…

OpenStack(3)--vxlan网络实战

目录 一、ML2配置文件 二、上传cirros镜像 三、创建vxlan10网络 四、创建实例/同vxlan通信测试 五、不同vxlan通信测试 5.1 新建vxlan11 5.2 新建路由/添加路由接口 5.3 不同vxlan通信测试 5.4 qemu-vnc报错 六、深度剖析vxlan 七、认识 Bridge br-ex、Bridge br-in…

「一本通 3.2 练习 6」汽车加油行驶

目录 第一步&#xff0c;二维转一维&#xff08;此步仅为方便&#xff0c;可以省略&#xff09; 第二步&#xff0c;建边&#xff08;啥都行&#xff0c;只要死不了&#xff09; 第三部&#xff0c;bfs&#xff08;你要dfs也行&#xff09; 第一步 第二步 第三步 可CA呢…

蓝桥杯专题-试题版-【01字符串】【2n皇后问题】【A+B问题】【Fibonacci数列】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

ECS 简略版说明一:Entities and components

目录 Entities and components Worlds and EntityManagers Archetypes Chunks Queries Entity IDs IComponentData Managed IComponentData components DynamicBuffer components Aspects Allocator overview Allocator.Temp Allocator.TempJob Allocator.Persis…

MySQL性能测试及调优中的死锁处理方法

目录 前言&#xff1a; 1、死锁检测 2、死锁避免 3、死锁解决 前言&#xff1a; MySQL死锁是指多个会话同时请求相同资源时发生的一种资源争用现象&#xff0c;导致会话无法继续执行。死锁的发生会导致事务无法提交或者回滚&#xff0c;影响应用程序的正常运行。因此&#xff0…

consul简介与安装

一、Consul简介 Consul 是 HashiCorp 公司推出的开源产品&#xff0c;用于实现分布式系统的服务发现、服务隔离、服务配置&#xff0c;这些功能中的每一个都可以根据需要单独使用&#xff0c;也可以同时使用所有功能。Consul 官网目前主要推 Consul 在服务网格中的使用。 与其…

【人工智能】教你如何让 AI 赢得贪吃蛇游戏----强化学习(初探)

人工智能--AI贪吃蛇&#xff0c;每一个代码都有详细的注释&#xff0c;希望多多收藏&#xff0c;点赞&#xff0c;评论 1.前言&#xff1a;训练ai玩游戏的可行性2.代码实现思路&#xff1a;3.代码完整实现3.1 Game Game.py 完整实现3.1.1 安装pygame库3.1.2 编写游戏逻辑代码 3…

Sangfor华东天勇战队:某咖啡还原密钥

最近学习了密钥还原&#xff0c;复现下并记录思路 function wbaes_encrypt_ecb(){var module_base Module.findBaseAddress("libcryptoDD.so")var func_base module_base.add(0x17BD41)Interceptor.attach(func_base,{onEnter:function (args){console.log("E…

风控引擎如何快速接入不同的数据源?

目录 数据是风控引擎的重要组成 风控引擎的数据接入 风控引擎是一种基于数据分析和机器学习算法的系统&#xff0c;能够实时识别和处理各种风险问题&#xff0c;适用于金融、电商、智能制造、交通运输等各领域&#xff0c;能够提高企业的风险管理水平和业务效率。 风控引擎主…

我心中的TOP1编程语言—JavaScript

作为一名研发工程师&#xff08;程序员&#xff09;&#xff0c;平时工作中肯定会接触或了解很多编程语言。每个人都会有自己工作中常用的语言&#xff0c;也会有偏爱的一些编程语言。而我心中的最爱&#xff0c;毫无疑问&#xff0c;就是 JavaScript。 JavaScript 是一门编程…

23. 数据结构之位图

前言 之前在讲散列表的时候&#xff0c;提到过位图的概念。位图&#xff08;Bitmap&#xff09;作为一种特殊的数据结构&#xff0c;它使用一系列位来表示数据&#xff0c;每个位只有两个状态&#xff08;0或1&#xff09;。由于它的高效性和节省空间的特性&#xff0c;位图在…