• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

如何快速写出高质量的 Go 代码?

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

前言

团队协作开发中,必然存在着不同的代码风格,并且诸如 http body closeunhandled error 等低级错误不能完全避免。通过使用 ci lint 能够及早的发现并修复问题,提高代码质量和幸福感。

目前主流的工具是 golangci-lint,里面集成了许多的 linters,安装及使用看官网文档即可,非常详细易读,本文主要是配合一些样例代码来分析一下相关 linters 的功能。

linters

deadcode

检查未使用的代码

var a = 100

func foo() {
	println("hello,world")
}
main.go:3:5: `a` is unused (deadcode)
var a = 100
    ^
main.go:5:6: `foo` is unused (deadcode)
func foo() {
     ^

类似的工具还有 structcheckvarcheck

errcheck

检查未处理的错误

由于 Go 语言的错误处理机制,导致代码中遍地的 if err != nil ,因此有不耐烦的同学,在某些自认为不会出错的地方直接不处理,比如 json.Marshal(),虽然多数情况下没啥问题,不过一但出了问题加班啥的估计跑不了。

可以通过修改配置文件来定制不同情况是否报告

linters-settings:
  errcheck:
    # 检查类型断言
    check-type-assertions: true
    # 检查使用 _ 来处理错误
    check-blank: true
func main() {
	foo()

	var i interface{} = 1
	ii := i.(int)
	fmt.Println(ii)

	num, _ := strconv.Atoi("110")
	fmt.Println(num)
}

func foo() error {
	return errors.New("i am error")
}
$ golangci-lint run
main.go:10:5: Error return value is not checked (errcheck)
        foo()
           ^
main.go:13:8: Error return value is not checked (errcheck)
        ii := i.(int)
              ^
main.go:16:7: Error return value of `strconv.Atoi` is not checked (errcheck)
        num, _ := strconv.Atoi("110")
             ^

gosimple

简化代码

func main() {
	t := time.Now()
	fmt.Println(time.Now().Sub(t))
}
$ golangci-lint run
main.go:10:14: S1012: should use `time.Since` instead of `time.Now().Sub` (gosimple)
        fmt.Println(time.Now().Sub(t))
                    ^

原始仓库中还有许多别的测试用例,感兴趣的同学可以看看,可以修改配置文件来指定生效的规则,默认是 all。

govet

go vet 是官方提供的工具,可以检查出许多问题,如 printf 参数不匹配、unmarshall 时未传递指针或者接口、循环变量捕获问题等。

type AAA struct {
	A int `json:"a"`
}

func main() {
	fmt.Printf("%s", true)

	var a AAA
	if err := json.Unmarshal([]byte(`{"a":1}`), a); err != nil {
		panic(err)
	}

	var s []int
	for i, v := range s {
		go func() {
			fmt.Println(i)
			fmt.Println(v)
		}()
	}
}
$ golangci-lint run
main.go:23:16: loopclosure: loop variable i captured by func literal (govet)
                        fmt.Println(i)
                                    ^
main.go:24:16: loopclosure: loop variable v captured by func literal (govet)
                        fmt.Println(v)
                                    ^
main.go:13:2: printf: fmt.Printf format %s has arg true of wrong type bool (govet)
        fmt.Printf("%s", true)
        ^
main.go:16:26: unmarshal: call of Unmarshal passes non-pointer as second argument (govet)
        if err := json.Unmarshal([]byte(`{"a":1}`), a); err != nil {
                                ^

ineffassign

检查无效的赋值,即变量赋值后并未使用

func main() {
	a := os.Getenv("a")
	if a == "" {
		a = "unknown"
	}
}
$ golangci-lint run
main.go:8:3: ineffectual assignment to a (ineffassign)
                a = "unknown"
                ^

本以为这种情况应该不多,但是测试了一下我们组内的某个项目,发现还不少


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
蓝蝴蝶之吻loading..(3) - I Should Go发布时间:2022-07-10
下一篇:
go的常见操作发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap