Go 1.11 相比 Go 1.10 有哪些值得注意的改动?

本系列旨在梳理 Go 的 release notes 与发展史,来更加深入地理解 Go 语言设计的思路。

go.dev/doc/go1.11

Go 1.11 值得关注的改动:

  1. WebAssembly 支持 : Go 1.11 实验性地增加了对 WebAssembly (js/wasm) 的支持,允许将 Go 程序编译成可在浏览器中运行的 .wasm 文件。编译产物包含 Go 运行时,因此体积较大(约 2MB,压缩后 500KB),并提供了实验性的 syscall/js 包与 JavaScript 进行交互。同时,新增了 GOOS="js"GOARCH="wasm",命名符合 *_js.go*_wasm.go 规则的文件现在仅在对应编译目标下生效。
  2. Go 模块 (Go Modules) : Go 1.11 初步引入了 Go 模块 (Go Modules) 作为 GOPATH 的替代方案,提供了内置的版本控制和包分发支持。虽然仍处于实验阶段,但其目标是让开发者不再局限于 GOPATH 工作区,并改善依赖管理和构建的可复现性。
  3. 编译器优化 : 编译器现在会报告在类型断言 switch 语句的 guard 中声明但未被使用的变量为错误,例如 switch x := v.(type) {} 中的 x 若未使用,编译将失败。这增强了代码的严谨性,与 gccgogo/types 的行为保持了一致。

下面是一些值得展开的讨论:

Go 模块 (Go Modules) 详解

Go 1.11 版本引入了对 Go 模块 (Go Modules) 的初步支持,这是 Go 语言在包管理和版本依赖方面的一个重大变革,旨在解决长期以来 GOPATH 模式带来的诸多问题。Modules 提供了一种新的方式来管理项目依赖,集成了版本控制和包分发功能,使得开发者可以:

  • GOPATH 之外创建和管理项目。
  • 通过 go.mod 文件明确、轻量地记录项目的版本依赖信息。
  • 实现更可靠、更可复现的构建过程。

尽管在 Go 1.11 中 Modules 仍处于实验阶段,其细节可能会在后续版本中调整,但官方保证使用 Go 1.11 迁移到 Modules 的项目将在 Go 1.12 及以后版本中继续工作。

Go 1.10 (及更早) 的 GOPATH 模式

在 Go 1.11 之前,Go 项目的开发和依赖管理主要依赖 GOPATH 环境变量。

  • 工作区限制 :所有的 Go 源代码(包括你自己的项目和第三方依赖)都必须放在 $GOPATH/src 目录下,形成了固定的目录结构,例如 $GOPATH/src/github.com/user/project
  • 依赖获取 :使用 go get 命令下载依赖包,默认会下载最新的代码到 $GOPATH/src 对应路径下。
  • 版本管理缺失GOPATH 本身没有内置的版本控制机制。开发者通常需要借助第三方工具(如 dep, glide 等)或者手动将依赖复制到项目下的 vendor 目录来进行版本锁定,但这并非语言内置功能,且容易导致不一致。
  • 可复现性问题 :由于 go get 默认拉取最新代码,不同时间、不同环境下构建同一个项目可能会因为依赖版本的变化而产生不同的结果或构建失败。

Go 1.11 的 Go Modules 模式

Go Modules 的引入改变了这一切:

  • 项目位置自由 :项目可以放在文件系统中的任何位置,不再受 GOPATH 限制。
  • go.mod 文件 :每个模块 (module) 的根目录下都有一个 go.mod 文件。该文件定义了模块路径(module path)、项目所需的最低 Go 版本以及所有直接依赖项及其要求的最低版本(通过 require 指令)。
  • go.sum 文件 :伴随 go.mod 生成的 go.sum 文件包含了模块所依赖的包(包括直接和间接依赖)的具体版本及其内容的哈希校验和,用于保证依赖包的完整性和构建的可复现性。
  • 自动依赖管理 :当你在代码中 import 一个新的包,或者使用 go build, go test, go list 等命令时,Go 工具链会自动分析 go.mod 文件,下载缺失的依赖项到 $GOPATH/pkg/mod 目录下(这是一个全局共享的缓存),并可能更新 go.modgo.sum 文件。

示例对比

假设我们要创建一个简单的项目,依赖 rsc.io/quote 包。

Go 1.10 (GOPATH 模式)

  1. 确保你的项目在 $GOPATH/src 下,比如 $GOPATH/src/myproject
  2. 创建 main.go:
go 复制代码
package main

import (
    "fmt"
    "rsc.io/quote"
)

func main() {
    fmt.Println(quote.Hello())
}
  1. 获取依赖:
bash 复制代码
go get rsc.io/quote

这会将 rsc.io/quote 的最新代码下载到 $GOPATH/src/rsc.io/quote。没有版本信息被记录在你的项目里。

  1. 构建:
bash 复制代码
go build

Go 1.11 (Go Modules 模式)

  1. 在任何你喜欢的位置创建项目目录,比如 /path/to/myproject (无需在 GOPATH 内)。
  2. 进入目录并初始化模块:
bash 复制代码
cd /path/to/myproject
go mod init myproject

这会创建一个 go.mod 文件,内容类似:

txt 复制代码
module myproject

go 1.11
  1. 创建 main.go (内容同上)。
  2. 构建或运行:
bash 复制代码
go build
# 或者 go run .

Go 工具会自动检测到 import "rsc.io/quote",查找该包的最新版本,下载它,并更新 go.modgo.sum

go.mod 文件可能变为:

txt 复制代码
module myproject

go 1.11

require rsc.io/quote v1.5.2 // 版本号可能不同

go.sum 文件也会被创建,包含类似以下的校验和信息:

txt 复制代码
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZO...
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:Nq...
rsc.io/quote v1.5.2 h1:w5fc...
rsc.io/quote v1.5.2/go.mod h1:Lz...
rsc.io/sampler v1.3.0 h1:7u...
rsc.io/sampler v1.3.0/go.mod h1:T1...

现在,项目的依赖及其精确版本都被清晰地记录下来了。

GO111MODULE 环境变量

Go 1.11 使用 GO111MODULE 环境变量来控制模块支持的开启状态:

  • GO111MODULE=on: 强制使用模块支持,忽略 GOPATH
  • GO111MODULE=off: 强制禁用模块支持,回归 GOPATH 模式。
  • GO111MODULE=auto (默认值): 当项目在 $GOPATH/src 之外,并且根目录或任何父目录包含 go.mod 文件时,启用模块支持。否则,使用 GOPATH 模式。

其他相关变更

  • 导入路径限制 : 由于 @ 符号在模块相关的命令(如 go get example.com/[email protected])中有特殊含义,Go 1.11 开始禁止在 import 路径中使用 @ 符号。
  • 包加载 API : 新增了 golang.org/x/tools/go/packages 包,提供了一个更强大的 API 来定位和加载 Go 源代码包,它能更好地支持模块,并可以与 Bazel、Buck 等其他构建系统集成。这个包旨在未来替代标准库中的 go/build 包。
  • 构建缓存强制化 : Go 1.10 引入了构建缓存 (GOCACHE)。Go 1.11 宣布这将是最后一个允许通过设置 GOCACHE=off 来禁用缓存的版本。从 Go 1.12 开始,构建缓存将是强制性的,这是逐步淘汰 $GOPATH/pkg 的一步。模块和新的包加载机制已经依赖于启用构建缓存。

总而言之,Go 1.11 的 Go Modules 为 Go 生态带来了现代化的依赖管理解决方案,虽然在当时是初步引入,但它奠定了未来 Go 项目开发的基础,极大地改善了版本控制和构建复现性。

相关推荐
虽千万人 吾往矣7 分钟前
golang channel源码
开发语言·后端·golang
_十六19 分钟前
文档即产品!工程师必看的写作密码
前端·后端
radient20 分钟前
线上FullGC问题如何排查 - Java版
后端·架构
6confim24 分钟前
掌握 Cursor:AI 编程助手的高效使用技巧
前端·人工智能·后端
知其然亦知其所以然34 分钟前
面试官问我 Java 原子操作,我一句话差点让他闭麦!
java·后端·面试
Lx35235 分钟前
📌K8s生产环境排错之:那些暗黑操作
后端·kubernetes
栗筝i40 分钟前
Spring Boot 核心模块全解析:12 个模块详解及作用说明
java·spring boot·后端
Cache技术分享43 分钟前
55. Java 类和对象 - 了解什么是对象
java·后端
楽码1 小时前
理解go指针和值传递
后端·go·编程语言