{"id":17330394,"url":"https://github.com/voidint/go-style-guide","last_synced_at":"2025-04-14T17:53:27.973Z","repository":{"id":90859678,"uuid":"104226008","full_name":"voidint/go-style-guide","owner":"voidint","description":"go style guide","archived":false,"fork":false,"pushed_at":"2019-05-26T05:43:33.000Z","size":15,"stargazers_count":6,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-28T06:23:26.718Z","etag":null,"topics":["go","guide","style"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/voidint.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-09-20T14:26:19.000Z","updated_at":"2022-01-08T23:43:09.000Z","dependencies_parsed_at":"2023-03-03T20:17:50.849Z","dependency_job_id":null,"html_url":"https://github.com/voidint/go-style-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidint%2Fgo-style-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidint%2Fgo-style-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidint%2Fgo-style-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidint%2Fgo-style-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/voidint","download_url":"https://codeload.github.com/voidint/go-style-guide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248931680,"owners_count":21185225,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","guide","style"],"created_at":"2024-10-15T14:51:07.958Z","updated_at":"2025-04-14T17:53:27.939Z","avatar_url":"https://github.com/voidint.png","language":null,"readme":"# Go代码规范(beta)\n## 目录\n- [前提](#前提)\n- [代码规范](#代码规范)\n\t- [import](#import)\n\t- [return](#return)\n\t- [不建议使用uint](#不建议使用uint)\n\t- [变量声明](#变量声明)\n\t- [变量导出](#变量导出)\n\t- [变量命名](#变量命名)\n\t- [package命名](#package命名)\n\t- [interface命名](#interface命名)\n\t- [源代码文件命名](#源代码文件命名)\n\t- [error处理](#error处理)\n\t- [error文本内容](#error文本内容)\n\t- [panic与error](#panic与error)\n\t- [字符串拼接](#字符串拼接)\n\t- [receiver类型](#receiver类型)\n\t- [控制结构](#控制结构)\n- [参考](#参考)\n\n## 前提\n- 代码经由[gofmt](https://github.com/golang/go/tree/master/src/cmd/gofmt)或[goimports](https://github.com/golang/tools/tree/master/cmd/goimports)工具格式化\n- 代码已通过[go tool vet](https://golang.org/cmd/vet/)、[golint](https://github.com/golang/lint)、[gometalinter](https://github.com/alecthomas/gometalinter)等工具的检查\n\n## 代码规范\n### import\n不要使用相对路径，使用绝对路径。\n##### Don't\n``` go\nimport ../config\n```\n##### Do\n``` go\nimport github.com/voidint/gbb/config\n```\n\n### return\n##### Don't\n``` go\nfunc run() (n int, err error) {\n\t// ...\n\treturn\n}\n```\n\n##### Do\n``` go\nfunc run() (n int, err error) {\n\t// ...\n\treturn n, err\n}\n```\n\n### 不建议使用uint\n需要使用整形数据类型情况下，多数都可以直接使用`int`，而不建议使用`uint`。标准库及其他第三方的类库，在类似的使用场景下多使用`int`。那么，此种`随大流`可以免去不必要的数据类型转换。\n\n##### Do\n``` go\ntype Person struct{\n\tAge int\n}\n```\n\n##### Don't\n``` go\ntype Person struct{\n\tAge uint\n}\n```\n\n### 变量声明\n空slice的声明\n##### Don't\n``` go\ns := []string{} // 声明并初始化变量\n```\n##### Do\n``` go\nvar s []string // 声明\n```\n\n函数内的变量声明，推荐使用`:=`的简短赋值语句。\n##### Don't\n``` go\nfunc saySomething() {\n\tvar msg = getMsg()\n\tfmt.Println(msg)\n}\n```\n##### Do\n``` go\n\nfunc saySomething() {\n\tmsg := getMsg()\n\tfmt.Println(msg)\n}\n```\n\n\n### 变量导出\n函数、方法、结构体、结构体属性等导出与否，由使用场景决定，但秉承着`权限最小化`的原则，能不导出就不要导出。\n\n##### Don't\n``` go\ntype Student struct{\n\tName string\n}\n\nstu := Student{\n\tName: \"voidint\",\n}\n\nfunc main(){\n\tfmt.Printf(\"student name: %s\\n\", stu.Name)\n}\n```\n\n##### Do\n``` go\ntype Student struct{\n\tname string\n}\n\nfunc NewStudent(name string) *Student{\n\treturn \u0026Student{name: name}\n}\n\nfunc (stu Student) Name() string{\n\treturn stu.name\n}\n\nfunc main(){\n\tfmt.Printf(\"student name: %s\\n\", NewStudent(\"voidint\").Name())\n}\n```\n\n### 变量命名\n使用`驼峰式`的变量命名方式。\n##### Don't\n``` go\nvar\tstudent_name string\nconst LOG_LEVEL = \"info\"\n```\n\n##### Do\n``` go\nvar\tstudentName string\nconst LogLevel = \"info\"\n```\n\n专有名词的缩写应保持字母大小写一致。具体是全部大写还是全部小写，应由实际使用场景决定。若变量可以不导出，那就全部小写，反之全部大写。\n##### Don't\n``` go\nvar (\n\tCpu string \n\tId int\n)\n```\n\n##### Do\n``` go\nvar (\n\tCPU string \n\tid int\n)\n```\n\n形参变量和函数返回值变量一律小写字母开头。\n##### Don't\n``` go\nfunc add(X, Y int) (Z int) {\n\treturn X + Y\n}\n```\n\n##### Do\n``` go\nfunc add(x, y int) (z int) {\n\treturn x + y\n}\n```\n\n为函数的多个返回值命名。在`godoc`生成的文档中，带有返回值的函数声明更利于理解。\n##### Don't\n``` go\nfunc SplitHostPort(hostport string) (string, string, error){\n...\n}\n```\n\n##### Do\n``` go\nfunc SplitHostPort(hostport string) (host, port string, err error){\n...\n}\n```\n\n**建议：每当变量命名不知所措时，使用[codelf](http://unbug.github.io/codelf/)看看世界上其他程序员的命名。**\n\n### package命名\n包名由小写字母组成，不要使用下划线或者混合大小写。\n##### Don't\n``` go\npackage busyBox\n```\n\n##### Do\n``` go\npackage busybox\n```\n\n包名不要使用复数\n##### Don't\n``` go\npackage utils\n```\n\n##### Do\n``` go\npackage util\n```\n\n\n所有对包内的引用都应该使用包名去访问，因此包内的名称引用可以去掉包名这个标识。\n##### Don't\n``` go\npackage chubby\n\ntype ChubbyFile struct{\n}\n```\n\n##### Do\n``` go\npackage chubby\n\ntype File struct{\n}\n```\n\n### interface命名\n理想情况下，接口命名以`er`结尾。\n##### Don't\n``` go\ntype IRead interface{\n}\n```\n\n##### Do\n``` go\ntype Reader interface{\n}\n```\n\n\n### 源代码文件命名\n遵循简洁的原则，对于包内的源代码文件命名，一般情况下无需再携带包信息。\n##### Don't\n``` go\n// service/network_service.go\npackage service\n```\n\n##### Do\n``` go\n// service/network.go\npackage service\n```\n\n\n### error处理\n一般情况下，都需要对函数的返回值error进行逻辑判断。\n\n如果函数返回的错误确实可以不处理，那么请用`_`明确告知他人`并非是忘记处理error而是将error丢弃`。丢弃error，本身也是一种处理方式。\n##### Don't\n``` go\n\n```\n\n##### Do\n``` go\nscores := map[string]int{\n\t\"jim\": 8,\n\t\"jerry\": 7,\n\t\"tom\": 3,\n}\n\nb,_ := json.Marshal(scores) // TODO 换个更好的例子\nfmt.Printf(\"%s\", b)\n```\n\n### error文本内容\n仅能使用英文系字符且以小写字母开头\n##### Don't\n``` go\nvar (\n\tErrInvalidIP = errors.New(\"无效的IP\")\n\tErrInvalidMacAddr = errors.New(\"Invalid mac address\")\n)\n```\n\n##### Do\n``` go\nvar (\n\tErrInvalidIP = errors.New(\"invalid ip\")\n\tErrInvalidMacAddr = errors.New(\"invalid mac address\")\n)\n```\n\n不要以标点符号结尾\n##### Don't\n``` go\nvar (\n\tErrInvalidIP = errors.New(\"invalid ip!\")\n)\n```\n\n##### Do\n``` go\nvar (\n\tErrInvalidIP = errors.New(\"invalid ip\")\n)\n```\n\n### panic与error\n在一般业务代码中，建议使用`error`而非`panic`。\n\n##### Don't\n``` go\nfunc (repo model.Repo) GetUserByName(name string)(user *model.User){\n\tif name == \"\"{\n\t\tpanic(\"user name can't be empty\")\n\t}\n\t...\n}\n```\n##### Do\n``` go\nvar ErrEmptyUserName = errors.New(\"user name can't be empty\")\n\nfunc (repo model.Repo) GetUserByName(name string)(user *model.User, err error){\n\tif name == \"\"{\n\t\treturn nil, ErrEmptyUserName\n\t}\n\t...\n}\n```\n\n有时候为了降低函数的错误处理成本，可以把函数的`error`返回值移除。而函数一旦发生错误，则发生`panic`。这种场景要求函数名称以`Must`开头，并且在注释中明确告知此函数的`副作用`。\n\n##### Do\n``` go\npackage regexp\n\n// MustCompile is like Compile but panics if the expression cannot be parsed.\n// It simplifies safe initialization of global variables holding compiled regular\n// expressions.\nfunc MustCompile(str string) *Regexp {\n  \tregexp, error := Compile(str)\n  \tif error != nil {\n  \t\tpanic(`regexp: Compile(` + quote(str) + `): ` + error.Error())\n  \t}\n  \treturn regexp\n}\n```\n\n对于那些可以被认为是`绝对不可能发生的事`，可谨慎使用`panic`。\n\n##### Do\n``` go\ntype Season int\n\nconst (\n\tSpring Season = iota\n\tSummer\n\tFall\n\tWinter\n)\n\nfunc SeasonName(season Season) string {\n\tswitch season {\n\tcase Spring:\n\t\treturn \"Spring\"\n\tcase Summer:\n\t\treturn \"Summer\"\n\tcase Fall:\n\t\treturn \"Fall\"\n\tcase Winter:\n\t\treturn \"Winter\"\n\t}\n\tpanic(\"unreachable\") \n}\n```\n\n- 对于`error`、`panic`模棱两可的情况，就选`error`。\n\n### 字符串拼接\n多个字符串拼接时不要使用`+`，建议使用`fmt.Sprintf`或者`strings.Builder`。\n##### Don't\n``` go\nfunc (stu Student) String() string {\n\treturn stu.Num + \" \" + stu.Name + \" \" + stu.Age\n}\n```\n\n##### Do\n``` go\nfunc (stu Student) String() string {\n\treturn fmt.Sprintf(\"%s %s %d\", stu.Num, stu.Name, stu.Age)\n}\n\n// OR\n\nfunc (stu Student) String() string {\n\tvar buf bytes.Buffer\n\tbuf.WriteString(stu.Num)\n\tbuf.WriteString(\" \")\n\tbuf.WriteString(stu.Name)\n\tbuf.WriteString(\" \")\n\tbuf.WriteString(stu.Age)\n\treturn buf.String()\n}\n```\n\n### receiver类型\n如果receiver是map,func,chan，不使用指针。\n\n如果receiver是slice,当方法不会重组或重新分配切片，不使用指针。\n\n如果方法需要改变receiver,必须使用指针。\n\n当receiver是包含锁或同步字段时，必须使用指针以避免复制。\n\n对于大的结构体或数组，指针更加的高效。\n\n当外面的改动必须影响到原始的receiver时，必须使用指针。\n\n最后，如果怀疑，那么请使用指针。\n\n### 控制结构\n将`变量作用域`控制在最小范围内。\n##### Don't\n``` go\nerr := file.Chmod(0664)\nif err != nil {\n    return err\n}\n```\n\n##### Do\n``` go\nif err := file.Chmod(0664); err != nil {\n    return err\n}\n```\n\n应尽早return结束代码块。尽量不要将语句嵌入代码块中，以避免层次过深，增加复杂度。\n##### Don't\n``` go\nfunc gender(female bool) (desc string){\n\tif female {\n\t\treturn \"female\"\n\t} else {\n\t\treturn \"male\"\n\t}\n}\n```\n\n##### Do\n``` go\nfunc gender(female bool) (desc string){\n\tif female {\n\t\treturn \"female\"\n\t}\n\treturn \"male\"\n}\n```\n\n判断结构中比较布尔类型变量\n##### Don't\n``` go\nfunc gender(female bool) (desc string){\n\tif female == true {\n\t\treturn \"female\"\n\t}\n\treturn \"male\"\n}\n```\n\n##### Do\n``` go\nfunc gender(female bool) (desc string){\n\tif female{\n\t\treturn \"female\"\n\t}\n\treturn \"male\"\n}\n```\n\n遍历slice时应尽量使用下标访问元素，避免不必要的内存拷贝。\n##### Don't\n``` go\ntype BigStruct struct{\n\tID int\n}\n\nitems := []BigStruct{\n\t{ID: 0},\n\t{ID: 1},\n}\n\nfor _, item := range items{ // 每次都会将下标元素拷贝至变量item\n\tfmt.Println(item.ID)\n}\n```\n\n##### Do\n``` go\ntype BigStruct struct{\n\tID int\n}\n\nitems := []BigStruct{\n\t{ID: 0},\n\t{ID: 1},\n}\n\nfor i := range items{ // 通过下标访问slice中的元素，无拷贝\n\tfmt.Println(items[i].ID)\n}\n```\n\n\n\n## 参考\n- [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments)\n- [Go Code Review Comments译文](https://github.com/wangming1993/issues/issues/42)\n- [Go Styleguide](https://github.com/bahlo/go-styleguide)\n- [Golang编码规范](https://segmentfault.com/a/1190000000464394)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoidint%2Fgo-style-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvoidint%2Fgo-style-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoidint%2Fgo-style-guide/lists"}