1.GO语言
Go(又称 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 开发的一种静态强类型、编译型语言。Go 语言语法与 C 相近,但功能上有:内存安全,GC(垃圾回收),结构形态及 CSP-style 并发计算
1.1简介
Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。
罗伯特·格瑞史莫(Robert Griesemer),罗勃·派克(Rob Pike)及肯·汤普逊(Ken Thompson)于2007年9月开始设计Go,稍后Ian Lance Taylor、Russ Cox加入项目。Go是基于Inferno操作系统所开发的。Go于2009年11月正式宣布推出,成为开放源代码项目,并在Linux及Mac OS X平台上进行了实现,后来追加了Windows系统下的实现。在2016年,Go被软件评价公司TIOBE 选为“TIOBE 2016 年最佳语言”。 目前,Go每半年发布一个二级版本(即从a.x升级到a.y)
1.2撰写风格
在Go中有几项规定,当不匹配以下规定时编译将会产生错误。
- 每行程序结束后不需要撰写分号(;)。
- 大括号({)不能够换行放置。
- if判断式和for循环不需要以小括号包覆起来。
Go亦有内置gofmt工具,能够自动整理代码多余的空白、变量名称对齐、并将对齐空格转换成Tab
1.3编译器
当前有两个Go编译器分支,分别为官方编译器gc和gccgo。官方编译器在初期使用C写成,后用Go重写从而实现自举。Gccgo是一个使用标准GCC作为后端的Go编译器。
官方编译器支持跨平台编译(但不支持CGO),允许将源代码编译为可在目标系统、架构上执行的二进制文件
1.4语言特点
- 背靠大厂,google背书,可靠
- 天生支持并发(最显著特点)
- 语法简单,容易上手
- 内置runtime,支持垃圾回收
- 可直接编译成机器码,不依赖其他库
- 丰富的标准库
- 跨平台编译
1.6 可以开发什么
网络编程和分布式计算
微服务和云原生应用开发
区块链技术和加密货币开发
后台管理和高并发应用开发
1.7 Go语言相关学习网站
- Go 官网:https://golang.google.cn/
- Go 语言圣经:The Go Programming Language
- GO 中文文档:https://www.topgoer.com/
2. Go目录规范
2.1 目录规范
一个好的目录结构至少要满足以下几个要求。
命名清晰
:目录命名要清晰、简洁,不要太长,也不要太短,目录名要能清晰地表达出该目录实现的功能,并且目录名可根据实际情况选择单数或者复数。
功能明确
:一个目录所要实现的功能应该是明确的、并且在整个项目目录中具有很高的辨识度。也就是说,当需要新增一个功能时,我们能够非常清楚地知道把这个功能放在哪个目录下。
全面性
:目录结构应该尽可能全面地包含研发过程中需要的功能,例如文档、脚本、源码管理、API 实现、工具、第三方包、测试、编译产物等。
可预测性
:项目规模一定是从小到大的,所以一个好的目录结构应该能够在项目变大时,仍然保持之前的目录结构。
可扩展性
:每个目录下存放了同类的功能,在项目变大时,这些目录应该可以存放更多同类功能。根据功能,我们可以
将目录结构分为结构化目录结构和平铺式目录结构两种。
- 结构化目录结构主要用在
Go
应用中,相对来说比较复杂; - 而平铺式目录结构主要用在
Go
包中,相对来说比较简单;
2.2 平铺式目录结构
一个 Go 项目可以是一个应用,也可以是一个代码框架 / 库,当项目是代码框架 / 库时,比较适合采用平铺式目录结构。
平铺方式就是在项目的根目录下存放项目的代码,整个目录结构看起来更像是一层的,例如 log 包 github.com/golang/glog 就是平铺式的,目录如下:
$ ls glog/
glog_file.go glog.go glog_test.go LICENSE README
$ ls glog/
glog_file.go glog.go glog_test.go LICENSE README
2.3 结构化目录结构
当前 Go
社区比较推荐的结构化目录结构是 https://github.com/golang-standards/project-layout。虽然它并不是官方和社区的规范,但因为组织方式比较合理,被很多 Go
开发人员接受。
├── api
├── assets
├── build
├── cmd
├── configs
├── deployments
├── docs
├── examples
├── githooks
├── go.mod
├── init
├── internal
├── LICENSE.md
├── Makefile
├── pkg
├── README_zh-CN.md
├── scripts
├── test
├── third_party
├── tools
├── vendor
├── web
└── website
├── api
├── assets
├── build
├── cmd
├── configs
├── deployments
├── docs
├── examples
├── githooks
├── go.mod
├── init
├── internal
├── LICENSE.md
├── Makefile
├── pkg
├── README_zh-CN.md
├── scripts
├── test
├── third_party
├── tools
├── vendor
├── web
└── website
一个 Go
项目包含 3 大部分:Go
应用 、项目管理和文档。所以,我们的项目目录也可以分为这 3 大类。同时,Go
应用又贯穿开发阶段、测试阶段和部署阶段,相应的应用类的目录,又可以按开发流程分为更小的子类。所以整体来看,我们的目录结构可以按下图所示的方式来分类
Go 应用开发目录
开发的代码包含前端代码和后端代码,可以分别存放在前端目录和后端目录中。
/web
前端代码存放目录,主要用来存放 Web
静态资源,服务端模板和单页应用(SPAs
)。
/cmd
一个项目有很多组件,可以把组件 main
函数所在的文件夹统一放在 /cmd
目录下,例如:
$ ls cmd/
gendocs geniamdocs genman genyaml apiserver iamctl iam-pump
$ ls cmd/apiserver/
apiserver.go
$ ls cmd/
gendocs geniamdocs genman genyaml apiserver iamctl iam-pump
$ ls cmd/apiserver/
apiserver.go
这里要保证 /cmd/<组件名>
目录下不要存放太多的代码,如果你认为代码可以导入并在其他项目中使用,那么它应该位于 /pkg
目录中。如果代码不是可重用的,或者你不希望其他人重用它,请将该代码放到 /internal
目录中。
/internal
存放私有应用和库代码
如果一些代码,你不希望被其他项目/库导入,可以将这部分代码放至/internal
目录下。一般存储一些比较专属于当前项目的代码包。这是在代码编译阶段就会被限制的,该目录下的代码不可被外部访问到。一般有以下子目录:
- /router 路由
- /application 存放命令与查询
- /command
- query
- /middleware 中间件
- /model 模型定义
- /repository 仓储层,封装数据库操作
- /response 响应
- /errmsg 错误处理
在/internal
目录下应存放每个组件的源码目录,当项目变大、组件增多时,扔可以将新增的组件代码存放到/internal
目录下
internal目录并不局限在根目录,在各级子目录中也可以有internal子目录,也会同样起到作用。
/pkg
该目录中存放可以被外部应用使用的代码库,其他项目可以直接通过 import
导入这里的代码。所以,我们在将代码库放入该目录时一定要慎重
/vendor
项目依赖,可通过 go mod vendor 创建。需要注意的是,如果是一个 Go 库,不要提交 vendor 依赖包。vendor 就是把依赖的代码 clone 一份,放在 vendor 中,这样构建时,go 编译器会使用 vendor 中的依赖,而不是到网上去下载,也不会使用本地 module cache 中的依赖。
/third_party
外部帮助工具,分支代码或其他第三方应用(例如 Swagger UI)。比如我们 fork 了一个第三方 go 包,并做了一些小的改动,我们可以放在目录 /third_party/forked 下。一方面可以很清楚的知道该包是 fork 第三方的,另一方面又能够方便地和 upstream 同步。
Go 应用测试目录
/test
用于存放其他外部测试应用和测试数据。/test 目录的构建方式比较灵活:对于大的项目,有一个数据子目录是有意义的。例如,如果需要 Go 忽略该目录中的内容,可以使用 /test/data 或 /test/testdata 目录。
需要注意的是,Go 也会忽略以 . 或 _ 开头的目录或文件。这样在命名测试数据目录方面,可以具有更大的灵活性。
Go 应用部署目录
/configs
放配置文件
/deployments
用来存放 Iaas
、PaaS
系统和容器编排部署配置和模板(Docker-Compose
,Kubernetes/Helm
,Mesos
,Terraform
,Bosh
)。在一些项目,特别是用 Kubernetes
部署的项目中,这个目录可能命名为 deploy
。
/init
存放初始化系统(systemd
,upstart
,sysv
)和进程管理配置文件(runit
,supervisord
)。比如 sysemd
的 unit
文件。这类文件,在非容器化部署的项目中会用到。
Go应用项目管理目录
/Makefile
一个 Go 项目在其根目录下应该有一个 Makefile 工具,用来对项目进行管理,Makefile 通常用来执行静态代码检查、单元测试、编译等功能。其他常见功能:
静态代码检查(lint):推荐用 golangci-lint。
单元测试(test):运行 go test ./...。
编译(build):编译源码,支持不同的平台,不同的 CPU 架构。
镜像打包和发布(image/image.push):现在的系统比较推荐用 Docker/Kubernetes 进行部署,所以一般也要有镜像构建功能。
清理(clean):清理临时文件或者编译后的产物。
代码生成(gen):比如要编译生成 protobuf pb.go 文件。
部署(deploy,可选):一键部署功能,方便测试。
发布(release):发布功能,比如:发布到 Docker Hub、github 等。
帮助(help):告诉 Makefile 有哪些功能,如何执行这些功能。
版权声明(add-copyright):如果是开源项目,可能需要在每个文件中添加版权头,这可以通过 Makefile 来添加。
API 文档(swagger):如果使用 swagger 来生成 API 文档,这可以通过 Makefile 来生成。
建议:直接执行 make 时,执行如下各项 format -> lint -> test -> build,如果是有代码生成的操作,还可能需要首先生成代码 gen -> format -> lint -> test -> build。
/scripts
该目录主要用来存放脚本文件,实现构建、安装、分析等不同功能。不同项目,里面可能存放不同的文件,但通常可以考虑包含以下 3 个目录:
/scripts/make-rules:用来存放 makefile 文件,实现 /Makefile 文件中的各个功能。Makefile 有很多功能,为了保持它的简洁,我建议你将各个功能的具体实现放在 /scripts/make-rules 文件夹下
/scripts/lib:shell 库,用来存放 shell 脚本。一个大型项目中有很多自动化任务,比如发布、更新文档、生成代码等,所以要写很多 shell 脚本,这些 shell 脚本会有一些通用功能,可以抽象成库,存放在 /scripts/lib 目录下,比如 logging.sh,util.sh 等。
/scripts/install:如果项目支持自动化部署,可以将自动化部署脚本放在此目录下。如果部署脚本简单,也可以直接放在 /scripts 目录下。
另外,shell 脚本中的函数名,建议采用语义化的命名方式,例如 iam::log::info 这种语义化的命名方式,可以使调用者轻松的辨别出函数的功能类别,便于函数的管理和引用
/build
存放安装包和持续集成相关的文件。这个目录下有 3 个大概率会使用到的目录,在设计目录结构时可以考虑进去。
/build/package
:存放容器(Docker
)、系统(deb
,rpm
,pkg
)的包配置和脚本。/build/ci
:存放CI
的配置文件和脚本。/build/docker
:存放子项目各个组件的Dockerfile
文件。
/tools
存放这个项目的支持工具。这些工具可导入来自 /pkg
和 /internal
目录的代码
/githooks
Git
钩子。比如,我们可以将 commit-msg
存放在该目录
/assets
项目使用的其他资源 (图片、CSS
、JavaScript
等)。
Go 应用文档目录
/README.md
项目的 README
文件一般包含了项目的介绍、功能、快速安装和使用指引、详细的文档链接以及开发指引等
/docs
存放设计文档、开发文档和用户文档等(除了 godoc
生成的文档)。推荐存放以下几个子目录:
/docs/devel/{en-US,zh-CN}
:存放开发文档、hack
文档等。/docs/guide/{en-US,zh-CN}
: 存放用户手册,安装、quickstart
、产品文档等,分为中文文档和英文文档。/docs/images
:存放图片文件。
/CONTRIBUTING.md
开源就绪的项目,用来说明如何贡献代码,如何开源协同等等。CONTRIBUTING.md
不仅能够规范协同流程,还能降低第三方开发者贡献代码的难度。
/api
/api 目录中存放的是当前项目对外提供的各种不同类型的 API 接口定义文件,其中可能包含类似
/api/protobuf-spec、/api/thrift-spec、/api/http-spec、openapi、swagger 的目录,这些目录包含了当前项目对外提供和依赖的所有 API 文件。
2.4 实际项目参考目录
├── admin.sh # 进程的start|stop|status|restart控制文件
├── conf # 配置文件统一存放目录
│ ├── config.yaml # 配置文件
│ ├── server.crt # TLS配置文件
│ └── server.key
├── config # 专门用来处理配置和配置文件的Go package
│ └── config.go
├── db.sql # 在部署新环境时,可以登录MySQL客户端,执行source db.sql创建数据库和表
├── docs # swagger文档,执行 swag init 生成的
│ ├── docs.go
│ └── swagger
│ ├── swagger.json
│ └── swagger.yaml
├── handler # 类似MVC架构中的C,用来读取输入,并将处理流程转发给实际的处理函数,最后返回结果
│ ├── handler.go
│ ├── sd # 健康检查handler
│ │ └── check.go
│ └── user # 核心:用户业务逻辑handler
│ ├── create.go # 新增用户
│ ├── delete.go # 删除用户
│ ├── get.go # 获取指定的用户信息
│ ├── list.go # 查询用户列表
│ ├── login.go # 用户登录
│ ├── update.go # 更新用户
│ └── user.go # 存放用户handler公用的函数、结构体等
├── main.go # Go程序唯一入口
├── Makefile # Makefile文件,一般大型软件系统都是采用make来作为编译工具
├── model # 数据库相关的操作统一放在这里,包括数据库初始化和对表的增删改查
│ ├── init.go # 初始化和连接数据库
│ ├── model.go # 存放一些公用的go struct
│ └── user.go # 用户相关的数据库CURD操作
├── pkg # 引用的包
│ ├── auth # 认证包
│ │ └── auth.go
│ ├── constvar # 常量统一存放位置
│ │ └── constvar.go
│ ├── errno # 错误码存放位置
│ │ ├── code.go
│ │ └── errno.go
│ ├── token
│ │ └── token.go
│ └── version # 版本包
│ ├── base.go
│ ├── doc.go
│ └── version.go
├── README.md # API目录README
├── router # 路由相关处理
│ ├── middleware # API服务器用的是Gin Web框架,Gin中间件存放位置
│ │ ├── auth.go
│ │ ├── header.go
│ │ ├── logging.go
│ │ └── requestid.go
│ └── router.go
├── service # 实际业务处理函数存放位置
│ └── service.go
├── util # 工具类函数存放目录
│ ├── util.go
│ └── util_test.go
└── vendor # vendor目录用来管理依赖包
├── github.com
├── golang.org
├── gopkg.in
└── vendor.json
├── admin.sh # 进程的start|stop|status|restart控制文件
├── conf # 配置文件统一存放目录
│ ├── config.yaml # 配置文件
│ ├── server.crt # TLS配置文件
│ └── server.key
├── config # 专门用来处理配置和配置文件的Go package
│ └── config.go
├── db.sql # 在部署新环境时,可以登录MySQL客户端,执行source db.sql创建数据库和表
├── docs # swagger文档,执行 swag init 生成的
│ ├── docs.go
│ └── swagger
│ ├── swagger.json
│ └── swagger.yaml
├── handler # 类似MVC架构中的C,用来读取输入,并将处理流程转发给实际的处理函数,最后返回结果
│ ├── handler.go
│ ├── sd # 健康检查handler
│ │ └── check.go
│ └── user # 核心:用户业务逻辑handler
│ ├── create.go # 新增用户
│ ├── delete.go # 删除用户
│ ├── get.go # 获取指定的用户信息
│ ├── list.go # 查询用户列表
│ ├── login.go # 用户登录
│ ├── update.go # 更新用户
│ └── user.go # 存放用户handler公用的函数、结构体等
├── main.go # Go程序唯一入口
├── Makefile # Makefile文件,一般大型软件系统都是采用make来作为编译工具
├── model # 数据库相关的操作统一放在这里,包括数据库初始化和对表的增删改查
│ ├── init.go # 初始化和连接数据库
│ ├── model.go # 存放一些公用的go struct
│ └── user.go # 用户相关的数据库CURD操作
├── pkg # 引用的包
│ ├── auth # 认证包
│ │ └── auth.go
│ ├── constvar # 常量统一存放位置
│ │ └── constvar.go
│ ├── errno # 错误码存放位置
│ │ ├── code.go
│ │ └── errno.go
│ ├── token
│ │ └── token.go
│ └── version # 版本包
│ ├── base.go
│ ├── doc.go
│ └── version.go
├── README.md # API目录README
├── router # 路由相关处理
│ ├── middleware # API服务器用的是Gin Web框架,Gin中间件存放位置
│ │ ├── auth.go
│ │ ├── header.go
│ │ ├── logging.go
│ │ └── requestid.go
│ └── router.go
├── service # 实际业务处理函数存放位置
│ └── service.go
├── util # 工具类函数存放目录
│ ├── util.go
│ └── util_test.go
└── vendor # vendor目录用来管理依赖包
├── github.com
├── golang.org
├── gopkg.in
└── vendor.json
Go API
项目中,一般都会包括这些功能项:Makefile
文件、配置文件目录、RESTful API
服务器的 handler
目录、model
目录、工具类目录、vendor
目录,以及实际处理业务逻辑函数所存放的 service
目录。这些都在上述的代码结构中有列出,新加功能时将代码放入对应功能的目录/文件中,可以使整个项目代码结构更加清晰,非常有利于后期的查找和维护。
2.5 makefile 的规则
https://blog.csdn.net/wohu1104/article/details/123209272
3. Hello Word
package main // 一个项目中只能有一个入口函数
import "fmt" //有引用必须调用
func main(){
}
package main // 一个项目中只能有一个入口函数
import "fmt" //有引用必须调用
func main(){
}
数组
slice
struct使用场景,固定好的数据结构,不可以变更
Order :=struct {
Uid string
Price string
Type int
time string
ProductId int
}{}
Order :=struct {
Uid string
Price string
Type int
time string
ProductId int
}{}
map使用场景,不用固定数据类型,可以随便增加减少
//某个人情况
people := map[string]interface{}{"name":"zhangsan","score":100,"sex":false}
//某个人分数
score:=map[string]int{"zhangsan":100,"lisi":10,"wangwu":11}
//某个人情况
people := map[string]interface{}{"name":"zhangsan","score":100,"sex":false}
//某个人分数
score:=map[string]int{"zhangsan":100,"lisi":10,"wangwu":11}