Skip to content

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 发展史

  • 2007年,Google开始着手开发Go语言,主要的设计者包括Robert Griesemer、Rob Pike和Ken Thompson等人.
  • 2009年11月,Google发布了Go语言的第一个稳定版本,即Go1.0。这标志着Go语言正式面世,并开始逐渐受到广泛关注和应用.
  • 2011年5月,Go1.0.2发布,这是Go语言的第一个正式稳定版本,其中包括了一些重要的bug修复和改进
  • 2012年3月,Go语言成为GitHub上最受欢迎的编程语言之一,这意味着Go语言已经受到了广泛的开发者社区的支持和认可
  • 2015年8月,G01.5发布,加入了支持ARMv7和ARM64架构、并行编译等特性,这使得Go语言在移动设备和嵌入式 系统等领域的应用更加便利
  • 2018年8月,Go1.11发布,号1X了模块支持、WebAssembly支持、延迟函数调用等特性,这些特性使得Go语言在 项目管理、跨平台应用和异步编程等方面有了更加强大的能力
  • 2019年2月,G01.12发布,加入了一些小的语法改进和工具增强,使得开发者能够更加便利地使用G0语言开发应用 程序。
  • 2020年2月,G01.14发布,加入了对嵌入式设备的支持、对HTTP服务器的性能优化等特性,这使得Go语言在物联 网和云计算等领域的应用更加广泛。
  • 2021年2月,G01.16发布,加入了对模块和错误处理的改进、垃圾回收器的性能提升等特性,这些改进使得Go语言 在性能、可靠性和开发体验等方面有了更大的提升。

1.3撰写风格

在Go中有几项规定,当不匹配以下规定时编译将会产生错误。

  1. 每行程序结束后不需要撰写分号(;)。
  2. 大括号({)不能够换行放置。
  3. if判断式和for循环不需要以小括号包覆起来。

Go亦有内置gofmt工具,能够自动整理代码多余的空白、变量名称对齐、并将对齐空格转换成Tab

1.4编译器

当前有两个Go编译器分支,分别为官方编译器gc和gccgo。官方编译器在初期使用C写成,后用Go重写从而实现自举。Gccgo是一个使用标准GCC作为后端的Go编译器。

官方编译器支持跨平台编译(但不支持CGO),允许将源代码编译为可在目标系统、架构上执行的二进制文件

1.5语言特点

  1. 背靠大厂,google背书,可靠
  2. 天生支持并发(最显著特点)
  3. 语法简单,容易上手
  4. 内置runtime,支持垃圾回收
  5. 可直接编译成机器码,不依赖其他库
  6. 丰富的标准库
  7. 跨平台编译

1.6为什么选择Golang?

使用简单(简单、便捷)

原生并发(轻量、高效)

组合(垂直组合、水平组合)

面向工程(标准库、工具链)

1.7 可以开发什么

网络编程和分布式计算

微服务和云原生应用开发

区块链技术和加密货币开发

后台管理和高并发应用开发

1.8 Go语言相关学习网站

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

用来存放 IaasPaaS 系统和容器编排部署配置和模板(Docker-ComposeKubernetes/HelmMesosTerraformBosh)。在一些项目,特别是用 Kubernetes 部署的项目中,这个目录可能命名为 deploy

/init

存放初始化系统(systemdupstartsysv)和进程管理配置文件(runitsupervisord)。比如 sysemdunit 文件。这类文件,在非容器化部署的项目中会用到。

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

项目使用的其他资源 (图片、CSSJavaScript 等)。

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 实际项目参考目录

yaml
├── 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

go
package main  // 一个项目中只能有一个入口函数

import "fmt" //有引用必须调用

func main(){
    
}
package main  // 一个项目中只能有一个入口函数

import "fmt" //有引用必须调用

func main(){
    
}

数组

slice

struct使用场景,固定好的数据结构,不可以变更

go
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使用场景,不用固定数据类型,可以随便增加减少

go
//某个人情况
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}