Menu

Golang 是什么?Go 语言详解与示例

Go(常被称为 Golang)是一门静态类型的编译型语言,由 Google 设计,用来构建快速、可靠的服务器和工具。本页介绍 Go 是什么、用来做什么,以及它的不足之处。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

Go 是一门由 Google 创造的静态类型编译型编程语言。它生成单个原生二进制文件,几秒内就能完成编译,带有垃圾回收,并通过 goroutine 和通道把并发直接内置在语言里。它的主要阵地是服务器端软件:API、网络服务,以及运行这些服务的命令行工具和云计算工具。

下面是一个完整的 Go 程序。点击“运行”。

每个 Go 程序都从 package main 中的 func main() 开始。:= 声明一个变量并推断它的类型(这里是 []string,即字符串切片)。range 遍历切片,每次给你一个下标和一个值。fmt 和 strings 来自标准库,标准库足够丰富,很多程序除此之外什么都不用导入。

Go 还是 Golang:名字的由来

这门语言叫 Go。“Golang”是来自项目第一个网站 golang.org 的别称(网站现在位于 go.dev)。人们一直沿用这个叫法,因为在网上搜索“go”会搜出各种东西,偏偏找不到这门语言。官方文档写的是“Go”,但几乎所有人在搜索框里输入的都是“golang”,两者指的是同一个东西。并不存在单独的“Golang”产品或方言。

谁创造了 Go,为什么

Robert Griesemer、Rob Pike 和 Ken Thompson 于 2007 年在 Google 开始设计 Go。它在 2009 年 11 月开源发布,Go 1.0 于 2012 年 3 月发布。

初衷非常务实。Google 庞大的 C++ 和 Java 代码库构建耗时很长,依赖关系难以管理;多核机器和网络服务已经是常态,但编写并发代码却很容易出错。Go 的设计直接回应了这些问题:

  • 构建快。 导入是显式的,未使用的导入是编译错误,编译器也不会反复解析头文件,所以大型程序几秒内就能构建完成。
  • 语言简单。 关键字很少,只有一种循环(for),没有继承,没有异常。不同人写的代码往往风格相近,这对大团队的代码评审很有帮助。
  • 并发是语言特性。 启动一个并发任务只需一个关键字 go,任务之间通过通道通信。
  • 部署容易。 产出物就是一个二进制文件,复制到服务器上即可。它通常是静态链接的;启用 cgo 时,net 等包可能会链接系统的 C 库,设置 CGO_ENABLED=0 可以关闭这一点。

Go 1.0 还带来了 Go 1 兼容性承诺:为 Go 1.0 编写的程序在后续的 1.x 版本中依然可以编译和运行。实际上这意味着升级工具链很少会让你的代码出问题,这也是团队放心用 Go 开发长期维护服务的一大原因。

Golang 用来做什么

当程序需要和网络打交道、需要长时间运行、又要方便交付时,Go 最能发挥优势:

领域示例
Web API 和微服务HTTP 和 gRPC 服务,Web 和移动应用的后端
云和基础设施工具Docker、Kubernetes、Terraform、Prometheus
命令行工具每个平台只需一个二进制文件的开发者 CLI
网络代理、负载均衡器、DNS 服务器
数据管道读取队列、转换记录、写入数据库的 worker

对于桌面 GUI 应用、移动应用、浏览器前端,以及数值计算或机器学习,它就不太合适了,这些领域里其他生态的库要好得多。

核心特性与代码

带类型推断的静态类型

每个变量的类型都在编译时确定,但你很少需要把它写出来。:= 会自动推断:

Go 从不在数值类型之间进行隐式转换。count * price 无法通过编译,因为一个是 int,另一个是 float64;你需要自己写 float64(count)。这样就杜绝了悄无声息的截断和精度问题。

错误就是值

Go 没有异常。可能失败的函数会把 error 作为最后一个返回值,由调用方检查:

if err != nil 是 Go 代码里最有辨识度的一行。它确实啰嗦,而这正是用意所在:程序每一个可能失败的地方,都在发生的位置清清楚楚地写着。包装和检查错误的方法见错误处理。

goroutine 和通道

goroutine 是一个与程序其余部分并发运行的函数。它只占用几 KB 的栈空间,所以同时运行成千上万个也很正常。通道可以在 goroutine 之间安全地传递值:

三个 goroutine 并发运行,所以这三行可能以任意顺序打印。多运行几次,你可能会看到不同的顺序。main 正好接收三个值,所以它会等它们全部到达后才退出。

没有“implements”的接口

一个类型只要拥有对应的方法,就满足了某个接口。没有 implements 关键字:

Rect 和 Circle 从未提到 Shape,但两者都可以存进 []Shape。这让你可以在使用接口的包里定义它,哪怕具体类型早就写好了。

一套工具链

go 命令包揽一切:go run 编译并运行,go build 生成二进制文件,go test 运行测试,go fmt 格式化代码,go vet 找出可疑的写法,go mod 管理依赖。官方只有一种格式化风格,由 gofmt 强制执行,所以 Go 项目不会为大括号或缩进争论不休。

Go 有意舍弃的功能

其他语言里常见的一些功能,Go 是故意不提供的:

  • 没有类和继承。 你使用结构体、方法、接口和嵌入。
  • 没有异常。 错误是返回值。panic 确实存在,但它用于 bug,而不是普通的失败。
  • 没有三元运算符。 你要写 if/else。
  • 没有 while 关键字。 for 涵盖所有循环。
  • 没有函数重载,也没有默认参数。
  • 泛型从 Go 1.18 才有, 而且相比 C++ 模板或 Java 泛型,是有意做了限制的。

真实的取舍

啰嗦。 显式的错误检查,加上没有三元运算符这类简写,让 Go 代码比同等功能的 Python 或 Kotlin 更长。读起来很轻松,写起来行数更多。

垃圾回收。 Go 的垃圾回收器停顿时间很短,但它终究是垃圾回收器。对于硬实时系统,或者每一次内存分配都很关键的代码,C、C++ 或 Rust 能给你更多控制权。

nil 值。 Go 有 nil 指针、map、切片和接口。对 nil 指针解引用会导致运行时 panic,编译器不会像 Rust 的类型系统那样阻止它。

类型系统较小。 没有和类型,没有枚举(要用常量和 iota 自己实现),泛型能覆盖常见场景,但不支持高级的类型层面编程。

生态短板。 Web 服务、数据库和云 API 方面的库非常出色。但在 GUI、科学计算和机器学习方面,Python、C++ 或 Julia 的库要多得多。

Go 与其他语言对比

GoPythonJavaRust
类型静态动态静态静态
运行方式原生二进制解释器JVM 字节码原生二进制
内存垃圾回收垃圾回收垃圾回收所有权,无 GC
并发goroutine、通道线程、asyncio(GIL 限制 CPU 并行)线程、虚拟线程线程、async
学习曲线平缓平缓中等陡峭

如果你想要编译型语言的性能和简单的部署,又不想面对 Rust 的学习曲线或 Java 的繁文缛节,就选 Go。

Go 值得学吗?

如果你写后端服务、命令行工具,或者从事云基础设施相关的工作,答案是肯定的。这个生态里的很多软件都是用 Go 写的,阅读它们的源码本身就是工作的一部分。这门语言很小,所以投入不大:核心语法几天就能掌握,地道的并发和错误处理需要几周的练习。

想在本地开始写 Go,先安装 Go,然后学习 hello world 页面,它会逐行讲解第一个程序。

常见问题

Golang 用来做什么?

主要用于后端和基础设施软件:Web 服务器和 API、微服务、命令行工具、网络程序,以及云计算工具。Docker、Kubernetes、Terraform 和 Prometheus 都是用 Go 写的。它很少用于桌面 GUI、移动应用或数据科学。

Go 和 Golang 是一回事吗?

是的。这门语言的名字是 Go。“Golang”来自最初的网站地址 golang.org,因为“go”这个词很难搜索,这个叫法就流传了下来。两个名字指的是同一门语言、同一套工具链。

Go 编程语言是谁创造的?

Robert Griesemer、Rob Pike 和 Ken Thompson 从 2007 年开始在 Google 设计 Go。它在 2009 年 11 月作为开源项目发布,Go 1.0 于 2012 年 3 月发布,Go 的兼容性承诺正是从这个版本开始的。

Go 好学吗?

语言本身很小:25 个关键字,一种循环结构,规范文档短到一个下午就能读完。大多数有其他语言经验的程序员几天之内就能写出可用的 Go 代码。需要更长时间的是惯用写法:显式的错误处理、接口,以及用 goroutine 和通道写出正确的并发代码。

Go 是编译型还是解释型语言?

编译型。go build 会生成原生机器码的二进制文件,不依赖解释器或虚拟机。go run 同样会编译,只是把结果构建到一个临时位置再运行。

Coddy 编程语言插图

和 Coddy 一起学编程

开始