7

Golang 代码编写中的技巧

 3 years ago
source link: https://hedzr.com/develop/tricks/go-tricks-2/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

此前有一篇 Golang开发环境中的技巧,偏向于 go tools 等等的记录,今后还会继续收录,因为那些碎片记忆起来有负担,不如收归一个确定的地点,省得寻找不易。

但今天这篇虽然 link 差别不大,关注的重点却不在于 go tools 方面或者 ide 方向,而是纯粹的代码编写上的技巧。

我认为是的,你随意就好。

In CodingPermalink

函数调用时,不要 inline 另一个调用Permalink

在业务逻辑编码过程中,避免使用嵌套连环函数调用。

也就是说,下面这样的代码不是好的:

if err = user.Verify(formUserID(), formUsername(), formPassword()); err != nil {
  // ...
}

怎么才是好的?将函数调用分离开,每个函数调用的参数都是简单的,可就地计算的,如同这样:

uid, usr, pwd := formUserID(), formUsername(), formPassword()
if err = user.Verify(uid, usr, pwd); err != nil {
  // ...
}

因为这样改写之后,我们可以在 line 2 打上断点,而且很容易了解 usr 值,然后很容易就地单步进入到 Verify 函数体之中。

而采用前一写法时,在 line 1 上断点,不但不能知道 usr 和 pwd 究竟是什么值,而且单步之后也不知道飞到哪儿去了,完全无法直接进入到 Verify 函数体中。

有做过单步跟踪的,自然而然就会理解到我所说的意思。

error 检测语句的优化Permalink

我没有打算提供另一个 checkerr(err) 函数写法。

实际上,我曾经在以前( Golang Testing 概览 - 基本篇 )提到过,很多很多 err != nil 语句可以改写为:

func A(filePath string) (err error) {
  var f *os.File
  if f, err = os.Open(filePath); err == nil {
    // open ok
    if f.IsRegular() {
      // go further ...
      return callForF(f)
    }
  }
  //
  return // has error
}

也即改写为深入嵌套的 err == nil 测试,在嵌套 if 的中央,用一个子函数调用(例如 callForF(f) )逃出。

这样做的用意在于:

  1. 约束函数代码到仅有两个出口点,这将会非常有利于调试(容易做断点,但难以确定错误退出的分支——除非参考 err 的具体值来判断原因)
  2. 比较容易做 coverage,很容易就能覆盖掉这个函数的一切分支

当然我已经提到过了,请勿滥用,因为它并不总是最佳选择。

错误容器Permalink

此外,在 Golang errors 编程模型 - Part II - 错误容器 中,我也提到过 error container 的概念。借助于 hedzr/errors.v2 可以不断地将若干 error 缓存到一个 container 中,然后收束为一个单一的 error 对象向上层返回。这个单一个 error 对象将会罗列出全部发生过的 errors。

最简短的示意性代码片段为:

import "gopkg.in/hedzr/errors.v2"

func checker() (err error) {
  var ec = errors.NewContainer("Checking for users ...\n")
  for _, u := range listAllUsers() {
    ec.Attach(checkUserIntegrities())
  }
  return ec.Error()
}


func checkUserIntegrities(u *User) (err error) {
  if ... {
    err = errors.New("forbidden")
  }
  return
}

在 line 5 你可以看见,我们不停地向容器 ec 中添加(Attach)错误对象,如果 checkUserIntegrities 返回的是没有错误(err == nil)也没有关系,因为 nil 会被 Attach 所忽略。所以我们现在的到了一个最简练的错误容器及其追加方法,而且使用起来也非常容易。

而且,收束的动作也很轻巧:用 ec.Error() 就可以获得一个 error 对象,它收容了曾经在 checkUserIntegrities 中检测到的所有 errors。

小结Permalink

这种收集,也只能慢慢来了。没有太多心情系统地整理,也没有这样的时间块。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK