>백엔드 개발 >Golang >Go 코딩 표준 세트를 공유하세요! 수집에 오신 것을 환영합니다!

Go 코딩 표준 세트를 공유하세요! 수집에 오신 것을 환영합니다!

藏色散人
藏色散人앞으로
2022-12-09 17:08:425650검색

최근 프로젝트에서 Go 언어 코드를 많이 검토했는데, 노트 기록이라고 할 수 있는 코드 사양을 요약할 필요가 있습니다.

앞서 언급했듯이 이는 우리 팀의 규범일 뿐입니다.

오늘 우리는 Go의 코딩 표준에 대해 이야기합니다. 이는 패키지 노트/변수/상수 이름 지정, 기본 구문, 함수, 오류 처리, 경험 등과 같은 여러 주요 모듈로 대략 구분됩니다. [추천: golang 튜토리얼]

1. 코드 스타일

1.1 코드 형식

  • 코드 형식은 gofmt로 구성해야 합니다. 구성은 직접 검색할 수 있습니다.
  • 우리가 작성하는 코드는 다음과 같습니다. 한 줄에 120자를 초과할 수 없으며, 초과하는 내용은 줄 바꿈으로 해결됩니다.
  • 한 파일의 최대 줄 수는 800줄을 초과할 수 없습니다.
  • 한 기능의 최대 줄 수는 80줄을 초과할 수 없습니다.
  • 가져오기 사양
    • 패키지를 소개하는 데 상대 경로를 사용하지 마세요. 예를 들어import ../util/net
    • 패키지를 가져올 때 여러 개의 동일한 패키지 이름이 충돌하는 경우 가져오기 별칭을 사용해야 합니다.
// bad
"github.com/google/uuid"

// good
uuid "github.com/google/uuid"
  • 가져온 패키지는 다음을 사용하는 것이 좋습니다. 그룹화 및 참조 익명 패키지 나중에 친구들이 쉽게 읽을 수 있도록 새 그룹을 사용하고 주석을 추가하는 것이 좋습니다
import (
    // Go 标准库
    "fmt"

    //第三方包
    "github.com/jinzhu/gorm"
    "github.com/google/uuid"
    "github.com/go-redis/redis/v8"

    // 匿名包
    /import mysql driver
    _"github.com/jinzhu/gorm/dialects/mysql"

    // 内部包
    slice "xxx.local/pkg/v1/goslice"
    meta "xxx.local/pkg/v1/meta"
    gomap "xxx.local/pkg/v2/gomap")

1.2 선언, 초기화 및 정의

  • 함수가 여러 변수를 사용해야 하는 경우 var 선언을 사용할 수 있습니다. 함수 시작 부분에. 함수 외부에 선언된 변수는 사용할 수 없습니다:=, 이는 함정으로 이어질 수 있습니다. 모르는 경우 주석 영역에 메시지를 남겨도 됩니다(주석 작성이 쉽지 않습니다)!
var (
    port = 8081
    metricServerPort = 2001)
  • 구조체 초기화 시 new(struct) 대신 &struct를 사용하여 구조 초기화와 일치하는지 확인하고, 구조 초기화 시 줄을 바꿉니다.
// bad
stu := new(S)
stu.Name = "张三"

// good
stu := &S{
    Name:"李四"
}
  • 콘텐츠를 미리 할당할 수 있도록 맵, 배열 등을 선언할 때 make를 사용하여 컨테이너의 용량을 지정하세요.
users := make(map[int]string, 10)tags := make([]int, 0, 10)
  • 표준 var 키워드를 사용하고 표현식의 유형과 다르지 않는 한 유형을 지정하지 마세요.
// bad
var _f string F()

func F() string {
    return "hello world!"
}

// good 
var _f F()

func F() string {
    return "hello world!"
}

1.3 오류 처리

  • 함수가 오류를 반환하면 해당 오류를 처리해야 합니다. 비즈니스에서 허용하는 경우 _를 사용하여 이를 수락하고 무시할 수 있습니다. 해당 지연은 명시적 처리 없이 처리될 수 있습니다.
// bad
func InitConfig() error {
    ...
}
InitConfig()


// good
func InitConfig() error {
    ...
}
err := InitConfig()
if err != nil {
    ...
}
// or 
_ := InitConfig()
  • error는 반환값으로 사용될 때 마지막 매개변수로 반환되어야 합니다.
// bad
func InitConfig() (error,int) {
    ...
}

// good 
func InitConfig() (int, error) {
    ...
}
  • Error는 별도로 처리해야 하며 다른 로직과 결합되지 않도록 노력해야 합니다.
// bad
res, err := InitConfig()
if err != nil || res != nil {
    return err
}

// good
res, err := InitConfig()
if err != nil {
    return err
}
if res != nil {
    return fmt.Errorf("invalid result")
}

1.4 패닉 처리

  • 비즈니스 코드에서 패닉 오류를 발생시키는 것은 금지되어 있습니다.
  • 패닉은 구성 읽기, 링크 저장(redis, mysql 등) 등 서비스가 시작되기 전에만 표시되도록 허용됩니다.
  • 비즈니스 코드에서는 패닉 대신 에러를 사용하는 것이 좋습니다.

1.5 단위 테스트

  • 중요 기능별로 테스트 케이스를 작성해야 하며, 코드 병합 시 모든 테스트가 자동으로 실행되어야 합니다.
  • 파일 이름은 xxx_test.go입니다.
  • 함수 이름을 지을 때 테스트 함수 이름을 사용하는 것이 좋습니다.

2. 명명 규칙

모든 언어에서 명명 규칙은 코드 사양에서 매우 중요합니다. 통일되고 정확한 명명은 코드의 가독성을 향상시킬 뿐만 아니라 사람들이 이 동지가 실제로 방법을 알고 있다는 느낌을 갖게 합니다. 그것을하기 위해. 황소!

2.1 包命名规范

  • 包名必须与目录名一致(这和其他 php、Java 还是有一点不太一样的),尽量采取有意义、简短的包名,不要与 go 的标准库名称一样。
  • 包名小写,没有下划线,可以使用中划线隔开,使用多级目录来划分目录。
  • 包名不要出现复数命名。
  • 包名命名尽量简单一目了然,ge:user、log。

2.2 文件命名规范

  • 文件名要见名思义,尽量简而短
  • 文件名小写,组合词用下划线分割

2.3 函数命名规范

  • 与 php、Java 一样,必须遵循驼峰规范,Go 语言中需要根据访问的控制决定大驼峰还是小驼峰。
  • 单元测试的函数用大驼峰,TestFunc。

2.4 结构体命名规范

  • 与 php、Java 一样,必须遵循驼峰规范,Go 语言中需要根据访问的控制决定大驼峰还是小驼峰。
  • 避免使用 info 、data 这种无意义的名称。
  • 命名使用名词而非动词。
  • 结构体在声明和初始化的时候需要换行,eg:
type Student struct{
    Name string
    Age uint8}student := Student{
    Name: "张三",
    Age: 18,}

2.5 变量命名规范

  • 和 php、Java 一样,必须遵循驼峰规范,Go 语言中需要根据访问的控制决定大驼峰还是小驼峰。
  • 若变量为私有时,可以使用小写命名。
  • 局部变量可以简写,eg:i 表示 index。
  • 若变量代表 bool 值,则可以使用 Is 、Can、Has 前缀命名,eg:
var isExit boolvar canReturn bool

2.6 常量命名规范

  • 必须遵循驼峰规范,Go 语言中需要根据访问的控制决定大驼峰还是小驼峰。
  • 若代表枚举值,需要先创建。
type Code intconst (
    ErrNotFound Code = iota
    ErrFatal)

3. 类型

3.1 字符串

好像学过的语言中,都是从字符串开始说起的。就像写代码第一行都是从 Hello World!一样!同意的点赞哈。

  • 字符串判空值
// bad
if s == "" {
    ...}
 // good
 if len(s) == 0 {
    ...}
  • 字符串去除前后子串。
// bad
var s1 "hello world"var s2 "hello"var s3 strings.TrimPrefix(s1, s2)
// good
var s1 "hello world"var s2 "hello"var s3 stringif strings.HasPrefix(s1, s2){
    s3 = s1[len(s2):]}

3.2 切片 slice

  • 声明 slice。
// bad
s := []string{}s := make([]string, 10)
// good
var s []string
s := make([]string, 0, 10)
  • 非空判断。
//bad
if len(slice) >0 {
    ...}
 // good
 if slice != nil && len(slice) > 0 {
    ...}
  • slice copy。
// badvar b1,b2 []bytefor i, v := range b1 {
    b2[i] = v}for i := range b1 {
    b2[i] = b1[i]}// goodcopy(b2,b1)
  • slice 新增。
// bad
var a,b []intfor _, v := range a {
    b = append(b,v)}
// good
var a, b []int
b := append(b, a...)

3.4 结构体 struct

  • 初始化需要多行。
type Student struct{
    Name string
    Age uint8}student := Student{
    Name: "张三",
    Age: 18,}

4. 控制语句

4.1 if

  • if 可以用局部变量的方式初始化。
if err := InitConfig; err != nil {
    return err}

4.2 for

  • 不允许在 for 中使用 defer, defer 只在函数结束时才会执行。
// bad
for file := range files {
    fd, err := os.Open(file)
    if err != nil {
        return err    }
    defer fd.close()}
// good
    for file := range files{
    func() {
        fd,err := os.open(file)
        if err!=nil {
            return err        }
        defer fd.close()
    }()}

4.3 range

  • 如果不需要 key 直接用 _ 忽略,value 也一样。
for _, v := range students {
    ...}for i, _ := range students {
    ...}for i, v := range students {
    ...}

注: 若操作指针时请注意不能直接用 s := v。想知道可以评论区告诉我哦!

4.4 switch

  • 和其他语言不一样,必须要有 defalt
switch type {
    case 1:
        fmt.Println("type = 1")
        break
     case 2:
        fmt.Println("type = 2")
        break
     default :
        fmt.Println("unKnown type")}

4.5 goto

  • 业务中不允许使用 goto。
  • 框架和公共工具也不允许使用 goto。

5. 函数

  • 传参和返回的变量小写字母。
  • 传入参数时slice、map、interface、chan 禁止传递指针类型。
  • 采用值传递,不用指针传值。
  • 入参个数不能超出 5 个,超过的可以用 struct 传值。

5.1 函数参数

  • 返回值超出 1 个时,需要用变量名返回。
  • 多个返回值可以用 struct 传。

5.2 defer

  • 当操作资源、或者事物需要提交回滚时,可以在创建开始下方就使用 defer 释放资源。
  • 创建资源后判断 error,非 error 情况后在用 defer 释放。

5.3 代码嵌套

  • 为了代码可读性,为了世界和平,尽量别用太多的嵌套,因为真的很难有人类能看懂。

6. 日常使用感悟

  • 能不用全局变量就不用,可以用参数传值的方式,这样可以大大降低耦合,更有利于单元测试。
  • 衣服开发中,在函数间多用 context 传递上下文,在请求开始时可以生成一个 request_id,便于链路、日志追踪。

6.1 提高性能

  • 在业务开发中,尽量使用 strconv 来替代 fmt。
  • 我们在使用 string 字符串类型时,当修改的场景较多,尽量在使用时用 []byte 来替代。因为每次对 string 的修改都需要重新在申请内存。

6.2 避免踩坑

  • append 要小心自动扩容的情况,最好在申明时分配好容量,避免扩容所带来的性能上的损耗以及分配新的内存地址。若不能确定容量,应选择一个比较大一点的值。
  • 并发场景下,map 非线程安全,需要加锁。还有一种评论区告诉我吧。
  • interface 在编译期间无法被检查,使用上会出现 panic,需要注意

7. 总结

本篇很讲了 Go 语言的编码规范,当时想说的,规范是大家预定的东西,每个公司、团队都会有不一样的规范,只要大家一起遵循就好啦。你可以根据自己团队的需求,定一套属于自己团队的项目规范。如果想小伙伴一起遵循,可以借助一些工具来保障执行度。

讲了很多,虽然很基础,希望对于刚刚转 Go 语言,或者刚学习 Go 语言的同学有帮助吧。今天就到这里了。希望得到大家的一键三连。感谢!

本文系转载,原文链接:mp.weixin.qq.com/s/lfjP9DEia2WL4Ua...

위 내용은 Go 코딩 표준 세트를 공유하세요! 수집에 오신 것을 환영합니다!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 learnku.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제