一、golang介绍与快速入门

27 阅读9分钟

一,Go语言介绍

Go语言(又称Golang)是由Google开发的一种静态类型、编译型的开源编程语言,诞生于2009年,并于2012年发布正式稳定版本。其设计团队由三位计算机科学领域的先驱组成:Robert Griesemer、Rob Pike和Ken Thompson(后者是Unix和C语言的共同创始人)。Go语言的设计目标是解决现代软件开发中的痛点,如代码复杂性、编译速度慢、并发编程困难以及跨平台支持不足等问题。

1.1 核心设计理念

  1. 简洁高效 Go语法类似C语言,但通过去冗余设计简化代码结构。例如:

    • 移除类继承、构造函数、注解等复杂概念。
    • 不支持函数重载和运算符重载。
    • 强制代码格式化工具gofmt统一代码风格,减少风格争议。
  2. 原生并发支持 Go的并发模型基于CSP理论(Communicating Sequential Processes),核心机制为:

    • Goroutine:轻量级线程,由Go运行时管理,创建成本极低(初始仅2KB栈,动态扩展)。
    • Channel:类型安全的管道,用于Goroutine间通信,避免共享内存导致的竞态问题。
    func main() {
        ch := make(chan int)
        go func() { ch <- 42 }() // 启动Goroutine发送数据
        fmt.Println(<-ch)        // 接收数据
    }
    
  3. 内存管理 Go内置自动垃圾回收(GC),通过三色标记清除算法优化延迟,现代版本(如Go 1.14+)的GC停顿时间通常低于1毫秒。

1.2 语言特性

  1. 类型系统

    • 静态类型:编译时检查类型错误,提升代码健壮性。

    • 接口隐式实现:类型无需显式声明实现接口,只需定义相同方法即可。

    • 泛型支持:Go 1.18引入泛型,通过类型参数增强代码复用性。

      func Swap[T any](a, b T) (T, T) { return b, a }
      
  2. 错误处理 采用显式错误返回而非异常机制,鼓励开发者主动处理错误:

    file, err := os.Open("file.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close() // 确保资源释放
    
  3. 工具链

    • 跨平台编译:通过GOOSGOARCH环境变量生成不同平台的二进制文件。
    • 依赖管理:Go Modules支持版本化依赖管理,替代旧版GOPATH模式。
    • 测试与性能分析:内置go test框架和pprof性能分析工具。

1.3 标准库与生态系统

  1. 丰富的标准库
    • 网络服务:net/http库支持快速构建HTTP服务器(如默认实现每秒可处理数万请求)。
    • 加密与编码:提供AES、RSA、JSON、XML等标准支持。
    • 并发原语:sync包提供互斥锁、条件变量等。
  2. 活跃的第三方生态
    • Web框架:Gin、Echo、Fiber等高性能框架。
    • 微服务与云原生:Kubernetes、Docker、Etcd等核心项目均用Go编写。
    • 数据库驱动:支持PostgreSQL、MySQL、MongoDB等主流数据库。

1.4 适用场景

  1. 后端服务与微服务 Go的高并发和低内存占用特性使其适合构建API网关、分布式系统等。
  2. 云计算与DevOps工具 如Kubernetes、Prometheus、Terraform等基础设施项目依赖Go的高效编译和部署能力。
  3. 命令行工具 单二进制文件分发(无外部依赖)特性适合开发CLI工具,如GitHub CLI、Cobra框架应用。

1.5 优缺点

优势

  • 编译速度快(大型项目通常在数秒内完成)。
  • 部署简单,生成静态二进制文件。
  • 并发模型简化多线程编程。

局限

  • 泛型支持较晚,旧代码可能缺乏通用性。
  • 错误处理代码可能显冗长。
  • 不适合实时系统(因GC存在不确定延迟)。

二,Go的安装与配置

2.1 语言环境安装

由于Go语言官网下载速度比较慢,这里推荐大家使用Go语言中文网下载即可,而且Go语言官网和这个中文网发版基本同步。

image-20250524140500769

点击下载后,会在下载文件夹中出现上面选择的文件,由于文件属于安装包,还是需要解压安装的,这里直接双击即可呈现下图,然后选择Next:

image-20250524140515084

一直选择下一步,最后安装完成后应该呈现如下图:

image-20250524140530483

2.2 环境验证

Win + R唤醒运行窗口之后,输入cmd打开控制台窗口,输入go version,可查看安装的go版本,检查其是否安装成功。

image-20250524140633656

在高版本里安装时会默认在环境变量中配置。

2.3 配置代理

在使用Go进行开发时,可能我们需要借用Go下载一些包什么的,但是默认官网源在国内访问不到,默认官网源如下

https://proxy.golang.org,direct

因此,我们需要配置GOPROXY(代理)。在控制台输入go env,可查看go的初始环境配置,然后执行以下命令,进行修改代理,将其替换成国内镜像源。Windows 下设置 GOPROXY 的命令为:

go env -w GOPROXY=https://goproxy.cn,direct

重新执行go env查看Go配置,结果如下图:

image-20250524140918208

2.4 配置包目录说明

首先在终端里输入go env命令可查看go相关环境变量,会发现GOPATH为用户家目录。

image-20250524141058041

点进去这个家目录下的go文件夹里,我们会发现里面有两个包文件:

image-20250524141114083

这两个包目录

名称作用
pkg目录常用于缓存第三方包文件
bin目录常用于存放可执行文件:通过go install命令下载的第三方包会放到$GOPATH/go下面的缓存目录,编译好的可执行文件会放到$GOPATH/go/bin

然后继续点进去bin目录里,我们会发现3个基本的可执行文件

image-20250524141132226

这三个文件

文件名作用安装命令
dlvgo-delve是Go语言的调试利器go install -v github.com/go-delve/delve/cmd/dlv@latest
gopls官方提供的实现语言服务器协议LSP的Language Server,具有构建、格式化、自动完成等功能。go install -v golang.org/x/tools/gopls@latest
staticcheck静态代码检查作用go install -v honnef.co/go/tools/cmd/staticcheck@latest

最后对安装包的两个命令也做个总结:

名称作用
go install命令下载的第三方包会放到$GOPATH/go下面的缓存目录,编译好的可执行文件会放到$GOPATH/go/bin
go get命令下载第三方包会放到$GOPATH/go下面的缓存目录,但不会编译,只是为了后面编程用到这些包

2.5 环境变量

查看 go 的环境变量的命令为go env

image-20250524141530189

上面打印出来的环境变量有很多,但着重理解并记住这几个环境变量的定义即可:

变量名解释
GOPATHgo 的工作目录
GOROOTgo 的安装目录
GOBINgo 的bin文件目录
GO111MODULEgo mod 开关 on为开启go mod
GOPROXY设置代理来加速模块下载

2.5.1 GOPATH

GOPATH 是 Go语言中使用的一个环境变量,它使用绝对路径提供项目的工作目录。GOPATH是早期的设置方式,将工作目录设置 GOPATH 到全局环境变量。不同的项目都在 GOPATH/src/ 下。

很显然这种设置方法是不太方便的,因为不同项目引用的 package 到放到了一起,这用 Git管理起来很麻烦。

  • 比如我们有这样一个场景:A项目引用了 a和b 两个 package,B 项目引用了 c和d 两个 package,那么如果我在 A 中修改了 package 的内容,我提交A项目时想要带着 package 时就很麻烦。
  • 其次是 如果Go语言所依赖的所有的第三方库都放在 GOPATH 这个目录下面,这就导致了同一个库只能保存一个版本的代码。如果不同的项目依赖同一个第三方的库的不同版本,应该怎么解决?

2.5.2 GO Module

那么为了解决上述问题,官方从从Go语言1.11 版本之后推出了版本管理工具go module ,并且从 Go语言1.13 版本开始,go module 成为了Go语言默认的依赖管理工具

在Go语言 1.12 版本之前,要启用go module工具首先要设置环境变量 GO111MODULE,不过在Go语言 1.13 及以后的版本则不再需要设置环境变量。

通过 GO111MODULE 可以开启或关闭 go module 工具。

GO111MODULE=off 禁用 go module,编译时会从 GOPATH 和 vendor 文件夹中查找包; GO111MODULE=on 启用 go module,编译时会忽略 GOPATH 和 vendor 文件夹,只根据 go.mod下载依赖; GO111MODULE=auto(默认值),当项目在 GOPATH/src 目录之外,并且项目根目录有 go.mod 文件时,开启 go module。

Windows 下开启 GO111MODULE 的命令为:

set GO111MODULE=on 或者 set GO111MODULE=auto

注意:现在新版本Go语言在配置环境变量时,只需要设置GOPROXY替换一下代理,无需再额外配置GOROOT、GOPATH。

2.5.3 修改GoPath

默认情况下GOPATH是安装到C盘下面的,而这个目录是用来存储一些package的,C盘空间有限,故不希望存C盘,这个时候就需要修改了,只需要在环境变量里面设置修改即可,如图所示

image-20250524143426537

2.6 版本管理

2.6.1 vendor

Go 语言中的 vendor 目录是一种用于项目级依赖隔离的机制,其核心目标是在项目中嵌入依赖的副本,以实现 离线构建版本锁定

  1. 什么是 vendor 目录?

    • 定义vendor 是 Go 项目中的一个特殊目录(通常位于项目根目录),用于存储项目依赖的完整副本

    • 历史背景:在 Go Modules 出现之前,社区工具(如 depglide)通过 vendor 管理依赖。Go 1.5+ 开始原生支持 vendor,但 Go Modules 推出后其重要性下降。

    • 文件结构

      my-project/
        ├── go.mod
        ├── go.sum
        ├── main.go
        └── vendor/
            ├── github.com/
            │   └── gin-gonic/
            │       └── gin/       # 依赖的完整代码
            └── modules.txt        # 依赖列表及版本
      
  2. vendor 的作用

    离线构建

    • 场景:当无法访问互联网(如内网环境)时,直接使用 vendor 内的依赖副本构建项目。

    • 命令

      go build -mod=vendor  # 强制使用 vendor 目录构建
      

    版本锁定

    • 避免意外升级:将依赖代码固化在 vendor 中,防止因外部仓库修改或删除导致构建失败。
    • 一致性保障:确保团队成员或 CI/CD 环境使用完全相同的依赖版本。

    依赖审计

    • 透明化依赖代码:直接查看 vendor 中的代码,便于安全审查或调试。
  3. 生成 vendor 目录

    使用 Go Modules 生成:在项目根目录运行以下命令,自动将 go.mod 中的依赖复制到 vendor

    go mod vendor  # 根据 go.mod/go.sum 生成 vendor 目录
    

    生成的 vendor/modules.txt 会记录依赖的精确版本。

  4. 4. vendor vs Go Modules

    特性vendor 目录Go Modules
    依赖存储位置项目内的 vendor 目录全局缓存 ($GOPATH/pkg/mod)
    版本控制代码副本固化在项目中通过 go.modgo.sum 声明版本
    网络依赖无需网络(离线构建)首次构建需下载依赖
    项目体积较大(包含依赖代码)较小(仅记录版本信息)
    维护成本需手动更新或定期执行 go mod vendor全自动管理

2.6.2 go.sum

定义go.sum:依赖内容的“指纹”校验文件(自动生成,禁止手动修改)

作用:定义 Go 模块的元数据依赖声明

内容

  • 模块名称(module example.com/my-project)。
  • Go 版本要求(go 1.21)。
  • 直接依赖列表(require github.com/foo/bar v1.2.3)。
  • 依赖替换规则(replaceexclude)。

示例

module example.com/app
go 1.21

require (
    github.com/gin-gonic/gin v1.9.1
    golang.org/x/sys v0.12.0 // indirect
)

replace github.com/old/pkg => ../local/pkg

2.6.3 go.mod

定义:依赖版本的管理清单(开发者直接编辑或通过 go get 管理)

作用:记录依赖的加密哈希值,确保依赖内容的完整性

内容

  • 每行格式:模块名 版本 哈希值
  • 包含直接依赖和间接依赖的哈希值。

示例

github.com/gin-gonic/gin v1.9.1 h1:4+fr4g88Y5f+8cF7aY0q7ZtVd+kd8i6A/5E5K7x1m0=
github.com/gin-gonic/gin v1.9.1/go.mod h256:xyz...

go.mod:依赖版本的管理清单(开发者直接编辑或通过 go get 管理)。

2.6.4 和Maven对比

太难理解了,直接和Maven进行对比

核心类比

Go ModulesMaven相似点
go.modpom.xml声明项目元数据与依赖版本
go.sum依赖的 .sha1 校验文件确保依赖完整性
go get / go mod tidymvn dependency:resolve依赖解析与下载

依赖来源

  • Go Modules
    • 去中心化:依赖直接从代码仓库(如 GitHub)下载,无需中央仓库(但支持代理镜像如 GOPROXY)。
    • 语义化版本(SemVer):版本号显式包含在模块路径中(如 github.com/foo/bar/v2)。
  • Maven
    • 中央仓库:依赖默认从 Maven Central 或 Nexus 等仓库下载。
    • 坐标定位:依赖通过 groupIdartifactIdversion 定位。

依赖锁定

  • Go
    • go.mod 声明最低兼容版本,实际构建时使用满足约束的最新版本(通过 MVS 算法解析)。
    • go.sum 记录所有依赖的哈希值,确保内容一致性。
  • Maven
    • pom.xml 中版本固定(除非使用范围版本如 [1.0,2.0))。
    • 通过 mvn dependency:purge-local-repository 清理本地缓存。

构建与生命周期

  • Go
    • 无内置构建生命周期(如 cleancompilepackage),需借助 Makefile 或脚本。
    • 编译为静态二进制文件,无 target 目录概念。
  • Maven
    • 强绑定构建生命周期(compiletestpackage 等)。
    • 输出产物为 jar/war,存储在 target 目录。

操作命令对比

功能Go 命令Maven 命令
初始化项目go mod init <module-name>mvn archetype:generate
添加依赖go get github.com/foo/bar@v1.2编辑 pom.xml + mvn install
更新依赖go get -u修改版本号 + mvn update
清理缓存go clean -modcachemvn dependency:purge-local-repository

总结

  • go.modpom.xml: 二者均为依赖管理的核心配置文件,但 Go 的版本解析更动态,Maven 更静态。
  • go.sumpom.xmlgo.sum 更接近 Maven 依赖的校验文件(如 .sha1),但设计上更严格(强制记录所有依赖哈希)。
  • 哲学差异: Go 强调极简主义(无构建生命周期、去中心化依赖),而 Maven 提供全功能构建框架(插件化、中央仓库)。

三,编写程序

package main

import "fmt"

func main() {
    // 打印 helloworld
	fmt.Println("Hello World")
}

Go程序语法的用法解释:

  • 第1行: 它包含程序的主体程序,具有程序的整体内容。这是运行程序的起点,因此必须编写程序。
  • 第2行: 它包含import“ fmt”,这是一个预处理程序命令,它告诉编译器包括位于程序包中的文件。
  • 第三行: 主函数,它是程序执行的开始。
  • 第4行: fmt.Println()是一个标准的库函数来打印的东西作为一个screen.In输出此,fmt包已经transmited的println方法,该方法用于显示的输出。fmt.Println()是一个标准的库函数,用于将某些内容打印为屏幕上的输出,fmt包已包含了Println方法,该方法用于显示输出。
  • 注释: 注释用于解释代码,并且以与Java或C或C ++类似的方式使用。编译器将忽略注释条目,并且不执行它们。注释可以是单行或多行。