100天精通Golang(基础入门篇)——第3天:Go语言的执行原理及常用命令、编码规范和常用工具

简介: 100天精通Golang(基础入门篇)——第3天:Go语言的执行原理及常用命令、编码规范和常用工具

🌷 博主 libin9iOak带您 Go to Golang Language.✨

🦄 个人主页——libin9iOak的博客🎐
🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺
🌊 《IDEA开发秘籍》学会IDEA常用操作,工作效率翻倍~💐
🪁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬请批评指正!🐥


Go语言的执行原理及常用命令、编码规范和常用工具

引言:

在学习和使用Go语言过程中,了解其执行原理和常用命令是非常重要的。同时,编写规范的代码和使用常用工具也是提高开发效率和代码质量的关键。本文将深入探讨Go语言的执行原理,介绍常用的命令,以及详细讲解编码规范和常用工具的使用方法。

摘要:

本文通过介绍Go语言的执行原理和常用命令,帮助读者全面了解Go的工作原理和常用命令的使用。同时,详细解释了Go编码规范的各个方面,包括命名规范、注释规范和代码风格。此外,还介绍了一些常用的工具,以提升开发效率和代码质量。通过学习本文,读者可以更好地掌握Go语言的使用技巧和开发规范。

Go语言的执行原理及常用命令

一、Go的源码文件

Go 的源码文件分类:

如上图,分为三类:

1、命令源码文件:

声明自己属于 main 代码包、包含无参数声明和结果声明的 main 函数。

命令源码文件被安装以后,GOPATH 如果只有一个工作区,那么相应的可执行文件会被存放当前工作区的 bin 文件夹下;如果有多个工作区,就会安装到 GOBIN 指向的目录下。

命令源码文件是 Go 程序的入口。

同一个代码包中最好也不要放多个命令源码文件。多个命令源码文件虽然可以分开单独 go run 运行起来,但是无法通过 go build 和 go install。

package main
import "fmt"
func main() {
  fmt.Println(`Hello Go!`)
  fmt.Print(`学习Go,学会Golang 就找wx: libin9iOak ! `)
}

我们先打开上次课Day0的hello目录,然后复制HelloGo.go为HelloGo2.go文件,并修改里面的内容:

package main
import "fmt"
func main() {
  fmt.Println(`Hello Go!`)
  fmt.Println(`我是第二个 Hello Go!`)
  fmt.Print(`学习Go,学会Golang 就找wx: libin9iOak ! `)
}

hello目录下有两个go文件了,一个是HelloGo.go,一个是HelloGo2.go。先说明一下,在上述文件夹中放了两个命令源码文件,同时都声明自己属于 main 代码包。

打开终端,进入hello这个目录,也可以看到这两个文件:

然后我们分别执行go run命令,可以看到两个go文件都可以被执行:

D:\GolandProjects\Day0-Environmental-Construction>go run HelloGo.go
Hello Go!
学习Go,学会Golang 就找wx: libin9iOak !
D:\GolandProjects\Day0-Environmental-Construction>go run HelloGo2.go
Hello Go!
我是第二个 Hello Go!
学习Go,学会Golang 就找wx: libin9iOak !
D:\GolandProjects\Day0-Environmental-Construction>

接下来执行 go build 和 go install ,看看会发生什么:

D:\GolandProjects\Day0-Environmental-Construction>go build
# Day0-Environmental-Construction
.\HelloGo2.go:5:6: main redeclared in this block
        .\HelloGo.go:5:6: other declaration of main
D:\GolandProjects\Day0-Environmental-Construction>go install
# Day0-Environmental-Construction
.\HelloGo2.go:5:6: main redeclared in this block
        .\HelloGo.go:5:6: other declaration of main

运行效果图:

这也就证明了多个命令源码文件虽然可以分开单独 go run 运行起来,但是无法通过 go build 和 go install。

同理,如果命令源码文件和库源码文件也会出现这样的问题,库源码文件不能通过 go build 和 go install 这种常规的方法编译和安装。具体例子和上述类似,这里就不再贴代码了。

所以命令源码文件应该是被单独放在一个代码包中。

2、库源码文件

库源码文件就是不具备命令源码文件上述两个特征的源码文件。存在于某个代码包中的普通的源码文件。

库源码文件被安装后,相应的归档文件(.a 文件)会被存放到当前工作区的 pkg 的平台相关目录下。

3、测试源码文件

名称以 _test.go 为后缀的代码文件,并且必须包含 Test 或者 Benchmark 名称前缀的函数:

func TestXXX( t *testing.T) {
}

名称以 Test 为名称前缀的函数,只能接受 *testing.T 的参数,这种测试函数是功能测试函数。

func BenchmarkXXX( b *testing.B) {
}

名称以 Benchmark 为名称前缀的函数,只能接受 *testing.B 的参数,这种测试函数是性能测试函数。

现在答案就很明显了:

命令源码文件是可以单独运行的。可以使用 go run 命令直接运行,也可以通过 go build 或 go install 命令得到相应的可执行文件。所以命令源码文件是可以在机器的任何目录下运行的。

举个栗子:

比如平时我们在 LeetCode 上刷算法题,这时候写的就是一个程序,这就是命令源码文件,可以在电脑的任意一个文件夹新建一个 go 文件就可以开始刷题了,写完就可以运行,对比执行结果,答案对了就可以提交代码。

但是公司项目里面的代码就不能这样了,只能存放在 GOPATH 目录下。因为公司项目不可能只有命令源码文件的,肯定是包含库源码文件,甚至包含测试源码文件的。

二、Go的命令

目前Go的最新版1.20里面基本命令有以下18个。

我们可以打开终端输入:go help即可看到Go的这些命令以及简介。

Go is a tool for managing Go source code.
Usage:
        go <command> [arguments]
The commands are:
        bug         start a bug report
        build       compile packages and dependencies
        clean       remove object files and cached files
        doc         show documentation for package or symbol
        env         print Go environment information
        fix         update packages to use new APIs
        fmt         gofmt (reformat) package sources
        generate    generate Go files by processing source
        get         add dependencies to current module and install them
        install     compile and install packages and dependencies
        list        list packages or modules
        mod         module maintenance
        work        workspace maintenance
        run         compile and run Go program
        test        test packages
        tool        run specified go tool
        version     print Go version
        vet         report likely mistakes in packages
Use "go help <command>" for more information about a command.
Additional help topics:
        buildconstraint build constraints
        buildmode       build modes
        c               calling between Go and C
        cache           build and test caching
        environment     environment variables
        filetype        file types
        go.mod          the go.mod file
        gopath          GOPATH environment variable
        gopath-get      legacy GOPATH go get
        goproxy         module proxy protocol
        importpath      import path syntax
        modules         modules, module versions, and more
        module-get      module-aware go get
        module-auth     module authentication using go.sum
        packages        package lists and patterns
        private         configuration for downloading non-public code
        testflag        testing flags
        testfunc        testing functions
        vcs             controlling version control with GOVCS
Use "go help <topic>" for more information about that topic.

其中和编译相关的有build、get、install、run这4个。接下来就依次看看这四个的作用。

在详细分析这4个命令之前,先罗列一下通用的命令标记,以下这些命令都可适用的:

名称 说明
-a 用于强制重新编译所有涉及的 Go 语言代码包(包括 Go 语言标准库中的代码包),即使它们已经是最新的了。该标记可以让我们有机会通过改动底层的代码包做一些实验。
-n 使命令仅打印其执行过程中用到的所有命令,而不去真正执行它们。如果不只想查看或者验证命令的执行过程,而不想改变任何东西,使用它正好合适。
-race 用于检测并报告指定 Go 语言程序中存在的数据竞争问题。当用 Go 语言编写并发程序的时候,这是很重要的检测手段之一。
-v 用于打印命令执行过程中涉及的代码包。这一定包括我们指定的目标代码包,并且有时还会包括该代码包直接或间接依赖的那些代码包。这会让你知道哪些代码包被执行过了。
-work 用于打印命令执行时生成和使用的临时工作目录的名字,且命令执行完成后不删除它。这个目录下的文件可能会对你有用,也可以从侧面了解命令的执行过程。如果不添加此标记,那么临时工作目录会在命令执行完毕前删除。
-x 使命令打印其执行过程中用到的所有命令,并同时执行它们。

1. go run

专门用来运行命令源码文件的命令,注意,这个命令不是用来运行所有 Go 的源码文件的!

go run 命令只能接受一个命令源码文件以及若干个库源码文件(必须同属于 main 包)作为文件参数,且不能接受测试源码文件。它在执行时会检查源码文件的类型。如果参数中有多个或者没有命令源码文件,那么 go run 命令就只会打印错误提示信息并退出,而不会继续执行。

这个命令具体干了些什么事情呢?来分析分析,我们先重新创建一个新文件:HelloGo.go,并加入以下代码:

package main
import "fmt"
func main() {
  fmt.Println(`Hello Go!`)
  fmt.Print(`学习Go,学会Golang 就找wx: libin9iOak ! `)
}

执行go run 配合-n:

D:\GolandProjects\Day0-Environmental-Construction>go run -n HelloGo.go
mkdir -p $WORK\b001\
cat >$WORK\b001\importcfg.link << 'EOF' # internal
packagefile command-line-arguments=C:\Users\DELL\AppData\Local\go-build\2b\2bd6ad0624f0645fa0e5af542f69e648a231ca6a2f9935ff1e8f8de6927004ea-d
packagefile fmt=C:\Users\DELL\AppData\Local\go-build\3c\3c35b207ddf783732e75e8e9fce6eb087fc231bd0727113344afa870b7b04083-d
packagefile runtime=C:\Users\DELL\AppData\Local\go-build\cf\cfdce82341d514dbc28ff8654ba5bda585b73b15ae35ae7d86545eb5a4cd13bc-d
packagefile errors=C:\Users\DELL\AppData\Local\go-build\7e\7e7304d7b9af989e583ddd1f8a5820a48f7bbdfef90c67a73cbbb34eafe93648-d
packagefile internal/fmtsort=C:\Users\DELL\AppData\Local\go-build\9b\9b0e005b117aa27ffed962c5d258af6b3fa617c9fa1b8ff8a6d73ec8c51d8ca2-d
packagefile io=C:\Users\DELL\AppData\Local\go-build\ab\ab6a14a39a314852aeaf6d96ae008b9aec8f7a85f8c371ac6be3d2af5451215d-d
packagefile math=C:\Users\DELL\AppData\Local\go-build\43\432639cfe764c9c0df3b00daa07e7696ba2b561739a290b5760925e3fd4353e7-d
packagefile os=C:\Users\DELL\AppData\Local\go-build\c2\c292b254469e7d904bc806b4b118adde0cc176507d86fdfca25b7d5f68b5667f-d
packagefile reflect=C:\Users\DELL\AppData\Local\go-build\d1\d185593dd3e10d591c2c62a9806bba416fd814523e6c68d56a5e7c4fd51f7b30-d
packagefile sort=C:\Users\DELL\AppData\Local\go-build\57\5708bd753e723e5a2622bd526343ae96320577c81ee5f284e6f4b0312dc68bc1-d
packagefile strconv=C:\Users\DELL\AppData\Local\go-build\81\8190375f61f9524ef77bb7a5bb07fd5b616ca352753c80dad8582d10e8b5ee67-d
packagefile sync=C:\Users\DELL\AppData\Local\go-build\0a\0a8c1deab61c4cdb1e388cd3e78113439fe886733e463f181e630df48f2e86fb-d
packagefile unicode/utf8=C:\Users\DELL\AppData\Local\go-build\70\7038eb351087e1b3f5e1f1b9db63ba4e0e7e570623ad7f9219cab9ecd966bba0-d
packagefile internal/abi=C:\Users\DELL\AppData\Local\go-build\19\19deee4ffa062ebb823e16d0985ac0cb267503eb8bd37ab1efb361c1c22175a7-d
packagefile internal/bytealg=C:\Users\DELL\AppData\Local\go-build\46\46a1c96025a1b8f457be439874049756954d50121f643f1c3c4b969f74d4e4ec-d
packagefile internal/coverage/rtcov=C:\Users\DELL\AppData\Local\go-build\10\10338d77712fb2873da719790ad23f5b53727a48859f047005507ce66d8e6f7c-d
packagefile internal/cpu=C:\Users\DELL\AppData\Local\go-build\05\053670270c3468062ed965c7268d69fe55144ec0165b9353b2ed87a3461819fb-d
packagefile internal/goarch=C:\Users\DELL\AppData\Local\go-build\09\09e36a64c03c3301dbd5c40179204684b9324eacc380ae53075f2ad265f2ce2f-d
packagefile internal/goexperiment=C:\Users\DELL\AppData\Local\go-build\4c\4cf0bf05316d86aa791823887cfad7e2a4f5d332870a3205c4867daa90cb3a0b-d
packagefile internal/goos=C:\Users\DELL\AppData\Local\go-build\3d\3d06725be51381414ebeabde383270627ab81f001c82510c5e772267856b733b-d
packagefile runtime/internal/atomic=C:\Users\DELL\AppData\Local\go-build\0f\0f1b6ba563e2236d8a89f5c1507c5c0a5fe7b208a486a3a1c3db30fb9fbe2904-d
packagefile runtime/internal/math=C:\Users\DELL\AppData\Local\go-build\a1\a1f82612aed40dfb4ac2884297afae7184aa10fbddf6083e80019b8db0955b35-d
packagefile runtime/internal/sys=C:\Users\DELL\AppData\Local\go-build\1a\1a7228ddd11f042c82951069d19531cc1acd4dfb4e45bf741e62c651bbda33f1-d
packagefile internal/reflectlite=C:\Users\DELL\AppData\Local\go-build\dc\dced230be4229638483a7f801b56c0c4d6202c447983f6e410bd10f8e2631333-d
packagefile math/bits=C:\Users\DELL\AppData\Local\go-build\33\3385b65d450d665e6a7c16bb97a3c8c0f945e19ad1210c95be8d11f4594ad794-d
packagefile internal/itoa=C:\Users\DELL\AppData\Local\go-build\37\37afe1b25ed3e0fb5a12bf28a5b41386f96691b67d1f59c664613869c8dd0c75-d
packagefile internal/poll=C:\Users\DELL\AppData\Local\go-build\c4\c4b871ad9dedd8c7f2b0f784cf96dbb233973372c13280eae69cbb07a08a3007-d
packagefile internal/safefilepath=C:\Users\DELL\AppData\Local\go-build\3c\3cc52bda0057ad884b53aa68f41a1821b82df6f8347df3e731748e4a341f54f5-d
packagefile internal/syscall/execenv=C:\Users\DELL\AppData\Local\go-build\26\261ca5afb7d46db3d72d9c356787803e5ad53d7ffa4b8506f2354a104492aef6-d
packagefile internal/syscall/windows=C:\Users\DELL\AppData\Local\go-build\9e\9e2c342ade11cf7f70a3ba2ca380e8c1587308fb248b0cb25b875e17e0fb89a8-d
packagefile internal/testlog=C:\Users\DELL\AppData\Local\go-build\81\81baa932ebb799ffd2e77d118f48ea0357e12c8e38df4c026ff2fcc1ea7edf30-d
packagefile io/fs=C:\Users\DELL\AppData\Local\go-build\e7\e7231aab61c74bd82f8ff3e00a76be93b21bbfc01c24bf4547a45a8b70ae1d46-d
packagefile sync/atomic=C:\Users\DELL\AppData\Local\go-build\4c\4c8aa57b5e613bdf756af136e8a38c658fc01f5e3a29265eed29ebf4664b9816-d
packagefile syscall=C:\Users\DELL\AppData\Local\go-build\d8\d807b3618ec1cb020abfce1e6c0e0ec0b3a3faa677c2026468054a6fdc013f83-d
packagefile time=C:\Users\DELL\AppData\Local\go-build\03\039303d3af19acb12bb91f2c4be182bc753f05b9c26d3ad3a3b474527bbf7cae-d
packagefile unicode/utf16=C:\Users\DELL\AppData\Local\go-build\76\76c228b95f4ab5ca3f0fb15647d86ff1218856db4c28a16e760f87429f06f8e9-d
packagefile internal/unsafeheader=C:\Users\DELL\AppData\Local\go-build\ba\ba6583504c64ff5494f6b12cda1a7ab251262d333ad9958dae1bf01d0ee6b631-d
packagefile unicode=C:\Users\DELL\AppData\Local\go-build\e1\e1b23cd549bfe190830d95358ba3a39016879996be66e7dd6684b96962aca5df-d
packagefile internal/race=C:\Users\DELL\AppData\Local\go-build\cb\cb359393b92642359b6ed939f6c0da833c26d0f917ee1023a2175287c759e707-d
packagefile internal/syscall/windows/sysdll=C:\Users\DELL\AppData\Local\go-build\87\873706adf5dd2f9af8925124802899648371898fb66a67120eb50737c779b660-d
packagefile internal/oserror=C:\Users\DELL\AppData\Local\go-build\a6\a6bb5bbbd7571473f9d959aa531de93d31482f009ddc781b024f2965cc27961a-d
packagefile path=C:\Users\DELL\AppData\Local\go-build\25\25475e013de00cdd5e60564aa59f1c9ed8da0cbeab3c93192cd97f200b5d3113-d
packagefile internal/syscall/windows/registry=C:\Users\DELL\AppData\Local\go-build\25\25eaa73ca9efcf9d7d248ecd0edff84257e56712f5da752a9f0efb26469aa98c-d
modinfo "0w\xaf\f\x92t\b\x02A\xe1\xc1\a\xe6\xd6\x18\xe6path\tcommand-line-arguments\nbuild\t-buildmode=exe\nbuild\t-compiler=gc\nbuild\tCGO_ENABLED=1\nbuild\tCGO_CFLAGS=\nbuild\tCGO_CPPFLAGS=\nbuild\tCGO_CXXFLAGS=\nbuild\tCGO_LDFLAGS=\nbuild\tGOARCH=amd64\nbuild\tGOOS=windows\nbuild\tGOAMD64=v1\n\xf92C1\x86\x18 r\x00\x82B\x10A\x16\xd8\xf2"
EOF
mkdir -p $WORK\b001\exe\
cd .
"D:\\Go\\pkg\\tool\\windows_amd64\\link.exe" -o "$WORK\\b001\\exe\\HelloGo.exe" -importcfg "$WORK\\b001\\importcfg.link" -s -w -buildmode=pie -buildid=h7cqzBwlEgeoXPcmB1dl/pgnZg569-6UyzEKIdV04/AX5-9rcgdTuIO-sFY2jf/h7cqzBwlEgeoXPcmB1dl -extld=gcc "C:\\Users\\DELL\\AppData\\Local\\go-build\\2b\\2bd6ad0624f0645fa0e5af542f69e648a231ca6a2f9935ff1e8f8de6927004ea-d"
$WORK\b001\exe\HelloGo.exe

运行效果图:

这里可以看到创建了两个临时文件夹 b001 和 exe,先执行了 compile 命令,然后 link,生成了归档文件.a 和 最终可执行文件,最终的可执行文件放在 exe 文件夹里面。命令的最后一步就是执行了可执行文件。

总结一下如下图:

举个例子,生成的临时文件可以用go run -work看到,比如当前生成的临时文件夹是如下的路径:

D:\GolandProjects\Day0-Environmental-Construction>go run -work HelloGo.go
WORK=C:\Users\DELL\AppData\Local\Temp\go-build3848787815
Hello Go!
学习Go,学会Golang 就找wx: libin9iOak !
D:\GolandProjects\Day0-Environmental-Construction>

我们进入:C:\Users\DELL\AppData\Local\Temp\go-build3848787815目录,可以看到如下目录结构:

可以看到,最终go run命令是生成了2个文件,一个是归档文件,一个是可执行文件。

go run 命令在第二次执行的时候,如果发现导入的代码包没有发生变化,那么 go run 不会再次编译这个导入的代码包。直接静态链接进来。

D:\GolandProjects\Day0-Environmental-Construction>go run -n HelloGo.go
mkdir -p $WORK\b001\
cat >$WORK\b001\importcfg.link << 'EOF' # internal
packagefile command-line-arguments=C:\Users\DELL\AppData\Local\go-build\2b\2bd6ad0624f0645fa0e5af542f69e648a231ca6a2f9935ff1e8f8de6927004ea-d
packagefile fmt=C:\Users\DELL\AppData\Local\go-build\3c\3c35b207ddf783732e75e8e9fce6eb087fc231bd0727113344afa870b7b04083-d
packagefile runtime=C:\Users\DELL\AppData\Local\go-build\cf\cfdce82341d514dbc28ff8654ba5bda585b73b15ae35ae7d86545eb5a4cd13bc-d
packagefile errors=C:\Users\DELL\AppData\Local\go-build\7e\7e7304d7b9af989e583ddd1f8a5820a48f7bbdfef90c67a73cbbb34eafe93648-d
packagefile internal/fmtsort=C:\Users\DELL\AppData\Local\go-build\9b\9b0e005b117aa27ffed962c5d258af6b3fa617c9fa1b8ff8a6d73ec8c51d8ca2-d
packagefile io=C:\Users\DELL\AppData\Local\go-build\ab\ab6a14a39a314852aeaf6d96ae008b9aec8f7a85f8c371ac6be3d2af5451215d-d
packagefile math=C:\Users\DELL\AppData\Local\go-build\43\432639cfe764c9c0df3b00daa07e7696ba2b561739a290b5760925e3fd4353e7-d
packagefile os=C:\Users\DELL\AppData\Local\go-build\c2\c292b254469e7d904bc806b4b118adde0cc176507d86fdfca25b7d5f68b5667f-d
packagefile reflect=C:\Users\DELL\AppData\Local\go-build\d1\d185593dd3e10d591c2c62a9806bba416fd814523e6c68d56a5e7c4fd51f7b30-d
packagefile sort=C:\Users\DELL\AppData\Local\go-build\57\5708bd753e723e5a2622bd526343ae96320577c81ee5f284e6f4b0312dc68bc1-d
packagefile strconv=C:\Users\DELL\AppData\Local\go-build\81\8190375f61f9524ef77bb7a5bb07fd5b616ca352753c80dad8582d10e8b5ee67-d
packagefile sync=C:\Users\DELL\AppData\Local\go-build\0a\0a8c1deab61c4cdb1e388cd3e78113439fe886733e463f181e630df48f2e86fb-d
packagefile unicode/utf8=C:\Users\DELL\AppData\Local\go-build\70\7038eb351087e1b3f5e1f1b9db63ba4e0e7e570623ad7f9219cab9ecd966bba0-d
packagefile internal/abi=C:\Users\DELL\AppData\Local\go-build\19\19deee4ffa062ebb823e16d0985ac0cb267503eb8bd37ab1efb361c1c22175a7-d
packagefile internal/bytealg=C:\Users\DELL\AppData\Local\go-build\46\46a1c96025a1b8f457be439874049756954d50121f643f1c3c4b969f74d4e4ec-d
packagefile internal/coverage/rtcov=C:\Users\DELL\AppData\Local\go-build\10\10338d77712fb2873da719790ad23f5b53727a48859f047005507ce66d8e6f7c-d
packagefile internal/cpu=C:\Users\DELL\AppData\Local\go-build\05\053670270c3468062ed965c7268d69fe55144ec0165b9353b2ed87a3461819fb-d
packagefile internal/goarch=C:\Users\DELL\AppData\Local\go-build\09\09e36a64c03c3301dbd5c40179204684b9324eacc380ae53075f2ad265f2ce2f-d
packagefile internal/goexperiment=C:\Users\DELL\AppData\Local\go-build\4c\4cf0bf05316d86aa791823887cfad7e2a4f5d332870a3205c4867daa90cb3a0b-d
packagefile internal/goos=C:\Users\DELL\AppData\Local\go-build\3d\3d06725be51381414ebeabde383270627ab81f001c82510c5e772267856b733b-d
packagefile runtime/internal/atomic=C:\Users\DELL\AppData\Local\go-build\0f\0f1b6ba563e2236d8a89f5c1507c5c0a5fe7b208a486a3a1c3db30fb9fbe2904-d
packagefile runtime/internal/math=C:\Users\DELL\AppData\Local\go-build\a1\a1f82612aed40dfb4ac2884297afae7184aa10fbddf6083e80019b8db0955b35-d
packagefile runtime/internal/sys=C:\Users\DELL\AppData\Local\go-build\1a\1a7228ddd11f042c82951069d19531cc1acd4dfb4e45bf741e62c651bbda33f1-d
packagefile internal/reflectlite=C:\Users\DELL\AppData\Local\go-build\dc\dced230be4229638483a7f801b56c0c4d6202c447983f6e410bd10f8e2631333-d
packagefile math/bits=C:\Users\DELL\AppData\Local\go-build\33\3385b65d450d665e6a7c16bb97a3c8c0f945e19ad1210c95be8d11f4594ad794-d
packagefile internal/itoa=C:\Users\DELL\AppData\Local\go-build\37\37afe1b25ed3e0fb5a12bf28a5b41386f96691b67d1f59c664613869c8dd0c75-d
packagefile internal/poll=C:\Users\DELL\AppData\Local\go-build\c4\c4b871ad9dedd8c7f2b0f784cf96dbb233973372c13280eae69cbb07a08a3007-d
packagefile internal/safefilepath=C:\Users\DELL\AppData\Local\go-build\3c\3cc52bda0057ad884b53aa68f41a1821b82df6f8347df3e731748e4a341f54f5-d
packagefile internal/syscall/execenv=C:\Users\DELL\AppData\Local\go-build\26\261ca5afb7d46db3d72d9c356787803e5ad53d7ffa4b8506f2354a104492aef6-d
packagefile internal/syscall/windows=C:\Users\DELL\AppData\Local\go-build\9e\9e2c342ade11cf7f70a3ba2ca380e8c1587308fb248b0cb25b875e17e0fb89a8-d
packagefile internal/testlog=C:\Users\DELL\AppData\Local\go-build\81\81baa932ebb799ffd2e77d118f48ea0357e12c8e38df4c026ff2fcc1ea7edf30-d
packagefile io/fs=C:\Users\DELL\AppData\Local\go-build\e7\e7231aab61c74bd82f8ff3e00a76be93b21bbfc01c24bf4547a45a8b70ae1d46-d
packagefile sync/atomic=C:\Users\DELL\AppData\Local\go-build\4c\4c8aa57b5e613bdf756af136e8a38c658fc01f5e3a29265eed29ebf4664b9816-d
packagefile syscall=C:\Users\DELL\AppData\Local\go-build\d8\d807b3618ec1cb020abfce1e6c0e0ec0b3a3faa677c2026468054a6fdc013f83-d
packagefile time=C:\Users\DELL\AppData\Local\go-build\03\039303d3af19acb12bb91f2c4be182bc753f05b9c26d3ad3a3b474527bbf7cae-d
packagefile unicode/utf16=C:\Users\DELL\AppData\Local\go-build\76\76c228b95f4ab5ca3f0fb15647d86ff1218856db4c28a16e760f87429f06f8e9-d
packagefile internal/unsafeheader=C:\Users\DELL\AppData\Local\go-build\ba\ba6583504c64ff5494f6b12cda1a7ab251262d333ad9958dae1bf01d0ee6b631-d
packagefile unicode=C:\Users\DELL\AppData\Local\go-build\e1\e1b23cd549bfe190830d95358ba3a39016879996be66e7dd6684b96962aca5df-d
packagefile internal/race=C:\Users\DELL\AppData\Local\go-build\cb\cb359393b92642359b6ed939f6c0da833c26d0f917ee1023a2175287c759e707-d
packagefile internal/syscall/windows/sysdll=C:\Users\DELL\AppData\Local\go-build\87\873706adf5dd2f9af8925124802899648371898fb66a67120eb50737c779b660-d
packagefile internal/oserror=C:\Users\DELL\AppData\Local\go-build\a6\a6bb5bbbd7571473f9d959aa531de93d31482f009ddc781b024f2965cc27961a-d
packagefile path=C:\Users\DELL\AppData\Local\go-build\25\25475e013de00cdd5e60564aa59f1c9ed8da0cbeab3c93192cd97f200b5d3113-d
packagefile internal/syscall/windows/registry=C:\Users\DELL\AppData\Local\go-build\25\25eaa73ca9efcf9d7d248ecd0edff84257e56712f5da752a9f0efb26469aa98c-d
modinfo "0w\xaf\f\x92t\b\x02A\xe1\xc1\a\xe6\xd6\x18\xe6path\tcommand-line-arguments\nbuild\t-buildmode=exe\nbuild\t-compiler=gc\nbuild\tCGO_ENABLED=1\nbuild\tCGO_CFLAGS=\nbuild\tCGO_CPPFLAGS=\nbuild\tCGO_CXXFLAGS=\nbuild\tCGO_LDFLAGS=\nbuild\tGOARCH=amd64\nbuild\tGOOS=windows\nbuild\tGOAMD64=v1\n\xf92C1\x86\x18 r\x00\x82B\x10A\x16\xd8\xf2"
EOF
mkdir -p $WORK\b001\exe\
cd .
"D:\\Go\\pkg\\tool\\windows_amd64\\link.exe" -o "$WORK\\b001\\exe\\HelloGo.exe" -importcfg "$WORK\\b001\\importcfg.link" -s -w -buildmode=pie -buildid=h7cqzBwlEgeoXPcmB1dl/pgnZg569-6UyzEKIdV04/AX5-9rcgdTuIO-sFY2jf/h7cqzBwlEgeoXPcmB1dl -extld=gcc "C:\\Users\\DELL\\AppData\\Local\\go-build\\2b\\2bd6ad0624f0645fa0e5af542f69e648a231ca6a2f9935ff1e8f8de6927004ea-d"
$WORK\b001\exe\HelloGo.exe
D:\GolandProjects\Day0-Environmental-Construction>

2. go build

go build 命令主要是用于测试编译。在包的编译过程中,若有必要,会同时编译与之相关联的包。

  1. 如果是普通包,当你执行go build命令后,不会产生任何文件。
  2. 如果是main包,当只执行go build命令后,会在当前目录下生成一个可执行文件。如果需要在$GOPATH/bin目录下生成相应的exe文件,需要执行go install 或者使用 go build -o 路径/可执行文件。
  3. 如果某个文件夹下有多个文件,而你只想编译其中某一个文件,可以在 go build 之后加上文件名,例如 go build a.go;go build 命令默认会编译当前目录下的所有go文件。
  4. 你也可以指定编译输出的文件名。比如,我们可以指定go build -o 可执行文件名,默认情况是你的package名(非main包),或者是第一个源文件的文件名(main包)。
  5. go build 会忽略目录下以”_”或者”.”开头的go文件。
  6. 如果你的源代码针对不同的操作系统需要不同的处理,那么你可以根据不同的操作系统后缀来命名文件。

当代码包中有且仅有一个命令源码文件的时候,在文件夹所在目录中执行 go build 命令,会在该目录下生成一个与目录同名的可执行文件。

// 假设当前文件夹名叫 hello
localhost:hello libin9ioak$ pwd
/Users/libin9ioak/go/src/hello
localhost:hello libin9ioak$ ls
HelloGo.go
localhost:hello libin9ioak$ go build
localhost:hello libin9ioak$ ls
hello   HelloGo.go
localhost:hello 
libin9ioak$
Microsoft Windows [版本 10.0.22621.1778]
(c) Microsoft Corporation。保留所有权利。
D:\GolandProjects\FirstGoProject>color 2
D:\GolandProjects\FirstGoProject>go build
D:\GolandProjects\FirstGoProject>

于是在当前目录直接生成了以当前文件夹为名的可执行文件( 在 Mac 平台下是 Unix executable 文件,在 Windows 平台下是 exe 文件)

但是这种情况下,如果使用 go install 命令,如果 GOPATH 里面只有一个工作区,就会在当前工作区的 bin 目录下生成相应的可执行文件。如果 GOPATH 下有多个工作区,则是在 GOBIN 下生成对应的可执行文件。

localhost:hello libin9ioak$ go install
go install hello: open /usr/local/go/bin/hello: permission denied
localhost:hello libin9ioak$

这个问题是因为它需要创建bin目录,然后把可刚才的可执行文件放进去,而目前我们在gopath下还没有bin目录,那么就需要先创建这个文件,而普通用户没有直接创建文件夹的权限,这个和Go语言的命令是没有关系的。我们可以加上sodu 来执行这个命令,表示使用管理员的身份执行,然后输入密码,那么就可以创建bin这个文件夹了。

再次执行:

localhost:hello libin9ioak$ sudo go install
Password:
localhost:hello libin9ioak$

执行完 go install 会发现可执行文件不见了!去哪里了呢?其实是被移动到了 bin 目录下了(如果 GOPATH 下有多个工作区,就会放在GOBIN 目录下)。

那 go build 和 go install 究竟干了些什么呢?

先来说说 go build。go build 用于编译我们指定的源码文件或代码包以及它们的依赖包。但是注意如果用来编译非命令源码文件,即库源码文件,go build 执行完是不会产生任何结果的。这种情况下,go build 命令只是检查库源码文件的有效性,只会做检查性的编译,而不会输出任何结果文件。

go build 编译命令源码文件,则会在该命令的执行目录中生成一个可执行文件,上面的例子也印证了这个过程。

go build 后面不追加目录路径的话,它就把当前目录作为代码包并进行编译。go build 命令后面如果跟了代码包导入路径作为参数,那么该代码包及其依赖都会被编译。

go build 命令究竟做了些什么呢?我们可以执行-n这个命令来查看:

localhost:hello libin9ioak$ go build -n
#
# hello
#
mkdir -p $WORK/b001/
cat >$WORK/b001/importcfg << 'EOF' # internal
# import config
packagefile fmt=/usr/local/go/pkg/darwin_amd64/fmt.a
packagefile runtime=/usr/local/go/pkg/darwin_amd64/runtime.a
EOF
cd /Users/libin9ioak/go/src/hello
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b001/_pkg_.a -trimpath $WORK/b001 -p main -complete -buildid PXDetO1R1NhLFMK5QGUc/PXDetO1R1NhLFMK5QGUc -goversion go1.12.1 -D "" -importcfg $WORK/b001/importcfg -pack -c=4 ./HelloGo.go
/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/_pkg_.a # internal
cat >$WORK/b001/importcfg.link << 'EOF' # internal
packagefile hello=$WORK/b001/_pkg_.a
...
EOF
mkdir -p $WORK/b001/exe/
cd .
/usr/local/go/pkg/tool/darwin_amd64/link -o $WORK/b001/exe/a.out -importcfg $WORK/b001/importcfg.link -buildmode=exe -buildid=diTh1q6kcbGRIX3aj3mU/PXDetO1R1NhLFMK5QGUc/PXDetO1R1NhLFMK5QGUc/diTh1q6kcbGRIX3aj3mU -extld=clang $WORK/b001/_pkg_.a
/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/exe/a.out # internal
mv $WORK/b001/exe/a.out hello
localhost:hello libin9ioak$

可以看到,执行过程和 go run 大体相同,唯一不同的就是在最后一步,go run 是执行了可执行文件,但是 go build 命令,只是把库源码文件编译了一遍,然后把可执行文件移动到了当前目录的文件夹中。

总结一下如下图:

3. go install

go install 命令是用来编译并安装代码包或者源码文件的。

go install 命令在内部实际上分成了两步操作:第一步是生成结果文件(可执行文件或者.a包),第二步会把编译好的结果移到$GOPATH/pkg或者$GOPATH/bin

可执行文件: 一般是 go install 带main函数的go文件产生的,有函数入口,所有可以直接运行。

.a应用包: 一般是 go install 不包含main函数的go文件产生的,没有函数入口,只能被调用。

go install 用于编译并安装指定的代码包及它们的依赖包。当指定的代码包的依赖包还没有被编译和安装时,该命令会先去处理依赖包。与 go build 命令一样,传给 go install 命令的代码包参数应该以导入路径的形式提供。并且,go build 命令的绝大多数标记也都可以用于

实际上,go install 命令只比 go build 命令多做了一件事,即:安装编译后的结果文件到指定目录。

安装代码包会在当前工作区的 pkg 的平台相关目录下生成归档文件(即 .a 文件)。

安装命令源码文件会在当前工作区的 bin 目录(如果 GOPATH 下有多个工作区,就会放在 GOBIN 目录下)生成可执行文件。

同样,go install 命令如果后面不追加任何参数,它会把当前目录作为代码包并安装。这和 go build 命令是完全一样的。

go install 命令后面如果跟了代码包导入路径作为参数,那么该代码包及其依赖都会被安装。

go install 命令后面如果跟了命令源码文件以及相关库源码文件作为参数的话,只有这些文件会被编译并安装。

go install 命令究竟做了些什么呢?

localhost:hello libin9ioak$ go install -n
#
# hello
#
mkdir -p $WORK/b001/
cat >$WORK/b001/importcfg << 'EOF' # internal
# import config
packagefile fmt=/usr/local/go/pkg/darwin_amd64/fmt.a
packagefile runtime=/usr/local/go/pkg/darwin_amd64/runtime.a
EOF
cd /Users/libin9ioak/go/src/hello
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b001/_pkg_.a -trimpath $WORK/b001 -p main -complete -buildid E1CTs4eXkD5M28s_FQXT/E1CTs4eXkD5M28s_FQXT -goversion go1.12.1 -D "" -importcfg $WORK/b001/importcfg -pack -c=4 ./HelloGo.go
/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/_pkg_.a # internal
cat >$WORK/b001/importcfg.link << 'EOF' # internal
packagefile hello=$WORK/b001/_pkg_.a
packagefile fmt=/usr/local/go/pkg/darwin_amd64/fmt.a
...
EOF
mkdir -p $WORK/b001/exe/
cd .
/usr/local/go/pkg/tool/darwin_amd64/link -o $WORK/b001/exe/a.out -importcfg $WORK/b001/importcfg.link -buildmode=exe -buildid=FJ6kJTmN9rcWcwLhqfiQ/E1CTs4eXkD5M28s_FQXT/E1CTs4eXkD5M28s_FQXT/FJ6kJTmN9rcWcwLhqfiQ -extld=clang $WORK/b001/_pkg_.a
/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/exe/a.out # internal
mkdir -p /usr/local/go/bin/
mv $WORK/b001/exe/a.out /usr/local/go/bin/hello
localhost:hello libin9ioak$

前面几步依旧和 go run 、go build 完全一致,只是最后一步的差别,go install 会把命令源码文件安装到当前工作区的 bin 目录(如果 GOPATH 下有多个工作区,就会放在 GOBIN 目录下)。如果是库源码文件,就会被安装到当前工作区的 pkg 的平台相关目录下。

总结一下如下图:

在安装多个库源码文件时有可能遇到如下的问题:

localhost:hello libin9ioak$  go install envir.go fpath.go ipath.go pnode.go util.go
go install: no install location for .go files listed on command line (GOBIN not set)

而且,在我们为环境变量 GOBIN 设置了正确的值之后,这个错误提示信息仍然会出现。这是因为,只有在安装命令源码文件的时候,命令程序才会将环境变量 GOBIN 的值作为结果文件的存放目录。而在安装库源码文件时,在命令程序内部的代表结果文件存放目录路径的那个变量不会被赋值。最后,命令程序会发现它依然是个无效的空值。所以,命令程序会同样返回一个关于“无安装位置”的错误。这就引出一个结论,我们只能使用安装代码包的方式来安装库源码文件,而不能在 go install 命令罗列并安装它们。另外,go install 命令目前无法接受标记-o以自定义结果文件的存放位置。这也从侧面说明了

go install 命令不支持针对库源码文件的安装操作。

4. go get

go get 命令用于从远程代码仓库(比如 Github )上下载并安装代码包。注意,go get 命令会把当前的代码包下载到 $GOPATH 中的第一个工作区的 src 目录中,并安装。

使用 go get 下载第三方包的时候,依旧会下载到 $GOPATH 的第一个工作空间,而非 vendor 目录。当前工作链中并没有真正意义上的包依赖管理,不过好在有不少第三方工具可选。

如果在 go get 下载过程中加入-d 标记,那么下载操作只会执行下载动作,而不执行安装动作。比如有些非常特殊的代码包在安装过程中需要有特殊的处理,所以我们需要先下载下来,所以就会用到-d 标记。

还有一个很有用的标记是-u标记,加上它可以利用网络来更新已有的代码包及其依赖包。如果已经下载过一个代码包,但是这个代码包又有更新了,那么这时候可以直接用-u标记来更新本地的对应的代码包。如果不加这个-u标记,执行 go get 一个已有的代码包,会发现命令什么都不执行。只有加了-u标记,命令会去执行 git pull 命令拉取最新的代码包的最新版本,下载并安装。

命令 go get 还有一个很值得称道的功能——智能下载。在使用它检出或更新代码包之后,它会寻找与本地已安装 Go 语言的版本号相对应的标签(tag)或分支(branch)。比如,本机安装 Go 语言的版本是1.x,那么 go get 命令会在该代码包的远程仓库中寻找名为 “go1” 的标签或者分支。如果找到指定的标签或者分支,则将本地代码包的版本切换到此标签或者分支。如果没有找到指定的标签或者分支,则将本地代码包的版本切换到主干的最新版本。

go get 常用的一些标记如下:

标记名称 标记描述
-d 让命令程序只执行下载动作,而不执行安装动作。
-f 仅在使用-u标记时才有效。该标记会让命令程序忽略掉对已下载代码包的导入路径的检查。如果下载并安装的代码包所属的项目是你从别人那里 Fork 过来的,那么这样做就尤为重要了。
-fix 让命令程序在下载代码包后先执行修正动作,而后再进行编译和安装。
-insecure 允许命令程序使用非安全的 scheme(如 HTTP )去下载指定的代码包。如果你用的代码仓库(如公司内部的 Gitlab )没有HTTPS 支持,可以添加此标记。请在确定安全的情况下使用它。
-t 让命令程序同时下载并安装指定的代码包中的测试源码文件中依赖的代码包。
-u 让命令利用网络来更新已有代码包及其依赖包。默认情况下,该命令只会从网络上下载本地不存在的代码包,而不会更新已有的代码包。

go get 命令究竟做了些什么呢?我们还是来打印一下每一步的执行过程。

go get 是 Go 语言中一个常用的命令,用于获取、构建和安装远程代码包。它的主要作用是从远程版本控制系统(如 GitHub、GitLab 等)下载并安装指定的 Go 代码包或库。

以下是 go get 命令的一些常见用法和作用:

  1. 下载代码包:通过指定远程代码包的路径,go get 可以自动下载代码包到本地的 GOPATH 目录中。
go get github.com/user/repo
  1. 安装依赖包:go get 可以递归地下载并安装项目所需的所有依赖包。
go get -u github.com/user/repo
  1. 更新代码包:使用 -u 标志可以更新已经下载的代码包到最新版本。
go get -u github.com/user/repo
  1. 安装可执行程序:如果代码包包含可执行程序,go get 会构建并将其安装到 $GOPATH/bin 目录下。
go get github.com/user/repo/cmd/myprogram
  1. 安装到指定目录:可以通过指定 -d 标志来只下载代码包,而不进行安装。可以通过 -o 标志指定下载的代码包放置的目录。
go get -d -o /my/directory github.com/user/repo

需要注意的是,自从 Go 1.16 版本起,默认情况下,go get 命令会使用 Go 模块代替旧的 GOPATH 工作流。它会自动使用 Go 模块管理依赖关系,而不再需要在 GOPATH 中进行下载和安装。

总结一下如下图:

5. 其他命令

go clean

go clean 命令是用来移除当前源码包里面编译生成的文件,这些文件包括

  • _obj/ 旧的object目录,由Makefiles遗留
  • _test/ 旧的test目录,由Makefiles遗留
  • _testmain.go 旧的gotest文件,由Makefiles遗留
  • test.out 旧的test记录,由Makefiles遗留
  • build.out 旧的test记录,由Makefiles遗留
  • *.[568ao] object文件,由Makefiles遗留
  • DIR(.exe) 由 go build 产生
  • DIR.test(.exe) 由 go test -c 产生
  • MAINFILE(.exe) 由 go build MAINFILE.go产生

go fmt

go fmt 命令主要是用来帮你格式化所写好的代码文件。

比如我们写了一个格式很糟糕的 test.go 文件,我们只需要使用 fmt go test.go 命令,就可以让go帮我们格式化我们的代码文件。但是我们一般很少使用这个命令,因为我们的开发工具一般都带有保存时自动格式化功能,这个功能底层其实就是调用了 go fmt 命令而已。

使用go fmt命令,更多时候是用gofmt,而且需要参数-w,否则格式化结果不会写入文件。gofmt -w src,可以格式化整个项目。

go test

go test 命令,会自动读取源码目录下面名为*_test.go的文件,生成并运行测试用的可执行文件。默认的情况下,不需要任何的参数,它会自动把你源码包下面所有test文件测试完毕,当然你也可以带上参数,详情请参考go help testflag

go doc

go doc 命令其实就是一个很强大的文档工具。

如何查看相应package的文档呢? 例如builtin包,那么执行go doc builtin;如果是http包,那么执行go doc net/http;查看某一个包里面的函数,那么执行go doc fmt Printf;也可以查看相应的代码,执行go doc -src fmt Printf;

# 查看net/http包
localhost:hello libin9ioak$ go doc net/http
# 查看time包
localhost:hello libin9ioak$ go doc time
# 查看某个包里的指定函数
localhost:hello libin9ioak$ go doc fmt Printf

通过命令在命令行执行 go doc -http=:端口号,比如godoc -http=:8080。然后在浏览器中打开127.0.0.1:8080,你将会看到一个golang.org的本地copy版本,通过它你可以查询pkg文档等其它内容。如果你设置了GOPATH,在pkg分类下,不但会列出标准包的文档,还会列出你本地GOPATH中所有项目的相关文档,这对于经常被限制访问的用户来说是一个不错的选择。

localhost:hello libin9ioak$ godoc -http=:9527

go fix 用来修复以前老版本的代码到新版本,例如go1之前老版本的代码转化到go1

go version 查看go当前的版本

go env 查看当前go的环境变量

go list 列出当前全部安装的package

编码规范

本规范旨在为日常Go项目开发提供一个代码的规范指导,方便团队形成一个统一的代码风格,提高代码的可读性,规范性和统一性。本规范将从命名规范,注释规范,代码风格和 Go 语言提供的常用的工具这几个方面做一个说明。该规范参考了 go 语言官方代码的风格制定。

一、 命名规范

命名是代码规范中很重要的一部分,统一的命名规则有利于提高的代码的可读性,好的命名仅仅通过命名就可以获取到足够多的信息。

Go在命名时以字母a到Z或a到Z或下划线开头,后面跟着零或更多的字母、下划线和数字(0到9)。Go不允许在命名时中使用@、$和%等标点符号。Go是一种区分大小写的编程语言。因此,Manpower和manpower是两个不同的命名。

  1. 当命名(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);
  2. 命名如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 private )

1、包命名:package

保持package的名字和目录保持一致,尽量采取有意义的包名,简短,有意义,尽量和标准库不要冲突。包名应该为小写单词,不要使用下划线或者混合大小写。

package demo
package main

2、 文件命名

尽量采取有意义的文件名,简短,有意义,应该为小写单词,使用下划线分隔各个单词。

my_test.go

3、 结构体命名

  • 采用驼峰命名法,首字母根据访问控制大写或者小写
  • struct 申明和初始化格式采用多行,例如下面:
// 多行申明
type User struct{
    Username  string
    Email     string
}
// 多行初始化
u := User{
    Username: "astaxie",
    Email:    "astaxie@gmail.com",
}

4、 接口命名

  • 命名规则基本和上面的结构体类型
  • 单个函数的结构名以 “er” 作为后缀,例如 Reader , Writer 。
type Reader interface {
        Read(p []byte) (n int, err error)
}

5、变量命名

  • 和结构体类似,变量名称一般遵循驼峰法,首字母根据访问控制原则大写或者小写,但遇到特有名词时,需要遵循以下规则:
  • 如果变量为私有,且特有名词为首个单词,则使用小写,如 apiClient
  • 其它情况都应当使用该名词原有的写法,如 APIClient、repoID、UserID
  • 错误示例:UrlArray,应该写成 urlArray 或者 URLArray
  • 若变量类型为 bool 类型,则名称应以 Has, Is, Can 或 Allow 开头
var isExist bool
var hasConflict bool
var canManage bool
var allowGitHook bool

6、常量命名

常量均需使用全部大写字母组成,并使用下划线分词

const APP_VER = "1.0"

如果是枚举类型的常量,需要先创建相应类型:

type Scheme string
const (
    HTTP  Scheme = "http"
    HTTPS Scheme = "https"
)

7、 关键字

Go 语言一共有 25 个关键字。

下面的列表显示了Go中的保留字。这些保留字不能用作常量或变量或任何其他标识符名称。

以下是 Go 语言中的关键字列表:

关键字 描述
break 终止当前循环或 switch 语句的执行
default switch 语句中的默认情况
func 声明一个函数或方法
interface 声明一个接口类型
select 用于在多个通信操作中进行选择
case switch 语句中的一个情况
defer 延迟执行一个函数或方法的调用
go 启动一个并发 goroutine
map 声明并创建一个映射(键值对集合)
struct 声明一个结构体类型
chan 声明一个通道
else if 语句中的否定条件分支
goto 无条件跳转到指定标签
package 声明一个包
switch 多条件选择语句
const 声明一个常量
fallthrough 在 switch 语句中,继续执行下一个 case 分支
if 条件语句,用于根据条件执行代码
range 用于迭代数组、切片、映射或通道中的元素
type 声明一个自定义类型
continue 继续当前循环的下一次迭代
for 循环语句,用于重复执行代码块
import 导入一个包
return 从函数中返回一个值
var 声明一个变量

这些关键字在 Go 语言中具有特殊含义,用于定义程序的结构、控制流程和数据类型等。

二、注释

Go提供C风格的/* */块注释和C ++风格的//行注释。行注释是常态;块注释主要显示为包注释,但在表达式中很有用或禁用大量代码。

  • 单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释
  • 多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段

go 语言自带的 godoc 工具可以根据注释生成文档,生成可以自动生成对应的网站( golang.org 就是使用 godoc 工具直接生成的),注释的质量决定了生成的文档的质量。每个包都应该有一个包注释,在package子句之前有一个块注释。对于多文件包,包注释只需要存在于一个文件中,任何一个都可以。包评论应该介绍包,并提供与整个包相关的信息。它将首先出现在godoc页面上,并应设置下面的详细文档。

详细的如何写注释可以

参考:http://golang.org/doc/effective_go.html#commentary

1、包注释

每个包都应该有一个包注释,一个位于package子句之前的块注释或行注释。包如果有多个go文件,只需要出现在一个go文件中(一般是和包同名的文件)即可。 包注释应该包含下面基本信息(请严格按照这个顺序,简介,创建人,创建时间):

  • 包的基本简介(包名,简介)
  • 创建者,格式: 创建人: rtx 名
  • 创建时间,格式:创建时间: yyyyMMdd

例如 util 包的注释示例如下

// util 包, 该包包含了项目共用的一些常量,封装了项目中一些共用函数。
// 创建人: hanru
// 创建时间: 20190419

2、结构(接口)注释

每个自定义的结构体或者接口都应该有注释说明,该注释对结构进行简要介绍,放在结构体定义的前一行,格式为: 结构体名, 结构体说明。同时结构体内的每个成员变量都要有说明,该说明放在成员变量的后面(注意对齐),实例如下:

// User , 用户对象,定义了用户的基础信息
type User struct{
    Username  string // 用户名
    Email     string // 邮箱
}

3、函数(方法)注释

每个函数,或者方法(结构体或者接口下的函数称为方法)都应该有注释说明,函数的注释应该包括三个方面(严格按照此顺序撰写):

  • 简要说明,格式说明:以函数名开头,“,”分隔说明部分
  • 参数列表:每行一个参数,参数名开头,“,”分隔说明部分
  • 返回值: 每行一个返回值

示例如下:

// NewtAttrModel , 属性数据层操作类的工厂方法
// 参数:
//      ctx : 上下文信息
// 返回值:
//      属性操作类指针
func NewAttrModel(ctx *common.Context) *AttrModel {
}

4、代码逻辑注释

对于一些关键位置的代码逻辑,或者局部较为复杂的逻辑,需要有相应的逻辑说明,方便其他开发者阅读该段代码,实例如下:

// 从 Redis 中批量读取属性,对于没有读取到的 id , 记录到一个数组里面,准备从 DB 中读取
xxxxx
xxxxxxx
xxxxxxx

5、注释风格

统一使用中文注释,对于中英文字符之间严格使用空格分隔, 这个不仅仅是中文和英文之间,英文和中文标点之间也都要使用空格分隔,例如:

// 从 Redis 中批量读取属性,对于没有读取到的 id , 记录到一个数组里面,准备从 DB 中读取

上面 Redis 、 id 、 DB 和其他中文字符之间都是用了空格分隔。

  • 建议全部使用单行注释
  • 和代码的规范一样,单行注释不要过长,禁止超过 120 字符。

三、代码风格

1、缩进和折行

  • 缩进直接使用 gofmt 工具格式化即可(gofmt 是使用 tab 缩进的);
  • 折行方面,一行最长不超过120个字符,超过的请使用换行展示,尽量保持格式优雅。

我们使用Goland开发工具,可以直接使用快捷键:ctrl+alt+L,即可。

2、语句的结尾

Go语言中是不需要类似于Java需要冒号结尾,默认一行就是一条数据

如果你打算将多个语句写在同一行,它们则必须使用 ;

3、括号和空格

括号和空格方面,也可以直接使用 gofmt 工具格式化(go 会强制左大括号不换行,换行会报语法错误),所有的运算符和操作数之间要留空格。

// 正确的方式
if a > 0 {
} 
// 错误的方式
if a>0  // a ,0 和 > 之间应该空格
{       // 左大括号不可以换行,会报语法错误
}

4、import 规范

import在多行的情况下,goimports会自动帮你格式化,但是我们这里还是规范一下import的一些规范,如果你在一个文件里面引入了一个package,还是建议采用如下格式:

import (
    "fmt"
)

如果你的包引入了三种类型的包,标准库包,程序内部包,第三方包,建议采用如下方式进行组织你的包:

import (
    "encoding/json"
    "strings"
    "myproject/models"
    "myproject/controller"
    "myproject/utils"
    "github.com/astaxie/beego"
    "github.com/go-sql-driver/mysql"
)

有顺序的引入包,不同的类型采用空格分离,第一种实标准库,第二是项目包,第三是第三方包。

在项目中不要使用相对路径引入包:

// 这是不好的导入
import “../net”
// 这是正确的做法
import “github.com/repo/proj/src/net”

但是如果是引入本项目中的其他包,最好使用相对路径。

5、错误处理

  • 错误处理的原则就是不能丢弃任何有返回err的调用,不要使用 _ 丢弃,必须全部处理。接收到错误,要么返回err,或者使用log记录下来
  • 尽早return:一旦有错误发生,马上返回
  • 尽量不要使用panic,除非你知道你在做什么
  • 错误描述如果是英文必须为小写,不需要标点结尾
  • 采用独立的错误流进行处理
// 错误写法
if err != nil {
    // error handling
} else {
    // normal code
}
// 正确写法
if err != nil {
    // error handling
    return // or continue, etc.
}
// normal code

6、测试

单元测试文件名命名规范为 example_test.go

测试用例的函数名称必须以 Test 开头,例如:TestExample

每个重要的函数都要首先编写测试用例,测试用例和正规代码一起提交方便进行回归测试

四、常用工具

上面提到了很过规范, go 语言本身在代码规范性这方面也做了很多努力,很多限制都是强制语法要求,例如左大括号不换行,引用的包或者定义的变量不使用会报错,此外 go 还是提供了很多好用的工具帮助我们进行代码的规范,

gofmt

大部分的格式问题可以通过gofmt解决, gofmt 自动格式化代码,保证所有的 go 代码与官方推荐的格式保持一致,于是所有格式有关问题,都以 gofmt 的结果为准。

goimport

我们强烈建议使用 goimport ,该工具在 gofmt 的基础上增加了自动删除和引入包.

go get golang.org/x/tools/cmd/goimports

go vet

vet工具可以帮我们静态分析我们的源码存在的各种问题,例如多余的代码,提前return的逻辑,struct的tag是否符合标准等。

go get golang.org/x/tools/cmd/vet

使用如下:

go vet .

学习总结:

通过本文的学习,我们深入了解了Go语言的执行原理和常用命令,包括go run、go build、go install、go get等。同时,我们也学习了Go编码规范的各个方面,包括命名规范、注释规范和代码风格等。此外,我们还了解了一些常用的工具,如错误处理和测试工具等。通过遵循规范和使用工具,我们可以提高开发效率和代码质量,更好地应用Go语言进行开发。

希望本文对读者在学习和使用Go语言过程中有所帮助,让我们一起深入探索Go语言的魅力!

结语

通过今天的学习,您已经踏上了Golang的学习之旅。在未来的日子里,您将探索Golang的各个方面,从基础概念到高级技巧,从实际应用到性能优化。

学习一门编程语言是一个持续的过程,每一天都是您向Golang的精通迈进的重要一步。我鼓励您坚持每天学习,保持热情和好奇心,解决挑战并享受成功的喜悦。

在您的学习旅程中,不要忘记参与社区和与其他Golang开发者交流。分享您的见解和经验,向他人学习,并在开源项目或实际应用中展示您的技能。

如果您在学习过程中遇到困难或有任何问题,不要犹豫向社区和专家寻求帮助。持续学习,勇敢探索,您将在Golang领域取得令人瞩目的成就。

最后,感谢您的阅读和支持!祝愿您在未来的每一天中都能够成为一名精通Golang的开发者!

期待听到您在学习过程中的进展和成就。如果您需要进一步的帮助,请随时告诉我。祝您在学习Golang的旅程中取得巨大成功!

如果您在学习过程中有任何疑惑,请点击下方名片,带您一对一快速入门 Go语言 的世界 ~

目录
相关文章
|
19小时前
|
安全 测试技术 Go
Golang深入浅出之-Go语言单元测试与基准测试:testing包详解
【4月更文挑战第27天】Go语言的`testing`包是单元测试和基准测试的核心,简化了测试流程并鼓励编写高质量测试代码。本文介绍了测试文件命名规范、常用断言方法,以及如何进行基准测试。同时,讨论了测试中常见的问题,如状态干扰、并发同步、依赖外部服务和测试覆盖率低,并提出了相应的避免策略,包括使用`t.Cleanup`、`t.Parallel()`、模拟对象和检查覆盖率。良好的测试实践能提升代码质量和项目稳定性。
6 1
|
19小时前
|
运维 监控 Go
Golang深入浅出之-Go语言中的日志记录:log与logrus库
【4月更文挑战第27天】本文比较了Go语言中标准库`log`与第三方库`logrus`的日志功能。`log`简单但不支持日志级别配置和多样化格式,而`logrus`提供更丰富的功能,如日志级别控制、自定义格式和钩子。文章指出了使用`logrus`时可能遇到的问题,如全局logger滥用、日志级别设置不当和过度依赖字段,并给出了避免错误的建议,强调理解日志级别、合理利用结构化日志、模块化日志管理和定期审查日志配置的重要性。通过这些实践,开发者能提高应用监控和故障排查能力。
8 1
|
19小时前
|
安全 Go
Golang深入浅出之-Go语言标准库中的文件读写:io/ioutil包
【4月更文挑战第27天】Go语言的`io/ioutil`包提供简单文件读写,适合小文件操作。本文聚焦`ReadFile`和`WriteFile`函数,讨论错误处理、文件权限、大文件处理和编码问题。避免错误的关键在于检查错误、设置合适权限、采用流式读写及处理编码。遵循这些最佳实践能提升代码稳定性。
5 0
|
1天前
|
安全 Unix Go
Golang深入浅出之-Go语言中的时间与日期处理:time包详解
【4月更文挑战第26天】Go语言的`time`包提供处理日期和时间的功能,包括`time.Time`类型、时间戳、格式化与解析。本文讨论了核心概念、常见问题(如时区处理、格式字符串混淆、超时控制和并发安全)及解决方法。推荐使用`time.LoadLocation`管理时区,熟悉时间格式规则,用`context`精确控制超时,并注意并发安全。文中通过代码示例展示了如何获取格式化时间、计算时间差以及创建定时任务。学习和应用这些知识可提高程序的健壮性和准确性。
15 2
|
1天前
|
XML JSON Go
Golang深入浅出之-XML处理在Go语言中的实现:encoding/xml包
【4月更文挑战第26天】Go语言的`encoding/xml`库提供XML处理,包括序列化和反序列化。本文讨论了XML处理的基础,如`xml.Marshal`和`xml.Unmarshal`函数,以及常见问题和易错点,如标签命名、结构体嵌套、omitempty标签和命名空间。建议遵循标签命名规则,正确处理嵌套和属性,谨慎使用omitempty,以及理解并有效利用命名空间。文中还给出了基础示例和处理XML属性的代码示例,帮助读者掌握XML处理技巧。
12 1
Golang深入浅出之-XML处理在Go语言中的实现:encoding/xml包
|
1天前
|
JSON JavaScript 前端开发
Golang深入浅出之-Go语言JSON处理:编码与解码实战
【4月更文挑战第26天】本文探讨了Go语言中处理JSON的常见问题及解决策略。通过`json.Marshal`和`json.Unmarshal`进行编码和解码,同时指出结构体标签、时间处理、omitempty使用及数组/切片区别等易错点。建议正确使用结构体标签,自定义处理`time.Time`,明智选择omitempty,并理解数组与切片差异。文中提供基础示例及时间类型处理的实战代码,帮助读者掌握JSON操作。
12 1
Golang深入浅出之-Go语言JSON处理:编码与解码实战
|
1天前
|
安全 Go 开发者
Golang深入浅出之-Go语言模板(text/template):动态生成HTML
【4月更文挑战第25天】Go语言的`text/template`和`html/template`库提供动态HTML生成。本文介绍了模板基础,如基本语法和数据绑定,以及常见问题和易错点,如忘记转义、未初始化变量、复杂逻辑处理和错误处理。建议使用`html/template`防止XSS攻击,初始化数据结构,分离业务逻辑,并严谨处理错误。示例展示了条件判断和循环结构。通过遵循最佳实践,开发者能更安全、高效地生成HTML。
7 0
|
2天前
|
中间件 Go API
Golang深入浅出之-Go语言标准库net/http:构建Web服务器
【4月更文挑战第25天】Go语言的`net/http`包是构建高性能Web服务器的核心,提供创建服务器和发起请求的功能。本文讨论了使用中的常见问题和解决方案,包括:使用第三方路由库改进路由设计、引入中间件处理通用逻辑、设置合适的超时和连接管理以防止资源泄露。通过基础服务器和中间件的代码示例,展示了如何有效运用`net/http`包。掌握这些最佳实践,有助于开发出高效、易维护的Web服务。
15 1
|
3天前
|
数据管理 Go 开发者
Golang深入浅出之-Go语言上下文(context)包:处理取消与超时
【4月更文挑战第25天】Go语言中的`context`包在并发、网络请求和长任务中至关重要,提供取消、截止时间和元数据管理。本文探讨`context`基础,如`Background()`、`TODO()`、`WithCancel()`、`WithDeadline()`和`WithTimeout()`。常见问题包括不当传递、过度使用`Background()`和`TODO()`以及忽略错误处理。通过取消和超时示例,强调正确传递上下文、处理取消错误和设置超时以提高应用健壮性和响应性。正确使用`context`是构建稳定高效Go应用的关键。
12 1
|
3天前
|
Unix Linux Go
Golang深入浅出之-信号(Signals)处理与优雅退出Go程序
【4月更文挑战第25天】Go语言中的信号处理关乎程序对外部事件的响应,尤其是优雅地终止进程。本文介绍了信号基础,如SIGINT、SIGTERM等常见信号,以及处理流程:注册处理器、等待信号、执行清理和优雅退出。强调了三个易错点及避免方法,并提供实战代码示例展示如何监听和响应信号。信号处理应简洁高效,确保程序健壮性和用户体验。
11 0