Go语言环境安装和程序结构
1、Go环境安装
Go安装包下载地址为:
https://golang.org/dl/
https://golang.google.cn/dl/
1.1 Windows下的安装
Windows 下可以使用.msi
后缀的安装包来安装,我这里下载的安装包是 go1.18.4.windows-amd64.msi
,双
击安装包,配置安装路径,然后点击下一步进行安装。
安装完成后的目录结构:
这个目录的结构遵守 GOPATH 规则,目录中各个文件夹的含义如下表所示:
api
:每个版本的api变更差异
bin
:源码包编译出的编译器(go)、文档工具(godoc)、格式化工具(gofmt)
doc
: 英文版的 Go 文档
lib
: 引用的一些库文件
misc
: 杂项用途的文件,例如 Android平台的编译、git 的提交钩子等
pkg
: 平台编译好的中间文件
src
: 标准库的源码
test
:测试用例
安装完成后使用 go version
查看版本:
# 进入cmd执行下面命令
$ go version
go version go1.18.4 windows/amd64
1.2 Linux下的安装
以下介绍在Linux系统下使用源码进行安装:
1、下载二进制包:go1.18.4.linux-amd64.tar.gz
。
2、将下载的二进制包上传至 /home/zhangshixing
目录下并且解压。
$ cd /home/zhangshixing
# 解压后的目录是go
$ tar -xvf go1.18.4.linux-amd64.tar.gz
3、将 /home/zhangshixing/go/bin
目录添加至 PATH 环境变量:
$ export PATH=$PATH:/home/zhangshixing/go/bin
以上只能暂时添加 PATH,关闭终端下次再登录就没有了。
我们可以编辑 ~/.bash_profile
或者 /etc/profile
,并将以下命令添加该文件的末尾,这样就永久生效了:
$ vim /etc/profile
# 添加如下内容
export PATH=$PATH:/home/zhangshixing/go/bin
添加后需要执行:
$ source ~/.bash_profile
或
$ source /etc/profile
安装完成后使用 go version
查看版本:
$ go version
go version go1.18.4 linux/amd64
1.3 包管理环境配置
go 开发需要配置的环境变量如下:
# 以Linux下的配置为例,Windows下的配置一样,只是配置方式不同
# 为了永久生效将下面的变量配置在~/.bash_profile或者/etc/profile文件中
export PATH=$PATH:/home/zhangshixing/go/bin
export GOROOT="/home/zhangshixing/go"
export GOPATH="/home/zhangshixing/go_work_space"
export GOBIN="/home/zhangshixing/go/bin"
export GO111MODULE=on
export GOPROXY=https://goproxy.cn,direct
export GOMODCACHE="/home/zhangshixing/go_work_space/pkg/mod"
四个变量 GOPATH
、PATH
、GOROOT
、GOBIN
的说明:
GOROOT
就是 go 的安装路径;GOPATH
就是go的工作目录;PATH
是go安装路径下的bin目录。GOBIN
是go安装路径下的bin目录。
1.4 系统环境变量配置文件的说明
# bashrc对系统所有用户有效,profile对当前用户有效
vim ~/.bashrc
vim ~/profile
# 更新环境变量,及时生效
source ~/.bashrc
source ~/profile
1.5 工作目录
$GOPATH
环境变量所指定的目录称为 Go 的工作目录, $GOPATH
可以配置为多个目录。
工作目录有相同的目录结构,内含三个子目录:
$GOPATH/---|
|-----src
|-----pkg
|-----bin
src 是工程的源码所在目录,一般 src下的第一层目录是工程根目录,工程根目录一般采用公司的域名+工程名或
用户名的格式,比如常 GitHub 上的工程源码组织形式:
# 如下都是工程根目录
$GOPATH/src/github.com/github/
$GOPATH/src/github.com/golang/
工程根目录才是工程各个项目的目录,项目目录下可以是其源代码文件和各种包的源码,这是一种推荐的代码组织
形式。举 个具体的示例 :$GOPATH/src/github.com/github/gh-ost
,$GOPATH/src/github.com/github/
是 GitHub
工程根目录, gh-ost
是具体的项目目录, gh-ost
内是该项目的源代码和包。
$GOPATH
环境变量可以配置多个目录,使用 go
下载第三方的包时,会将包下载到$GOPATH
的第一个目录里
面,很多人喜欢在 GOPATH
里面配置两个目,第一个目录专于下载第三方的包,第二个目录用于内部工程目
录,这也是一种解决办法,避免外部包和自身工程代码互相干扰。但官方还是推荐使用仅包含一个目录的
GOPATH
, 结合官方的包管理工具来管理。
1.6 交叉编译
Go 编译工具 1.5 后版本中完全使用Go语言重写, Go编译器内置交叉编译的功能,只需要设置 GOOS
和GOARCH
变量就可以轻松进行交叉编译。
Go交叉编译,涉及到几个环境变量的设置:GOARCH
、GOOS
和CGO_ENABLED
。
GOARCH
:编译目标平台的硬件体系架构(amd64, 386, arm, ppc64等)。
GOOS
:编译目标平台上的操作系统(darwin, freebsd, linux, windows)。
CGO_ENABLED
:代表是否开启CGO,1表示开启,0表示禁用。由于CGO不能支持交叉编译,所以需要禁用。
下面看一个具体的示例:
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Printf("OS:%s\nArchitecture:%s\n", runtime.GOOS, runtime.GOARCH)
}
Mac 下编译 Linux 和 Windows 64位可执行程序:
export CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
export CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
Linux 下编译 Mac 和 Windows 64位可执行程序
export CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go
export CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
Windows 下编译 Mac 和 Linux 64位可执行程序
SET CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go
SET CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
其他平台或32位系统类似,这里就不再赘述。
1.7 Go项目初始化
一些Go标准库强依赖于 go mod 命令。
(1)、go mod init module_name
初始化当前目录中的新模块,会生成 go.mod 文件。
(2)、go mod tidy
会添加缺失的依赖,或者移除未被使用的依赖。一般来说,我们建议在创建项目之后,或者在添加了新的依赖以
后,执行该命令。
2、Go语言结构
在我们开始学习 Go 编程语言的基础构建模块前,让我们先来了解 Go 语言最简单程序的结构。
2.1 Go Hello World 实例
Go 语言的基础组成有以下几个部分:
- 包声明
- 引入包
- 函数
- 变量
- 语句 & 表达式
- 注释
Hello World
代码:
package main
import "fmt"
func main() {
/* 这是我的第一个简单的程序 */
fmt.Println("Hello, World!")
}
让我们来看下以上程序的各个部分:
1、第一行代码
package main
定义了包名,你必须在源文件中非注释的第一行指明这个文件属于哪个包,包名一般和所属的目录同名。
package main
表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为
main
的包。
2、下一行
import "fmt"
告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。
3、下一行
func main()
是程序开始执行的函数,main
函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有
init()
函数则会先执行该函数)。
4、下一行
/*...*/
是注释,在程序执行时将被忽略。单行注释是最常见的注释形式,你可以在任何地方使用以
//
开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。
5、下一行
fmt.Println(...)
可以将字符串输出到控制台,并在最后自动增加换行字符\n
。使用
fmt.Print("hello, world\n")
可以得到相同的结果。Println
这两个函数也支持使用变量,如:
fmt.Println(arr)
。如果没有特别指定,它们会以默认的打印格式将变量arr
输出到控制台。
6、当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:
Group1
,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导
出(像面向对象语言中的
public
);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的
protected
)。
2.2 执行 Go 程序
让我们来编写 Go 代码并执行它:
$ go run helloworld.go
Hello, World!
我们还可以使用 go build
命令来生成二进制文件:
$ go build hello.go
# 在Linux下会生成helloworld可执行文件
# 在Windows下回生成helloworld.exe可执行文件
# 可以像执行可执行文件一样单独执行
需要注意的是 {
不能单独放在一行,所以以下代码在运行时会产生错误:
package main
import "fmt"
func main()
{
fmt.Println("Hello, World!")
}
2.3 关于包
golang使用包package
来管理定义模块,可以使用import
关键字来导入使用。
-
如果导入的是go自带的包,则会去安装目录
$GOROOT/src
按包路径加载,如fmt包 -
如果是我们go get安装或自定义的包,则会去
$GOPATH/src
下加载
package的存放位置是以$GOPATH/src
作为根目录,然后灵活的按照目录去组织,且包名需与最后一级目录名一
致。例如我们自定义baz
包,包模块的存放位置则为$GOPATH/src/foo/bar/baz
, baz
包的源码都存放在此目
录下,foo/bar/baz
则作为包路径被import载入。
我们需要规范的将baz包中源码的package定义为baz
,就定义好一个可import载入的的包了。
关于包,根据本地测试得出以下几点:
-
文件名与包名没有直接关系,不一定要将文件名与包名定成同一个。
-
文件夹名与包名没有直接关系,并非需要一致。
-
同一个文件夹下的文件只能有一个包名,否则编译报错。
package demo
的代码:
# 目录结构
[root@zsx src]# tree package_demo/
package_demo/
├── go.mod
├── math_func
│ ├── math1.go
│ └── math2.go
└── math_main
└── test.go
package main
import (
"fmt"
"proj/math_func"
)
func main(){
// 2
fmt.Println(mathclass.Add(1,1))
// 0
fmt.Println(mathclass.Sub(1,1))
}
package mathclass
func Add(x, y int) int {
return x + y
}
package mathclass
func Sub(x, y int) int {
return x - y
}
Go语言是使用包来组织源代码的,并实现命名空间的管理。任何源代码文件必须属于某个包。源码文件的第一行
有效代码必须是 package pacakgeName
语句,通过该语句声明自己所在的包。
2.3.1 基本概念
Go语言的包借助了目录树的组织形式,一般包的名称就是其源文件所在目录的名称,虽然Go没有强制包名必须和
其所在的目录名同名,但还是建议包名和所在目录同名,这样结构更清晰。包可以定义在很深的目录中,包的定义
是不包括目录路径的,但是包的引用 一般是全路径引用。比如在$GOPATH/src/a/b/
下定义一个包c,在包c的源
码中只需要声明为package c
,而不是声明为 package a/b/c
,但是在import
包c时,需要带上路径
import a/b/c
。包的引用有两种形式,后面会详细介绍。
包的习惯用法:
-
包名一般是小写的,使用一个简短的命名。
-
包名一般要和所在的目录同名。
-
一般放到公司的域名目录下,这样能保证包名的唯一性,便于共享代码。比如个人的GitHub项目的包一般放
在
$GOPATH/src/github.com/userName/projectName
目录下。
2.3.2 包引用
标准包的源码位于$GOROOT/src /
下面,标准包可以直接引 。自定义的包和第三方包的源码必须放到
$GOPATH/src
目录下才能被引用。
包引用路径:
包的引用路径有两种写法, 一种是全路径,另一种是相对路径。
全路径引用
包的绝对路径就是GOROOT/src
或$GOPATH/src
后面包的源码的全路径,比如下面的包引用:
import "lab/test"
import "database/sql/driver"
import "database/sql"
test包是自定义的包,其源码位于$GOPATH/src/lab/test
目录下; sql和driver包的源码分别位于
$GOROOT/src/database/sql
和$GOROOT/src/database/sql/driver
下。
相对路径引用
相对路径只能用于引用$GOPATH下的包,标准包的引用只能使用全路径引用。比如下面两个包:包a的路径是
$GOPATH/src/lab/a
,包b的源码路径为$GOPATH/src/lab/b
,假设b引用了a包,则可以使用相对路径引用方
式。示例如下:
// 相对路径引用
import "../a"
// 全路径引用
import "lab/a"
包引用格式
包引用有四种引用格式,为叙述方便,我们以 fmt 标准库为例进行说明。
- 标准引用方式如下
import "fmt"
此时可以用 fmt. 作为前缀引用包内可导出元素,这是常用的一种方式。
- 别名引用方式如下
import F "fmt"
此时相当于给包 fmt 起了个别名 F ,用 F. 代替标准的 fmt 作为前缀引用 fmt 包内可导出元素。
- 省略方式如下
import . "fmt"
此时相当于把包 fmt 的命名空间直接合并到当前程序的命名空间中,使用 fmt 包内可导出元素可以不用前缀
fmt.,直接引用。示例如下:
package main
import . "fmt"
func main() {
// 不需要加前级fmt.
Println("hello,world!")
}
- 仅执行包初始化init函数
使用标准格式引用包,但是代码中却没有使用包,编译器会报错。如果包中有 init 初始化函数,则通过
import _ “packageName” 这种方式引用包,仅执行包的初始化函数,即使包没有 init 初始化函数,也不会
引发编译器报错。示例如下:
import _ "fmt"
一个包可以有多个 init 函数,包加载会执行全部的 init 函数,但并不能保证执行顺序,所以不建议在一个包中
放入多个 init 函数,将需要初始化的逻辑放到 init 函数里面。
2.4 Go语言常用命令
命令 | 说明 |
---|---|
go env | 用于打印Go语言的环境信息 |
go run | 命令可以编译并运行命令源码文件 |
go get | 可以根据要求和实际情况从互联网上下载或更新指定的代码包及其依赖包,并对它们进行编译和安装 |
go build | 命令用于编译我们指定的源码文件或代码包以及它们的依赖包 |
go install | 用于编译并安装指定的代码包及它们的依赖包 |
go clean | 命令会删除掉执行其它命令时产生的一些文件和目录 |
go doc | 命令可以打印附于Go语言程序实体上的文档。我们可以通过把程序实体的标识符作为该命令的参数来达到查看其文档的目的 |
go test | 命令用于对Go语言编写的程序进行测试 |
go list | 命令的作用是列出指定的代码包的信息 |
go fix | 会把指定代码包的所有Go语言源码文件中的旧版本代码修正为新版本的代码 |
go vet | 是一个用于检查Go语言源码中静态错误的简单工具 |
go tool pprof | 命令来交互式的访问概要文件的内容 |
go tool cgo | 这个工具可以使我们创建能够调用C语言代码的Go语言源码文件 |