如何提高golang的可读性

栏目: 编程语言 · Clojure · 发布时间: 5年前

内容简介:反例:从这个例子来看,在service层和数据库查询,我们都进行了userId的判断. 因为当我们经常会忘记,我们是否在上一层入参的时候进行了userId为空的判断. 为了避免空指针,我们不得已一层层进行判断.假如我们尽早地返回,那么就可以避免后续的层层判空

1. 尽早返回

反例:

//UserCtrl
func UserInfo(userId string){
  user.UserInfo(userId)
  ....
  ....
  //resp result ...
}

//UserService
func UserInfo(userId string){
  if len(userId) > 0 { 
    //do query database 
    .....
  } 
}
// repo
func queryUserInfo(userId string){
  if len(userId) > 0{
    //select * from user where user_id = ?
  }
}

从这个例子来看,在service层和数据库查询,我们都进行了userId的判断. 因为当我们经常会忘记,我们是否在上一层入参的时候进行了userId为空的判断. 为了避免空指针,我们不得已一层层进行判断.

假如我们尽早地返回,那么就可以避免后续的层层判空

推荐写法:

//userCtrl
func UserInfo(userId string){
  if len(userId) == 0 {
    //resp some error
  }
  user.UserInfo(userId)
}

2. 写好分支语句

反例:

func xxx(lang string){
  if lang == "java"{
    doA()
  } else {
    doB()
  }
  
  if lang == "java"{
    doC()
  }else{
    doD()
  }
}

推荐写法:

func java(lang string){
  doA()
  doC()
}

func other(lang string){
  doB()
  doC()
}

if都需要包含else

反例:

if cmd == "1" {
  if status == 0 {
    doSome()
  }
}else {
  if tag == 1 {
    doSomeB()
  }
}

推荐写法:

if cmd == "1" {
  if status == 0 {
    
  }else{
    
  }
}else {
  if tag == 1{
    
  }else {
    
  }
}

避免啰嗦的条件

if isDone() == true {
  do()
}

推荐:

if isDone() {
  doSome()
}

使用switch语句

反例:

if lang == "java"{
  
}else if lang == "c#" {
  
}else if lang == "clojure"{
  
}

推荐写法:

switch lang:
case "java":
case "c#":
case "clojure":

减少逻辑表达式:

逻辑表达式是门电路的表达式,总会有人不能记得他的先后执行顺序。

反例:

if lang == "java" || lang == "c#" && lang == "clojure" {
  doSome()
}

如果非得使用逻辑表达式,推荐使用括号,显示地说明调用的顺序.

if (lang == "java" || lang == "c#") && lang == "clojure" {
  doSome()
}

使用正序的逻辑

反例:

if !isUserInfoSaved() {
  doA()
}else {
  doB()
}

if !isNotStop() {
  doSome()
}

用一个符合人类思考顺序方式来写分支,减少阅读代码时的时间

if isUserInfoSaved() {
  doB()
}else {
  doA()
}

if isStart(){
  doSome()
}

3.合理使用局部变量

可能我们知道定义一个变量会开辟一块新的内存,有时候觉得自己重复使用一个变量,会让性能"好一些", 于是我们就会写出下面的代码

反例:

var name
if login {
  name = "user"
  doSome(name)
}else {
  name = "guest"
  doSome(name)
}

其实在栈上开辟内存的成本很低,编译器会对代码进行逃逸分析,而且执行完这个方法后,内存就会被回收掉,所以不用担心这个性能问题.

推荐写法:

if login {
    //使用局部变量
  name := "user"
  doSome(name)
}else {
  name := "guest"
  doSome(name)
}

有的时候我们会想耍个酷,那么牛逼的调用一行代码就写完了,可是这时候阅读起来是非常痛苦的一件事情.

反例:

saveXXX(queryRole(),queryOrder(),saveXXX(queryUserInfo(genUserId())))

推荐写法:

我们把参数通过一个中间变量存起来,这样会很明显地说明,我们都干了些什么.

userInfo := queryUserInfo(genUserId)
u := saveXXX(userInfo)
saveXXX(queryRole(),queryOrder(),u)

4.循环

循环本身就不好读,假如在循环中包含continue,break之类的,让原本的代码更难读

反例:

for i,itm := range Users {
  if item.Name != "admin" {
    continue
  }else {
    doSome()
  }
}

推荐写法:

for i,itm := range Users {
  if item.Name == "admin" {
    doSome()
  }
}

使用i,j之类的下标,本身就比较相似,一不小心就会造成了下标越界,推荐使用foreach

反例:

for i:=0 ; i< len(users); i++ {
   for j:=0 ; j < len(users[i].children); j++ {
     // doSome
   }
}

推荐写法

for _,itm := range users {
  for _, c := range item{
    //dosome
  }
}

假如非得使用下标操作,也要避免使用i,j之类的变量

for uidx :=0 ; uidx< len(users); uidx++ {
   childen := users[uidx].children  //使用中间变量,避免臃肿
   for chidx:=0 ; chidx < len(childen); chidx++ {
       // chidx 和 uidx 能避免混淆,能在使用的过程中避免出错。
   }
}

5.面条代码, 过程式代码

面条代码过程式代码

type UserInf struct {
  UserName   string
  UserId     string
  Role       *Role
  Alias     string
}

type Role struct {
  Id string
  Name string
}

func save(inf *UserInf){
  Role(inf)
  inf.Alias = genAlias()
  update(inf)
}

func update(inf *UserInf){
  //update ....
}

func Role(inf *UserInfo) {
  queryUser(inf)
  inf.Role = queryRole(inf.UserId)
}

func queryUser(inf *UserInf){
  //select * from user where user_id = ?
  inf.UserName = ...
  inf.xxx = ...
}

思考: 为什么要使用纯函数?

6. 控制代码的长度

人的左脑关心的是逻辑,右脑做的是快照(可能是伪科学),实际情况中,假如我们一眼能看完,是不是剩下的就是在想逻辑,而不是一边读代码,一边想逻辑,这样能让我们大脑一次性把看到的代码缓存起来,然后专注于想逻辑。简短的代码,也可以避免bug,所以方法建议都控制在100行之内。

7. 命名

这个放最后来写的原因是这个命名本来就很难,命名得好就会让代码清晰可读,命名不好,就会误导导致需要大量的注视来注释代码,本来维护代码已经是一件痛苦的事情了,假如在修改了代码后,注释没有同步修改,反而会引起误导。因为母语不是英文,很多同学跟我一样也都很痛苦,这里可以上网找找相关命名的资料,本人水平有限也只能是大概地举几个例子

bool isStart // 服务启动的状态,最好使用正向的表达,是否启动,不推荐使用  bool isNotStop
func ComputeUserScore() //计算用户积分,假如这是一个耗时的操作,推荐在方法名上就表示出来,不推荐使用GetUserScore,
func DownloadFile() //下载文件,不推荐使用GetFile

个人博客 https://youkale.github.io


以上所述就是小编给大家介绍的《如何提高golang的可读性》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

图解网络硬件

图解网络硬件

[日] 三轮贤一 / 盛荣 / 人民邮电出版社 / 2014-7 / 69.00元

本书详细介绍了计算机网络硬件的相关知识,在对硬件设备、相关技术及规范进行详尽考据和整理的同时,侧重工程实践,重点讲述了在实际网络建设工程中真实使用的网络硬件设备及其相关背景知识,能够帮助读者深入理解计算机网络在工程实践中某些容易混淆的概念,如L3交换机和路由器等。 本书在讲解的同时,还辅以丰富的图例,使计算机网络设备的真实情况一目了然,同时深入浅出地介绍了原本复杂抽象的计算机网络术语,因此对......一起来看看 《图解网络硬件》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具