惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
阮一峰的网络日志
阮一峰的网络日志
G
Google Developers Blog
J
Java Code Geeks
Blog — PlanetScale
Blog — PlanetScale
大猫的无限游戏
大猫的无限游戏
云风的 BLOG
云风的 BLOG
Vercel News
Vercel News
L
LangChain Blog
Hugging Face - Blog
Hugging Face - Blog
T
The Blog of Author Tim Ferriss
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Stack Overflow Blog
Stack Overflow Blog
P
Proofpoint News Feed
腾讯CDC
博客园_首页
博客园 - 聂微东
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
M
MIT News - Artificial intelligence
WordPress大学
WordPress大学
D
DataBreaches.Net
Microsoft Security Blog
Microsoft Security Blog
有赞技术团队
有赞技术团队
博客园 - 叶小钗

Chongxiの咖啡屋

Google相册迁移到iCloud分享 - Chongxiの咖啡屋 讲讲「万物皆虚,万事皆允」 - Chongxiの咖啡屋 舞萌DX 落雪查分器使用指南 - Chongxiの咖啡屋 现代人的刻舟求剑 - Chongxiの咖啡屋 舞萌DX错误码0010深度解析及处理方法 - Chongxiの咖啡屋 做了一个明日方舟-奇象巡展的像素画拼豆工具 - Chongxiの咖啡屋 舞萌DX国服封禁机制详解 - Chongxiの咖啡屋 舞萌开机网络自检底层技术说明,断网如何排查讲解 - Chongxiの咖啡屋 舞萌机台开机初始化进程详解 - Chongxiの咖啡屋 为什么喜欢音乐 反而不该去学音乐? - Chongxiの咖啡屋 从装逼到嘉豪:中国互联网的精神胜利进化史 - Chongxiの咖啡屋 游蒋介石故居:奉化溪口 - Chongxiの咖啡屋 钢铁雄心4 steam正版导入全DLC补丁 - Chongxiの咖啡屋 漫漫长夜全地图及介绍 - Chongxiの咖啡屋 记一次无需实名换绑米哈游通行证手机号 - Chongxiの咖啡屋 邮储银行万事达借记卡全面指南 - Chongxiの咖啡屋 x402:一个来自27年前的状态码能救活被ai榨干的「人类网站」吗 - Chongxiの咖啡屋 舞萌国人口大普查:全服玩家数据分析 - Chongxiの咖啡屋 家中网络「捉奸」记 - Chongxiの咖啡屋 中国移动PT927G光猫折腾指南:破解超级密码改桥接 - Chongxiの咖啡屋 最好用的Android邮件客户端推荐 - Chongxiの咖啡屋 如何验证对方是不是Chongxi我本人 - Chongxiの咖啡屋 三星S20系列刷入移植OneUI8流程 - Chongxiの咖啡屋 使用obisidian和git插件来完美管理静态博客 - Chongxiの咖啡屋 玩客云拆机教程 - Chongxiの咖啡屋 母语级英语的本质,不是英语 - Chongxiの咖啡屋 我用过最好用的Android桌面(启动器) - Chongxiの咖啡屋 1. 区块链基本知识 - Chongxiの咖啡屋 b站创作激励提现几乎无门槛了 - Chongxiの咖啡屋 速报:APKPure 版 Telegram 被植入恶意后门 - Chongxiの咖啡屋
Ch.02:Go程序是怎么运行的 - Chongxiの咖啡屋
Chongxi · 2026-05-01 · via Chongxiの咖啡屋

在此之前我们装好了环境,跑通了 Hello。但你有没有想过,你写的那几行魔法,计算机怎么跑起来的

在真正开始写代码之前,先花一篇的时间搞清楚这件事,不需要太深入底层,但理解这个过程,会让你少点疑问

计算机只认识 0 和 1#

计算机本质上是一堆电路,电路只有两种状态:通电和断电。人类用 1 表示通电,0 表示断电,这就是二进制

所有的程序,最终都要变成一串 0 和 1,CPU 才能执行。但没有人会直接写 0 和 1,太痛苦了。所以人类发明了编程语言,用接近自然语言的方式写代码,再让工具把它翻译成机器能懂的东西

这个翻译的过程,有两种主流方式

编译型 vs 解释型#

编译型语言#

先把整个源代码翻译成机器码,生成一个可执行文件,然后再运行。翻译这个动作叫编译,做这件事的工具叫编译器

Go 是编译型语言。你写好代码,go build 一下,生成一个二进制文件,直接运行,不需要任何额外环境

PRTCL // PLAINTEXT

源代码 → 编译器 → 可执行文件 → 运行

优点是运行快,因为机器码直接在 CPU 上跑。缺点是每次改完代码都要重新编译

解释型语言

不提前翻译,运行的时候边读代码边执行。做这件事的工具叫解释器

Python 是解释型语言。你写好代码,python hello.py,解释器一行一行读,一行一行执行

PRTCL // PLAINTEXT

源代码 → 解释器 → 运行(边翻译边执行)

优点是改完代码立刻能跑,开发方便。缺点是运行速度比编译型慢,因为翻译是实时发生的


Go 是编译型,但提供了 go run 让你感觉像解释型:它在后台帮你编译,编译完立刻运行,临时文件放在系统缓存目录里,你不用关心中间过程

学习阶段用 go run,部署的时候用 go build,这个习惯记住就行

Go 程序的基本结构#

回头看上一篇那个:

PRTCL // GO

package main

import "fmt"

func main() {

fmt.Println("Hello, Go!")

}

package#

每个文件都属于一个包

Go 的代码是用包(package) 来组织的。每个 .go 文件的第一行,必须声明自己属于哪个包

main 是一个特殊的包名,意思是”这是程序的入口”。Go 运行的时候,会找 package main 里的 main 函数,从那里开始执行

如果你把 package main 改成 package hello,这个文件就变成了一个库,不能直接运行。包的组织方式后面会专门讲,现在只需要记住:能直接运行的程序,包名一定是 main

import#

引入别人写好的代码

import 的意思是”引入这个包,我要用”。fmt 是 Go 标准库里的一个包,提供格式化输入输出的功能

引入多个包时用括号括起来:

PRTCL // GO

import (

"fmt"

"time"

)

Go 有一个强规定:引入了包必须用,不然报错

PRTCL // GO

import (

"fmt"

"time"

)

func main() {

fmt.Println("hello")

// time 没用

}

// 报错:time imported and not used

这个设计和变量必须被使用一样,目的是保持代码干净,不留垃圾

如果有时候你确实需要引入一个包但不直接调用它(比如只需要它的初始化副作用),这时候用 _ 匿名引入:

PRTCL // GO

import _ "some/package"

还可以给包起别名,在包名太长或者有冲突的时候用:

PRTCL // GO

import (

f "fmt"

)

func main() {

f.Println("hello") // 用别名 f 代替 fmt

}

func main()#

程序从这里开始

PRTCL // GO

func main() {

// 代码写在这里

}

func 是定义函数的关键字,main 是函数名,() 是参数列表,现在是空的,{} 里面是函数体

Go 程序启动时,自动从 func main() 的第一行开始,从上到下依次执行,执行完程序就结束了

遇到函数调用时,会跳进那个函数执行完,再回到原来的位置继续往下走:

PRTCL // GO

func main() {

fmt.Println("第一行") // 1. 先执行这里

fmt.Println("第二行") // 2. 再执行这里

fmt.Println("第三行") // 3. 最后这里

}

输出永远是按顺序的:

PRTCL // PLAINTEXT

第一行

第二行

第三行

这个顺序执行的概念听起来理所当然,但你要真正记住它,因为后面学并发的时候,这个顺序会被打破

fmt.Println#

PRTCL // GO

fmt.Println("Hello, Go!")

fmt 是包名,Println 是这个包里的一个函数,. 是”属于”的意思

注意 Println 的首字母是大写的。在 Go 里,大小写决定了一个东西能不能被外部访问

  • 大写字母开头:公开的,其他包可以用
  • 小写字母开头:私有的,只有同一个包内部能用

fmt.Println 之所以能被我们调用,就是因为它首字母大写,是公开的。如果 Go 官方把它写成 fmt.println,你就调用不了

这个规则贯穿整个 Go,函数、变量、结构体,都遵守这个规定,后面会反复遇到

为什么花括号不能换行#

你可能注意到,Go 的开括号 { 必须和函数声明在同一行:

PRTCL // GO

// 正确

func main() {

fmt.Println("hello")

}

// 报错

func main()

{

fmt.Println("hello")

}

Go 在编译之前,会自动在某些行末尾插入分号。规则很简单:如果一行最后一个词是标识符、数字、字符串,或者 )]} 这类符号,就自动加分号

所以 func main() 这一行,因为最后是 ),编译器会自动加分号变成 func main();,然后下一行的 { 就成了孤立的符号,语法错误

{ 放在同一行就不会触发这个规则

注释#

注释是写给人看的,编译器会完全忽略它

单行注释:

PRTCL // GO

// 这是注释

fmt.Println("hello") // 行尾注释

多行注释:

实际项目里单行注释用得更多。多行注释一般用来临时屏蔽一段代码,调试的时候很方便

多个文件组成一个程序#

现在你写的程序只有一个文件,但真实项目不可能把所有代码塞进一个文件里

Go 允许同一个包的代码分散在多个文件里:

PRTCL // PLAINTEXT

golearn/

main.go

helper.go

main.go

PRTCL // GO

package main

import "fmt"

func main() {

fmt.Println(greet("Chongxi"))

}

helper.go

PRTCL // GO

package main

func greet(name string) string {

return "你好," + name

}

两个文件都声明了 package main,Go 会把它们当成同一个包处理。运行的时候:

PRTCL // BASH

go run main.go helper.go

# 或者

go run . # 运行当前目录所有 .go 文件

函数和变量的概念后面会讲,这里只是让你知道多文件是怎么回事,不用深究

工具链#

Go 自带一套工具,开发过程中会经常用到

go run

编译并立刻运行,适合开发阶段:

PRTCL // BASH

go run hello.go

go build

编译生成可执行文件,适合生产部署:

PRTCL // BASH

go build hello.go

./hello

go fmt

自动格式化代码,解决所有缩进和换行问题:

PRTCL // BASH

go fmt hello.go # 格式化单个文件

go fmt ./... # 格式化当前目录所有文件

养成习惯,写完代码跑一下 go fmt,不要手动纠结格式

go vet

静态检查,帮你找代码里的潜在问题,比如格式化字符串用错了类型:

PRTCL // BASH

go vet hello.go

go vet 不报错不代表代码一定对,但它报错了就一定有问题,要认真看

go doc

查看任何包或函数的文档,不用开浏览器:

PRTCL // BASH

go doc fmt

go doc fmt.Println

标准库文档#

Go 的标准库文档在 pkg.go.dev/std,所有官方包都在这里,每个函数都有说明和示例

比如你想知道 fmt 里还有哪些函数,打开 pkg.go.dev/fmt 就能看到

遇到不认识的函数或者不确定怎么用,先查这里。标准库文档是 Go 最权威的参考资料


小结#

本篇偏概念,现在来过一遍:

  • Go 属于编译型语言,先翻译再运行
  • 每个文件必须声明 package,能直接运行的程序包名是 main
  • import 引入包,引入了必须用或者_匿名,可以起别名
  • 程序从 func main() 开始,从上到下顺序执行
  • 大写字母开头是公开的,小写是私有的
  • 花括号不能换行, Go 有自动分号插入机制
  • go fmt 格式化,go vet 静态检查,go doc 查文档

下一篇会讲真正有意思的部分:边亮变量