写在前面
开一个新坑:从零开始学习Golang语言,使用的IDE是Goland。在本系列中,博主将持续发布自己学习golang的笔记。由于博主也是零基础学习golang语言,文中如有不对之处,还望不吝赐教。随着学习的深入,博主也会不断回顾之前的文章,不断更正自己的笔记,希望我们能够一起进步。💪
Go语言背景
Go(又称 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 开发的一种静态强类型、编译型语言。Go 语言语法与 C 相近,但功能上有:内存安全,GC(垃圾回收),结构形态及 CSP-style 并发计算。
Go语言相关学习网站:
- Go官网:https://golang.google.cn/
- Go语言圣经:The Go Programming Language
- GO中文文档:https://www.topgoer.com/
搭建开发环境
安装Golang
在Go官网下载安装包:
下载好了安装包,点击启动执行,接下来的步骤就是按导航提示一步步操作即可。有一点要注意的是,GO默认安装在C:\GO
,如果要修改默认安装路径,在见到如下界面时重新选择。
我将其安装在了D:\Program Files\Go\
,这个路径就是后面提到的GOROOT路径(重要),选好之后点Next
。
最后点Finish
,这样,Go语言开发环境就安装完成了。
配置环境变量
在安装完golang后,还需了解三个环境变量,分别是GOROOT
、GOPATH
、PATH
。下面来分别介绍一下它们的作用
GOROOT
:GO安装的根目录。PATH
:各个操作系统都存在的环境变量,用于指定系统可执行命令的默认查找路径。GOPATH
:用来设置工作目录,即编写代码的地方。包也都是从GOPATH
设置的路径中寻找。
配置系统变量GOROOT
,变量名为GO_HOME
,变量值为之前填入的安装路径,我的为D:\Program Files\Go\
配置系统变量Path
,添加环境变量,值为之前填入的安装路径中的二进制bin
文件夹,我的为D:\Program Files\Go\bin
配置用户变量GOPATH
,变量名为GOPATH
,变量值可以暂时设置为任意目录,我设置的为D:\Code\go
,因为后面我们使用Goland
这个IDE来创建项目,为了使每个项目相互隔离,使用不同的包,我们需要为每个项目设置不同的工作目录。
这个时候,打开cmd
,输入 go versioin
就会出来当前安装的Go语言环境版本。我安装的版本为go1.17.6
到此,Go语言环境就安装完成了🎉
Goland创建项目并运行
Goland下载地址,按照引导安装非常简单,不做赘述。
安装完成后点New Project
,创建新项目
配置项目地址,我这里设置为D:\Code\GolandProjects\TestProject
配置代理,我这里设置为GOPROXY=https://goproxy.cn
,GOPROXY
是Go语言官方提供的一种通过中间代理商来为用户提供包下载服务的方式。
配置GOPATH
,设置为之前填写的项目地址,取消索引整个GOPATH
接下来,我们配置一下项目的目录结构:新建三个文件夹bin
、pkg
、src
,创建go.mod
包管理文件
bin
文件目录:用于存放编译生成的可执行文件.exe
src
文件目录:用于存放源代码pkg
文件目录:存放依赖包go.mod
包管理文件就放在src
下面就行。
之后,我们设置本项目GOPATH
、Module GOPATH
路径为刚才创建的文件目录。
在GoLand
中,选择File→Settings
,打开设置
Project GOPATH
为src
文件目录,存放源码Module GOPATH
为项目目录- 取消使用系统环境定义的
GOPATH
来到GO Modules
设置
- 选中使用GO包整合
- 配置包的代理下载地址
配置运行方式
这个时候,基本设置好了,下面开始经典的HelloWorld
程序编写
在src
目录下新建一个main
包,在main
包新建一个名为HelloWorld
的go程序
打印HelloWorld,我们用Go自带的打印方法打印,输入:
|
|
这时系统会自动识别并引入包所在的目录:import "fmt"
,因为这个是Go自带的SDK里的方法。可以自己识别到并自动添加,后面自己引用第三方的包也一样。这里也强调一点,引入的是这个包所在的目录,在你用的时候才是包名。
最后,构建一个Run/Debug Configuration
GoLand中,运行Go有三种方式:
- 文件方式运行(File)
- 以包的方式运行(Package)
- 以整个目录的方式运行(Directory)
以文件方式运行
以单个文件的方式运行,最为简单,直接可以右击要运行的文件,选择Run
,则可以直接运行程序,编译生成的可执行文件位于用户目录C:\Users\username\AppData\Local\Temp\GoLand\
下,并不在bin
文件中
右击文件运行后,GoLand
新建了一个默认的运行配置文件。在右上方,可以看到配置运行方式的地方,如果之前没有任何配置的话,会提示你Add Configurations
,如果之前有过配置,会出现下拉框让你选择配置或者Edit Configurations
。
这是以文件方式运行go文件的默认运行配置
设置Output directory
为当前项目的bin
文件目录,我这里设置为D:\Code\GolandProjects\TestProject\bin
后,执行,可以看到bin
文件目录中生成可执行文件:
从下方窗口也可以看到输出路径和运行结果:
以包方式运行
Run kind
选择Package
Package path
输入main
函数所在的包名,其他保持不变,这样就以包的方式去运行和调试了
以整个目录的方式运行
若Run kind
选择Directory
,Directory
输入main
函数所在的目录,其他保持不变,则以包的方式去运行和调试。
不管以什么方式运行,运行的入口,即main
方法的所属包名必须是package main
:
|
|
引入第三方包
在go.mod
文件中加入第三方包的名称和版本,这时,Goland就会在网上把包下载下来,保存在一开始我们设置的Module GOPATH
路径下pkg
文件夹下。
|
|
这个时候,我们只是下载了第三方包,还没有去引用它,所以还没有在External Libraries
中有所体现。
接下来我们在程序中引用包,import
后,会发现goland
识别不了,这时我们把光标移动到红色位置,然后同时按下Alt+Enter
,Goland
会智能提示需要同步包,我们点同步
同步好后,会发现左边的pkg
文件目录下出现了我们导入的第三方包go-ole
,External Libraries
中也识别出了这个包。这个时候我们就可以在程序中使用了,如下图:
到这里,我们就可以成功配置并运行一个GO项目了!🎉🎉🎉
导入本地包
2023.9.29补充
只用在项目src目录下建一个go.mod
即可,不用在每个包下建立go.mod
(弃用之前2023.8.19
的方法)
使用时通过包名/函数名or变量名
即可,使用Goland
的话包会自动导入
注意:
- 导入包被外部包调用的变量名或函数名首字母要大写
- 避免包循环导入:明确业务层、工具类等包的规划
2023.8.19补充
在要被导入的本地包路径下执行:
|
|
在要使用该包的包路径下的go.mod
文件中添加
|
|
在要使用该包的go
文件中
|
|
注意:避免包之间互相依赖,如果检测到
import cycle
会在编译时报错import cycle not allowed
例如:
Package A depends on Package B Package B depends on Package A
像
mutex
死锁一样,陷入了死循环
万事开头难,希望我们能坚持学习💪
GOPATH和GoModule区别
Go 语言的的包依赖管理从最初的 GOPATH
到 GO VENDOR
,再到最新的 GO Modules
。目前最主流的包依赖管理方式是使用官方推荐的 Go Modules
,在版本 Go 1.14
发布后,官方强烈推荐使用 Go Modules
进行包依赖管理。
GOPATH
可以将GOPATH
理解为工作目录,在这个工作目录下,通常有如下的目录结构
bin:存放编译后生成的二进制可执行文件
pkg:存放编译后生成的 .a 文件
src:存放项目的源代码和下载的包,将包全部放在 $GOPATH/src 目录下进行管理的方式,我们称之为GOPATH模式
在这个模式下,使用 go install
时,生成的可执行文件会放在 $GOPATH/bin
下。
如果你安装的是一个库,则会生成 .a
文件到 $GOPATH/pkg
下对应的平台目录中(由 GOOS
和 GOARCH
组合而成)。
GOOS
:表示目标操作系统,有darwin(Mac)
,linux
,windows
,android
,netbsd
,openbsd
,solaris
,plan9
等GOARCH
,表示目标架构,常见的有arm
,amd64
等- 这两个都是
go env
里的变量,可以通过go env 变量名
进行查看
使用 GOPATH
模式进行包依赖管理的缺点:
- 无法在项目中,使用指定版本的包。因为不同版本包的导入方法都一样。
- 其他人运行你的开发的程序时,无法保证他下载的包版本是你所期望的版本。当对方使用了其他版本,有可能导致程序无法正常运行。
- 在本地,一个包只能保留一个版本。这意味着:在本地开发的所有项目,都得用同一个版本的包,这几乎是不可能的。
GoVendor
为了解决 GOPATH
方案下不同项目下无法使用多个版本库的问题,Go v1.5
开始支持vendor
。
以前使用 GOPATH
的时候,所有的项目都共享一个 GOPATH
,需要导入依赖的时候,都来这里找。
解决的思路就是,在每个项目下都创建一个 vendor
目录,每个项目所需的依赖都只会下载到自己vendor
目录下,项目之间的依赖包互不影响。
在编译时,Go v1.5
在你设置了开启 GO15VENDOREXPERIMENT=1
(注:这个变量在 v1.6 版本默认为1,但是在 v1.7 后,已去掉该环境变量,默认开启 vendor 特性,无需你手动设置)后,会提升 vendor
目录的依赖包搜索路径的优先级(相较于 GOPATH)。
其搜索包的优先级顺序,由高到低是这样的
- 当前包下的
vendor
目录 - 向上级目录查找,直到找到
src
下的vendor
目录 - 在
GOROOT
目录下查找 - 在
GOPATH
下面查找依赖包
虽然这个方案解决了一些问题,但是解决得并不完美。
如果多个项目用到了同一个包的同一个版本,这个包会存在于该机器上的不同目录下,不仅对磁盘空间是一种浪费,而且没法对第三方包进行集中式的管理(分散在各个角落)。
并且如果要分享开源你的项目,你需要将你的所有的依赖包悉数上传,别人使用的时候,除了你的项目源码外,还有所有的依赖包全部下载下来,才能保证别人使用的时候,不会因为版本问题导致项目不能如你预期那样正常运行。
GoModule
go modules
在 v1.11
版本正式推出,从 v1.11
开始,go env
多了一个环境变量: GO111MODULE
,
它有三个可选值:off
、on
、auto
,默认值是auto
。
GO111MODULE=off
禁用模块支持,编译时会从GOPATH
和vendor
文件夹中查找包。
GO111MODULE=on
启用模块支持,编译时会忽略GOPATH
和vendor
文件夹,只根据go.mod
下载依赖。
GO111MODULE=auto
,当项目在$GOPATH/src
外且项目根目录有go.mod
文件时,自动开启模块支持。
在使用go modules
模式后,项目目录下会多生成两个文件也就是 go.mod
和 go.sum
。这两个文件是 go modules
的核心。
go.mod
go mod
不再依靠GOPATH
,使得它可以脱离GOPATH
来创建项目- 对项目进行
go modules
的初始化 - 第一行:模块的引用路径
- 第二行:项目使用的 go 版本
- 第三行:项目所需的直接依赖包及其版本
在实际应用上,你会看见更复杂的 go.mod
文件,比如下面这样
|
|
主要是多出了两个 flag:
exclude
: 忽略指定版本的依赖包replace
:由于在国内访问golang.org
的各个包比较慢,所以在go.mod
中使用replace
将golang.org
替换成github.com
上对应的库。
go.sum
每一行都是由模块路径,模块版本,哈希检验值组成,其中哈希检验值是用来保证当前缓存的模块不会被篡改。hash
是以h1:
开头的字符串,表示生成checksum
的算法是第一版的hash
算法(sha256
)。
go.mod
和 go.sum
是 go modules
版本管理的指导性文件,因此 go.mod
和 go.sum
文件都应该提交到你的 Git 仓库中去,避免其他人使用你写项目时,重新生成的go.mod
和 go.sum
与你开发的基准版本的不一致。
综上,GOPATH
和GoModule
的区别是:
GOPATH模式 | GoModule模式 | |
---|---|---|
GOPATH 环境变量 |
必须设置 | 可设置可不设置 |
$GOPATH/pkg 文件目录 |
存放.a 文件 |
$GOPATH/pkg 目录存放依赖包 |
$GOPATH/src 文件目录 |
存放源码和依赖包 | 存放源码 |
对依赖包的版本控制 | 无法对依赖包作版本控制 | 可以对依赖包作版本控制 |
Go的根目录结构
简单介绍下go的目录结构。以windows
为例,进入D:\Program Files\go
将看到如下内容
介绍几个比较主要的目录:
api
,里面包含所有API列表,IDE使用了里面的信息;bin
,里面是一些go的工具命令,主要是go
、gofmt
、godoc
doc
,go的使用文档,可以让我们在没有网络的情况下也可以阅读;src
,主要是一些源码,如golang
的编译器、各种工具集以及标准库的源码。