这是Go常见错误系列的第12篇:Go语言中冗余的嵌套代码,俗称箭头型代码。
素材来源于Go布道者,现Docker公司资深工程师Teiva Harsanyi。
本文涉及的源代码全部开源在:Go常见错误源代码,欢迎大家关注公众号,及时获取本系列最新更新。
我们先看看如下的代码:
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) {
// ...
}
这段代码要做的事情很简单:
- 把两个字符串s1和s2拼接起来,如果长度超过max,就只返回长度为max的子串。
- 实现过程中,对s1和s2做了判空;对concatenate返回值有无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) {
// ...
}
这段代码实现了和刚才完全一样的功能,但是可读性好很多。
那有什么最佳实践我们可以作为参考,来规范代码实现呢?
通常来说,函数里的代码嵌套的层次越多,可读性就越差。可以参考如下原则来规范代码编写:
-
当if语句里会return时,那不要继续用else了,直接把else里的内容和if放在同一个层次。
bad case:
if foo() { // ... return true } else { // ... }
good case:
if foo() { // ... return true } // ...
-
如果修改判断条件,可以减少嵌套层次,可以考虑对判断条件做调整。示例如下:
bad case:
if s != "" { // ... } else { return errors.New("empty string") }
good case:
if s == "" { return errors.New("empty string") } // ...
-
归纳上面2个原则,其实就是能先return的就先return,减少不必要的代码嵌套。
感兴趣的也可以看看参考资料里"左耳朵耗子"写过的一篇文章"如何重构箭头型代码",
下一篇文章,我们会讲解下Go语言里init函数的常见错误和最佳实践。
文章和示例代码开源在GitHub: Go语言初级、中级和高级教程。
公众号:coding进阶。关注公众号可以获取最新Go面试题和技术栈。
个人网站:Jincheng's Blog。
知乎:无忌。
我为大家整理了一份后端开发学习资料礼包,包含编程语言入门到进阶知识(Go、C++、Python)、后端开发技术栈、面试题等。
关注公众号「coding进阶」,发送消息 backend 领取资料礼包,这份资料会不定期更新,加入我觉得有价值的资料。
发送消息「进群」,和同行一起交流学习,答疑解惑。