{"id":26022124,"url":"https://github.com/fsgo/go_fmt","last_synced_at":"2026-01-12T16:04:17.773Z","repository":{"id":49753826,"uuid":"223525387","full_name":"fsgo/go_fmt","owner":"fsgo","description":"更好用的 go代码格式化工具","archived":false,"fork":false,"pushed_at":"2024-08-25T09:43:31.000Z","size":367,"stargazers_count":94,"open_issues_count":1,"forks_count":10,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-08-25T10:43:52.035Z","etag":null,"topics":["go","gofmt","goimports","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fsgo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2019-11-23T03:34:10.000Z","updated_at":"2024-08-25T09:40:02.000Z","dependencies_parsed_at":"2022-09-26T20:40:59.456Z","dependency_job_id":"1b8b017e-dd43-4049-a123-8c667786aae9","html_url":"https://github.com/fsgo/go_fmt","commit_stats":null,"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fsgo%2Fgo_fmt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fsgo%2Fgo_fmt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fsgo%2Fgo_fmt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fsgo%2Fgo_fmt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fsgo","download_url":"https://codeload.github.com/fsgo/go_fmt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242187638,"owners_count":20086217,"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","gofmt","goimports","golang"],"created_at":"2025-03-06T09:54:26.255Z","updated_at":"2026-01-12T16:04:17.759Z","avatar_url":"https://github.com/fsgo.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"\u003c!-- Keep these links. Translations will automatically update with the README. --\u003e\n[Deutsch](https://zdoc.app/de/fsgo/go_fmt) | \n[English](https://zdoc.app/en/fsgo/go_fmt) | \n[Español](https://zdoc.app/es/fsgo/go_fmt) | \n[français](https://zdoc.app/fr/fsgo/go_fmt) | \n[日本語](https://zdoc.app/ja/fsgo/go_fmt) | \n[한국어](https://zdoc.app/ko/fsgo/go_fmt) | \n[Português](https://zdoc.app/pt/fsgo/go_fmt) | \n[Русский](https://zdoc.app/ru/fsgo/go_fmt) | \n[中文](https://zdoc.app/zh/fsgo/go_fmt)\n\n# Go 代码格式化\n\n## 1 功能说明\n* 格式化 import 部分：分3段式，依默认为 `标准库`、`第三方库`、`项目自身库`\n* 格式化单行注释：若为 `//注释内容`，调整为 `//{空格}注释内容`\n* 默认只对 git 项目库里有修改的进行格式化\n* 支持将多行的 copyright 注释修改为单行格式(默认不调整)\n* 简化代码、重写修正(将废弃的方法替换为推荐的新方法)\n* struct 赋值表达式，自动补齐 key\n* 补充空行、移除多余的空行\n\n对于 import 部分：\n\u003e 1.可使用`-mi`参数来控制是否将多段import合并为一段（默认否）。  \n\u003e 2.对于注释的import path,会按照其实际路径参与分组和排序。   \n\u003e 3.对于非末行的注释的位置会和其下面紧挨的import path绑定在一起。  \n\u003e 4.末行的注释则会放入import的头部。  \n\u003e 5.import path 不要使用相对路径(如`./` 和 `../`)。\n\n会忽略当前目录以及子目录下的 `testdata` 和 `vendor` 目录。  \n若需要可进入其目录里执行该命令。  \n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eExample 1：补齐 struct key\u003c/i\u003e\u003c/summary\u003e\n\n``` diff\n- u2 := User{\"hello\", 12}\n+ u2 := User{Name: \"hello\", Age: 12}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eExample 2：注释格式化\u003c/i\u003e\u003c/summary\u003e\n\n```diff\n- //User 注释内容\n+ // User 注释内容\ntype User struct{\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eExample 3：简化、重写代码\u003c/i\u003e\u003c/summary\u003e\n\n1. 简化循环逻辑：\n```diff\n- s[a:len(s)]\n+ s[a:]\n\n- for x, _ = range v {...}\n+ for x = range v {...}\n\n- for _ = range v {...}\n+ for range v {...}\n\n- for {\n+ for ok{\n-   if !ok {\n-     break\n-   }\n   // do something\n }\n```\n\n2. 简化判断逻辑：\n```diff\n- if b == true {\n+ if b { \n\n- if b == false {\n+ if !b {\n\n- if b != true {\n+ if !b {\n\n- if b != false {\n+ if b {\n\n- for b == true {\n+ for b {\n\n- _ = 1 == index\n+ _ = index == 1\n\n- _ = 1 \u003c index\n+ _ = index \u003e 1\n\n func ok() bool {\n- \tif a \u003e b {\n- \t\treturn true\n- \t}else{\n- \t\treturn false\n+ \treturn a \u003e b\n} \n\nfunc ok() bool {\n- \tif a \u003e b {\n- \t\treturn true\n- \treturn false\n+ \treturn a \u003e b\n} \n\n- if val!=nil \u0026\u0026 len(val)!=0 {\n+ if len(val)!=0 {\n   // do something\n}\n\n```\n\n3. 使用 `strings.Contains` 替换 `strings.Count` 和 `strings.Index`\n```diff\n- strings.Count(s, \"a\") == 0\n+ !strings.Contains(s, \"a\")\n\n- strings.Count(s, \"a\") \u003e 0\n+ strings.Contains(s, \"a\")\n\n- strings.Count(s, \"a\") != 0\n+ strings.Contains(s, \"a\")\n```\n`bytes.Count` 具有和 `strings.Count` 一样的规则。\n\n```diff\n- strings.Index(s, \"a\") == -1\n+ !strings.Contains(s, \"a\")\n\n- strings.Index(s, \"a\") != -1\n+ strings.Contains(s, \"a\")\n```\n`bytes.Index` 具有和 `strings.Index` 一样的规则。\n\n4. 字符串的比较：\n\n使用 `bytes.Equal` 替换 `bytes.Compare`：\n```diff\n- bytes.Compare(s,a) == 0\n+ bytes.Equal(s, a)\n\n- bytes.Compare(s,a) != 0\n+ !bytes.Equal(s, a)\n```\n\n使用 `==` 替换 `strings.Compare`：\n```diff\n- strings.Compare(\"abc\",\"a\") == 0\n+ \"abc\" == \"a\"\n\n- strings.Compare(\"abc\",\"a\") != 0\n+ \"abc\" != \"a\"\n```\n\n5. 递增 1、递减 1:\n```diff\n- i += 1\n+ i++\n\n- i -= 1\n+ i--\n```\n\n6. time.Since 和 time.Until\n`time.Since`  替换 `time.Now().Sub`:\n```diff\n- time.Now().Sub( t1 )\n+ time.Since( t1 )\n```\n\n`time.Until`  替换 `t.Sub( time.Now() )`:\n```diff\n- t1.Sub( time.Now() )\n+ time.Until( t1 )\n```\n\n7. channel:\n```diff\n- _ = \u003c-chan\n+ \u003c-done\n```\n\n8. map:\n```diff\n- x, _ := someMap[\"key\"]\n+ x := someMap[\"key\"]\n```\n\n9. fmt:\n```diff\n- fmt.Errorf(\"hello\")\n+ errors.New(\"hello\")\n\n- fmt.Printf(\"abc\")\n+ fmt.Print(\"abc\")\n\n- log.Printf(\"abc\")\n+ log.Print(\"abc\")\n\n- _ = errors.New(fmt.Sprintf(\"hello\"))\n+ _ = errors.New(\"hello\")\n\n- _ = errors.New(fmt.Sprintf(\"hello %s\", \"world\"))\n+ _ = fmt.Errorf(\"hello %s\", \"world\")\n\n- bf.Write([]byte(fmt.Sprintf(\"hello %d\", 1)))\n+ fmt.Fprintf(bf,\"hello %d\",1)\n\n- fmt.Sprintf(\"%d\",123)  // 性能  1\n+ strconv.Atoi(123)      // 性能  3\n\n- fmt.Sprintf(\"%v\",123)\n+ strconv.Atoi(123)   \n\n- fmt.Sprintf(\"%d\",int32Num)\n+ strconv.FormatInt(int64(int32Num), 10)\n\n- fmt.Sprintf(\"%d\",uint32Num)\n+ strconv.FormatUint(uint64(uint32Num), 10)\n```\n\n10. raw string :\n```diff\n- regexp.Compile(\"\\\\A(\\\\w+) profile: total \\\\d+\\\\n\\\\z\")\n+ regexp.Compile(`\\A(\\w+) profile: total \\d+\\n\\z`)\n```\n\n11. sort :\n```diff\n- sort.Sort(sort.StringSlice(x))\n+ sort.Strings(x)\n```\n\n12. os.IsExist 等替换为使用 errors.Is\n```diff\n- os.IsExist(err)\n+ errors.Is(err, fs.ErrExist)\n\n- os.IsNotExist(err)\n+ errors.Is(err, fs.ErrNotExist)\n\n- os.IsPermission(err)\n+ errors.Is(err, fs.ErrPermission)\n```\n添加于： 2025-09-02 v0.7.0\n\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eExample 4：基于表达式规则，重写代码\u003c/i\u003e\u003c/summary\u003e\n使用 `-rr=false` 可以使用默认内置规则不生效。\n\n1. 替换废弃的 `ioutil` 的函数调用：\n\n```diff\nimport (\n-\t\"io/ioutil\"\n+\t\"io\n)\n\n- buf, err := ioutil.ReadAll(f)\n+ buf, err := io.ReadAll(f)\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eExample 5：移除多余的空行\u003c/i\u003e\u003c/summary\u003e\n\n1. 移除 struct 内部前后多余的空行：\n```diff\ntype userfn91 struct{\n-\t\t\t\t\n\tname string\n-\t\t\t\t\n}\n```\n\n2. 移除 func 内部前后多余的空行：\n``` diff\nfn1() {\n-\t\t\t\t\n\tprintln(\"hello\")\n-\t\t\t\t\n}\n\n```\n\n3. 空 func 变为一行：\n```diff\n- fn1() {\n- }\n+ fn1() {}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eExample 6：补充空行\u003c/i\u003e\u003c/summary\u003e\n在适当的位置添加空行可以增加代码的可读性。\n\n1. struct 有文档的字段前后添加换行：\n\n```diff\ntype User1 struct {\n-\t\t\t\t\n\t// on Name\n\tName string\n+\t\t\t\t\n\t// on Age\n\tAge int\n+\t\t\t\t\n\tGrade int\n\tClass int\n\n\tAddress string // 前面有空行，会保持\n}\n```\n\n2. interface 有文档的方法前后添加换行：\n\n```diff\ntype Group1 interface {\n-\t\t\t\t\n\t// Register 注册延迟函数\n\tRegister(fn func())\n+\t\t\t\t\n\tAdd()\n+\t\t\t\t\n\t// on Delete\n\tDelete()\n+\t\t\t\t\n\tFn1()\n\n\tFn2() // 前面有空行，会保持\n-\t\t\t\t\n}\n```\n\n3. 多个定义之间添加空行:\n\n```diff\ntype (\n\tUser1 struct {\n\t\tname string\n\t}\n+\t\t\t\t\n\tUser1 struct {\n-\t\t\t\t\n\t\tname string\n\t}\n)\n```\n\n4. 全局的，不同类型定义之间添加空行：\n\n```diff\nvar a=\"hello\"\nvar b=\"world\" // after b\n+\t\t\t\t\nconst c01=\"say\"\n+ \t\t\t\t\nvar a0 = \"a0\"\n```\n\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eExample 7：Array / Slice 格式化\u003c/i\u003e\u003c/summary\u003e\n\n```diff\n- var _ = []int{\n-\t1, 2, \n-\t3, 4, 5}\n// 当代码是如上这种 3 行格式的时候（这 3 行内不能有注释），会格式化为下面这样。\n// 上面第一行是 2 个元素，所以按照每行 2 个元素格式化对齐。\n\n+\tvar _ = []int{\n+\t 1, 2,\n+\t 3, 4,\n+\t 5,\n+\t }\n```\n\u003c/details\u003e\n\n## 2 安装/更新\n```bash\nexport GO111MODULE=on\ngo env GOPROXY=https://goproxy.cn,direct\n\ngo install github.com/fsgo/go_fmt/cmd/gorgeous@latest\n```\n升级 Go 版本后，请用最新版本 go 重新安装/更新 `gorgeous` 。  \n最低 Go 版本：go1.23\n\n\n## 3 使用\n\n### 3.0 help\n\u003e gorgeous -help\n\n```bash\nusage: gorgeous [flags] [path ...]\n  -d\tdisplay diffs instead of rewriting files\n  -df string\n    \tdisplay diffs format, support: text, json (default \"text\")\n  -e\tenable extra rules (default true)\n  -ig string\n    \timport groups sort rule,\n    \tstc: Go Standard package, Third Party package, Current package\n    \tsct: Go Standard package, Current package, Third Party package\n    \t (default \"stc\")\n  -local string\n    \tcurrent package path, will put imports beginning with this string as 3rd-party packages.\n    \tby default, it will got from 'go.mod' file.\n    \t (default \"auto\")\n  -mi\n    \tmerge imports into one section.\n    \twith env 'GORGEOUS_MI=false' to set default value as false (default true)\n  -r value\n    \trewrite rule (e.g., 'a[b:len(a)] -\u003e a[b:]')\n    \tor a file path for rewrite rules (like -rr)\n\n  -rr\n    \trewrite with build in rules:\n    \ta[b:len(a)] -\u003e a[b:]\n    \tinterface{} -\u003e any                    // go1.18\n    \tio/#ioutil.NopCloser -\u003e io.NopCloser  // go1.16\n    \tio/#ioutil.ReadAll   -\u003e io.ReadAll    // go1.16\n    \tio/#ioutil.ReadFile  -\u003e os.ReadFile   // go1.16\n    \tio/#ioutil.TempFile  -\u003e os.CreateTemp // go1.16\n    \tio/#ioutil.TempDir   -\u003e os.MkdirTemp  // go1.16\n    \tio/#ioutil.WriteFile -\u003e os.WriteFile  // go1.16\n    \tio/#ioutil.Discard   -\u003e io.Discard    // go1.16\n\n    \twith env 'GORGEOUS_RR=false' to set default value as false\n    \t (default true)\n  -s\tsimplify code (default true)\n  -slcr\n    \tmultiline copyright to single-line\n    \twith env 'GORGEOUS_SLCR=true' to set default value as true (default true)\n  -trace\n    \tshow trace messages\n  -w\twrite result to (source) file instead of stdout (default true)\n```\n### 3.1 格式化 `git` 项目里有修改的`.go`文件\n```bash\n$ gorgeous\n```\n\n### 3.2 对当前目录所有 `.go` 文件格式化\n```bash\n$ gorgeous ./...\n```\n\n### 3.3 对指定 `.go` 文件格式化\n```bash\n$ gorgeous abc.go\n```\n\n### 3.4 从 STDIN 读取代码并输出到 STDOUT\n```bash\n$ cat code.go|gorgeous stdin\n```\n\n## 4 git hooks\n在执行 git 命令时自动格式化或者检查是否已经完成格式化。\n\n### 4.1 使用 bin-auto-switcher 添加全局 Hooks\n[bin-auto-switcher](https://github.com/fsgo/bin-auto-switcher) 可以很方便的对任意命令添加前置和后置 Hooks。\n\n1. 安装 git 替换命令（安装后，执行 git 命令时，实际会执行此命令，并执行配置的 Hooks）：  \n    `go install github.com/fsgo/bin-auto-switcher/git@latest`\n2. 编辑配置文件 `~/.config/bas/git.toml`\n```toml\n[[Rules]]\nCmd = \"/usr/local/bin/git\" # 替换为实际 git 命令的地址\n\n[[Rules.Pre]]\nMatch = \"^add\\\\s\"  # 在执行 git add 命令前执行\nTrace = true       # 打印日志\n#Cond  = [\"in_dir /home/work/goapps\"]\nCond  = [\"go_module\"]\nCmd   = \"gorgeous\"\n\n# 在 go.mod 文件所在目录下执行 gorgeous 命令\n#Cmd   = \"inner:find-exec\"\n#Args  = [\"-name\",\"go.mod\",\"-dir_not\",\"testdata\",\"gorgeous\"]\n```\n\n### 4.2 使用 git hooks\n\n编辑项目的 `.git/hooks/pre-commit`文件，将`gorgeous`命令加入。\n\n```bash\n# 检查是否格式化\necho -e '\\n gorgeous -d \\n' \u003e\u003e $(git rev-parse --git-dir)/hooks/pre-commit\n\nchmod 777 $(git rev-parse --git-dir)/hooks/pre-commit\n\n# 或者：自动格式化\necho -e '\\n gorgeous \\n git add . \\n' \u003e\u003e $(git rev-parse --git-dir)/hooks/pre-commit\n```\n\n还可以配置到全局 Hooks：\n\u003e 该方式会导致项目自身的 hooks 失效。  \n\u003e 若项目有自己的 hooks，请不要配置全局而要配置到单个项目。\n```bash\nmkdir -p ~/.git_config/hooks/\ngit config --global core.hooksPath ~/.git_config/hooks/\n\necho -e '\\n gorgeous -d\\n' \u003e\u003e  ~/.git_config/hooks/pre-commit\nchmod 777 ~/.git_config/hooks/pre-commit\n```\n\n## 5 GitHub Actions\n```yml\n- name: Set up Go\n  uses: actions/setup-go@v4\n  with:\n    go-version: 1.23\n\n- name: gorgeous style check \n  # gorgeous 添加 “-d” 参数后，只检查代码风格，不重写文件，会在终端输出需要格式化的文件信息，退出码为非 0\n  run: go install github.com/fsgo/go_fmt/cmd/gorgeous@latest \u0026\u0026 gorgeous -d ./...\n```\n\n## 6 Visual Studio Code\n\n### 6.1 As goformat\n1. Install as goformat:\n```bash\ngo install github.com/fsgo/go_fmt/cmd/goformat@latest\n```\n2. 配置的 `Go: Format Tool`，设置为 \"goformat\"：\n```\n  \"go.formatTool\": \"goformat\"\n```\n\n### 6.2 Run on Save\n1. 先安装插件 [Run on Save](https://marketplace.visualstudio.com/items?itemName=pucelle.run-on-save) \u003cimg src=\"https://github.com/pucelle/vscode-run-on-save/raw/master/images/logo.png\" width=\"20px\"/\u003e\n\n2. 配置插件，在保存文件的时候执行格式化命令：\n```json\n  \"runOnSave.commands\": [\n    {\n        \"match\": \"\\\\.go$\",\n        \"command\": \"cd ${fileDirname} \u0026\u0026 gorgeous -rr ${fileBasename}\",\n        \"runIn\":\"terminal\"\n    }\n ]\n```\n3. 配置的 `Go: Format Tool`，设置为 \"default\"：\n```\n  \"go.formatTool\": \"default\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffsgo%2Fgo_fmt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffsgo%2Fgo_fmt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffsgo%2Fgo_fmt/lists"}