Go语言必知必会100问题-02 减少代码的嵌套层数
创始人
2025-05-31 00:38:23

减少代码的嵌套层数

软件开发中的“心智模型”用于描述开发人员在编码时心理活动,每段代码其实是人在编写这段代码时的心智模型投射,不能把代码看成是客观的存在,而是主观的产物,参合了当时心理活动或各种直觉感知。在编程时,必须不断维护心智模型,例如关于整体代码交互和功能实现的心智模型,代码是否具有可读性,代码风格,变量命名规范等。可读性强的代码需要的心智模型更简单,更容易阅读和维护。

代码嵌套层级的数量是影响可读性的一个关键因素,假设正在一个新项目上进行开发工作,并且需要读懂下面join函数实现的功能。此join函数实现的功能是将两个字符连接起来,如果连接起来的字符串超过给定的长度max,则返回前max个字符的子串。在处理的过程中,对参数进行检查并判断concatenate是否有返回错误。

func join(s1, s2 string, max int) (string, error) {if s1 == "" {return "", errors.New("s1 is empty")} else {if s2 == "" {return "", errors.New("s2 is empty")} else {concat, err := concatenate(s1, s2)if err != nil {return "", err} else {if len(concat) > max {return concat[:max], nil} else {return concat, nil}}}}
}func concatenate(s1 string, s2 string) (string, error) {// ...
}

从功能实现的角度来看,上述函数是正确的。然而,建立一个涵盖所有不同输入参数情况的心智模型可能不是一项简单的任务。为啥呢?由于代码嵌套的数量层级过多。现在,对上面的代码进行重构,得到新的实现如下。

func join(s1, s2 string, max int) (string, error) {if s1 == "" {return "", errors.New("s1 is empty")}if s2 == "" {return "", errors.New("s2 is empty")}concat, err := concatenate(s1, s2)if err != nil {return "", err}if len(concat) > max {return concat[:max], nil}return concat, nil
}func concatenate(s1 string, s2 string) (string, error) {// ...
}

对比这两种实现,虽然功能一样,但是阅读这个新版本的心智模型需要的认知负荷更少,因为新版实现中函数嵌套层级更少。正如Mat Ryer(Go Time播客小组成员)所说:

将正常情况逻辑(happy path)向左对齐,阅读时能够快速向下扫描一列可以查看预期的执行流程。

由于存在嵌套的if/else语句,很难看出重构前版本中的预期执行流程。相反,重构后的版本眼睛只需向下扫描一列便可知道预期的执行流程,通过第二列了解各种特殊情况的处理逻辑。

在这里插入图片描述

一般来说,函数需要的嵌套层数越多,阅读和理解就越复杂。下面来看看如何使用这条规则优化代码的可读性。

  • 当if语句在满足和不满足都有逻辑处理时,我们应该省略else语句块,不应该像下面这样写.
if foo() {// ...return true
} else {// ...
}

而应该像下面这样写,将else语句省略掉,并将else语句块中的逻辑移动到顶层,使其更易于阅读。

if foo() {return true
}
// ...
  • 对于像下面这种if语句是一条non-happy路径,可以通过改变比较条件来减少代码块数量。
if s != "" {// ...
} else {return errors.New("empty string")
}

上面s为空是一个non-happy路径,我们可以通过翻转条件,得到如下实现。下面这种实现就更容易阅读,因为它将快乐路径放在了左边并减少了代码块的数量。

if s == "" {return errors.New("empty string")
}
// ...

编写可读的代码对每个开发人员来说都是一项重要的挑战,努力减少代码块嵌套的层级数量,将快乐路径对齐放在左侧,并尽早返回是提高代码可读性的具体手段,在工作中,我们应该应用这些手段。

相关内容

热门资讯

Mysql常用数据类型总结 整形 枚举类型ENUE整形       TINYINT,SMALLINT,MEDIUMINT,IN...
【flink sql】创建表 flink sql创建表语法 CREATE TABLE [IF NOT EXISTS] [catal...
python opencv 保... 👨‍💻个人简介: 深度学习图像领域工作者 dz...
Pytorch深度学习实战3-... 目录1 数据集Dataset2 数据加载DataLoader3 常用预处理方法4 模型处理5 实例&...
自定义类型的超详细讲解ᵎᵎ了解...   目录 1.结构体的声明 1.1基础知识 1.2结构体的声明 1.3结构体的特殊声明  1.4结构...
Docker等容器技术如何与移... 移动应用程序的开发面临着很多挑战,包括开发环境的设置、测试的困难、部署的复杂性等。由于...
【微服务】—— Nacos安装... 文章目录1. Windows安装1.1 下载安装包1.2 解压1.3 端口配置1.4 启动1.5 访...
【OpenGL】 为了理解这个函数我们需要先学习一些OpenGL的内容 OpenGL可视化 https://g...
hjr-详细说一下Redis集... Redis作用 缓存 一般我们用Redis做缓存,热点数据 击穿:访问到...
【蓝桥杯】 C++ 数字三角形... 文章目录题目描述输入描述输出描述实现代码解题思路注意点知识点 题目描述 上图给出了一个数字三角形。从...
VR全景展会丨探索未来,重塑现... 随着科技的不断发展,虚拟现实(VR)技术逐渐成为一个重要的...
C++数据类型 目录 C++基础数据类型 指针 指针类型 指针赋值 引用 参考:《深...
超实用!!! 三分钟将你的项目... 文章目录前言一、在项目中新增配置二、配置github page setting?三、如...
数据结构---队列 专栏:数据结构 个人主页:HaiFan. 专栏简介:这里是...
数字操作方法 系列文章目录 前端系列文章——传送门 JavaScript系列文章——传送门 文章目录系列文章目录...
Cartesi 2023 年 ... 查看 Cartesi Machine、Cartesi Rollups 和 Noether 的更新正在...
JavaWeb——jsp概述入... JSP定义:  在如下一个jsp文件里面有如下的代码  <%@ page content...
一切喜怒哀乐都来自于你的认知 01 有个学子,准备出国,父母请来清华的教授宁向东。请问教授࿱...
JAVA并发编程——synch... 引言         Java语言为了解决并发编程中存在的原子性、可见性和有序性问题,...
git学习----3.21 未... 文章目录前言Git :一个分布式版本控制工具目标一、概述1.1 开发中的实际场景1.2...
Qt优秀开源项目之十七:QtP... QtPromise是Promises/A+规范的Qt/C++实现。该规范的译...
【前端八股文】JavaScri... 文章目录Set概念与arr的比较属性和方法并集、交集、差集Map概念属性和方法String用索引值和...
海康硬盘录像机接入RTSP/o... EasyNVR安防视频云服务平台可支持设备通过RTSP/Onvif协议接入平台,能提供...
在混合劳动力时代如何避免网络安... 在混合劳动力时代如何避免安全网络风险 三年多来,混合工作一直是工作生活中不可或缺的一...
2023还不懂Jmeter接口... 这里介绍的Jmeter接口测试的的实战,如果文章内容没遇看懂的话,我这边...
基于4G/5G弱网聚合的多链路... 基于4G/5G多卡聚合(弱网聚合)的智能融合通信设备技术亮点 增强带宽提供可靠连接 通过将多个有线和...
如何使用Synplify综合v... 文章目录使用Synplify综合的好处synplify的教程方法1(无效)...
2023年全国最新高校辅导员精... 百分百题库提供高校辅导员考试试题、辅导员考试预测题、高校辅导员考试真题、辅导员证考试题库等ÿ...
2022年18个值得期待的Le... 有数百个独特的LearnDash附加组件,您可能很难选择您的LearnDash LMS...
【java基础】Stream流... 文章目录基本介绍流的创建流的各种常见操作forEach方法filter方法map方法peek方法fl...