1.1 安装 Go
Windows 安装(你的环境)
- 打开官方下载页:https://go.dev/dl/
- 下载
go<版本>.windows-amd64.msi(例如go1.26.x.windows-amd64.msi) - 双击安装,一路下一步即可。默认安装路径是
C:\Program Files\Go - 安装程序会自动把 Go 加入 PATH
验证安装
打开一个新的 cmd 窗口(重要:旧窗口不会刷新环境变量),运行:
go version
看到类似输出就成功了:
go version go1.26.0 windows/amd64
如果提示「'go' 不是内部或外部命令」,说明 PATH 没生效。重启电脑,或手动把
C:\Program Files\Go\bin加到系统 PATH。
1.2 关键概念:GOROOT 与 GOPATH
装完 Go,你会遇到两个路径概念。现代 Go(1.11+)你基本不用管它们,但了解一下有好处:
| 概念 | 含义 | 类比 |
|---|---|---|
GOROOT |
Go 安装目录(含标准库源码) | Node.js 安装目录 |
GOPATH |
你的工作区,第三方包和编译产物放这里 | 全局 node_modules |
注意:Go 1.11 引入 Go Modules(go mod)之后,项目不再需要放在 GOPATH 下。你可以把项目放在任何位置(比如你的 D:\Project_Test\AIStudy\Go\)。这也是现代 Go 项目的标准做法。
1.3 配置国内代理(强烈推荐)
Go 下载第三方包默认从 proxy.golang.org 拉,国内访问慢甚至失败。装完后第一件事就是配置国内代理:
go env -w GOPROXY=https://goproxy.cn,direct
go env -w GO111MODULE=on
这两条命令会写入 Go 的环境配置文件(不是系统环境变量),对当前用户全局生效。
验证:
go env GOPROXY应输出https://goproxy.cn,direct。
如果您在设置之前启动了其它终端,需要重启一下那个终端才生效。
1.4 配置 VSCode
VSCode 是你已经在用的编辑器,对 Go 支持非常好。
安装 Go 扩展
- 打开 VSCode,进入扩展面板(
Ctrl+Shift+X) - 搜索
Go,安装官方的Go Team at Google出品的扩展(图标是 Go gopher)
触发工具链安装
安装扩展后,一般几秒钟后,VSCode 会提示你安装 Go 的辅助工具(gopls 语言服务器、调试器等)。点「Install All」全部安装。如果没弹出提示,手动触发:按 Ctrl+Shift+P → 输入 Go: Install/Update Tools → 全选 → 确定。
⚠️ 这些工具会通过
go install下载。如果你忘了配 1.3 的代理,这里会很慢或失败。装不上就回头配代理。
推荐配置
按 Ctrl+Shift+P → Preferences: Open User Settings (JSON),加入以下 Go 相关配置:
{
"go.formatTool": "goimports",
"go.lintTool": "staticcheck",
"go.useLanguageServer": true,
"[go]": {
"editor.formatOnSave": true,
"editor.tabSize": 4,
"editor.insertSpaces": false
},
"gopls": {
"ui.semanticTokens": true
}
}
几个要点:
formatOnSave: true—— 保存自动格式化。Go 社区对代码格式高度统一(用gofmt),不争论花括号位置、缩进风格,编辑器统一处理。insertSpaces: false—— Go 强制用 Tab 缩进(这是语言规范的一部分)。VSCode 装了 Go 扩展会自动处理,但显式设置更保险。
1.5 创建你的第一个 Go 程序
现在创建第一个项目。打开终端,切到你的学习目录:
cd /d D:\Project_Test\AIStudy\Go\code\ch01-hello
这个目录在教程里已经为你建好了,并放好了代码。我们下面一步步看是怎么来的。
第一步:初始化 module
任何一个 Go 项目都从一个 module 开始。在项目目录下运行:
# go mod init 表示初始化一个新的 Go 模块,会生成 go.mod 文件。相当于 npm init。
# github.com/yourname/ch01-hello 这是模块的名字,可以随意自己起名,比如:
# go mod init ch01-hello # ← 纯名字,最简单
# go mod init study/ch01-hello
go mod init github.com/yourname/ch01-hello
这会生成一个 go.mod 文件,内容类似:
module github.com/yourname/ch01-hello
go 1.26.4
对比 Node.js:
| Node.js | Go | |
|---|---|---|
| 初始化 | npm init |
go mod init <模块名> |
| 配置文件 | package.json |
go.mod |
| 锁文件 | package-lock.json |
go.sum |
| 装依赖 | npm install xxx |
go get xxx@version |
模块名(github.com/yourname/ch01-hello)是这个项目的全局唯一标识,类似 npm 的包名。本地学习项目你可以随便起,但公开项目通常用 GitHub 仓库路径,这是 Go 的约定。
什么是 module?
module 就是 go.mod 文件定义的那个东西,它是一组 Go 包(package)的集合 + 版本号 + 依赖清单。
关键判断标准:看有几个 go.mod 文件。
一个 go.mod 文件 = 一个 module
场景 1:一个项目一个 module(主流,90% 的项目)
比如你的博客项目:
blog-api/
├── go.mod ← 整个项目只有这一个 go.mod = 一个 module
├── main.go
└── internal/
├── handler/
├── service/
└── repository/
所有子目录(handler、service 等)都是这个 module 下的不同 package,它们共享同一个 go.mod,共享同一套依赖。这是推荐做法。
场景 2:一个项目多个 module(monorepo)
大公司常见,比如一个仓库里放多个独立的库:
my-monorepo/
├── go.work ← 用 go.work 把多个 module 串起来(Go 1.18+)
├── module-a/
│ ├── go.mod ← module A
│ └── main.go
├── module-b/
│ ├── go.mod ← module B
│ └── main.go
└── shared-lib/
├── go.mod ← module C
└── utils.go
每个子目录有自己的 go.mod,是独立的 module,有独立的依赖版本。go.work 文件让它们在本地开发时能互相引用。
典型例子:Go 官方很多大项目、Kubernetes、字节内部的 eino 生态都是 monorepo + 多 module。
什么是 package ?
这个我们后面会细讲,这里只是简单介绍一下:一个目录就是一个包,一个包里可以有多个go文件,每个go文件开头必须声明:package 包名。同目录下的所有 .go 文件,package 名必须完全一样。
注意:包名可以和目录名不同,但 Go 社区强烈约定包名 = 目录名
项目根目录下的go文件的包名
这个有多种情况,这里先只讲 根目录是「可执行程序入口」的情况:模块根目录下写可执行程序,包名必须是 main,并且必须有 func main()。
// main.go
package main ← 必须是 main!
import "fmt"
func main() { ← 必须有 main 函数!
fmt.Println("Hello")
}
第二步:写代码
在目录下创建 main.go:
package main
import "fmt"
func main() {
fmt.Println("Hello, Go!")
}
(教程里已经放好了完整版本,你可以直接用。)
第三步:运行
go run main.go
输出:
Hello, Go!
🎉 你的第一个 Go 程序跑起来了!
1.6 程序骨架逐行解读
别小看这五行代码,它包含了 Go 程序的所有基础要素:
package main // ① 声明这个文件属于 main 包
import "fmt" // ② 导入标准库 fmt(格式化输出)
func main() { // ③ main 函数是程序入口
fmt.Println("Hello, Go!") // ④ 调用 fmt 包的 Println 函数
}
① package main —— 包声明
每个 .go 文件第一行必须是包声明。package main 是特殊的——它告诉 Go「这是一个可执行程序,而不是库」。
package main+func main()= 可执行程序(window下能编译成 .exe)- 其他
package xxx= 库,被别人 import 使用
对比:相当于 Node.js 里区分「应用入口」和「npm 包」。
② import "fmt" —— 导入包
导入标准库的 fmt 包(format 缩写),用于格式化输入输出。
import "fmt"
// 多个包可以这样写:
import (
"fmt"
"os"
"strings"
)
对比 Node.js:
// Node.js
const fmt = require('fmt') // ❌ 不存在,类比而已
const { println } = require('./utils')
// Go
import "fmt" // 标准
import "github.com/gin-gonic/gin" // 第三方
⚠️ Go 和 Node.js 的关键差异:Go 不允许导入未使用的包。如果你写了 import "fmt" 但没用 fmt,编译直接报错。这是 Go 强制的简洁性。
③ func main() —— 入口函数
main 函数是程序入口,必须在 main 包里,必须没有参数和返回值。
对比:相当于 Node.js 脚本从上到下执行,但 Go 必须有显式的 main 函数。
④ fmt.Println(...) —— 函数调用
调用 fmt 包里的 Println 函数。
注意:Go 中函数名首字母大小写有特殊含义(1.9 节详讲):
Println首字母大写 → 公开(导出),外部可以调用println首字母小写 → 私有,只在包内可用
fmt.Println 是大写 P,所以它是对外公开的。这是 Go 的可见性规则,非常重要,后面会反复遇到。
1.7 常用命令速查
学完这章,记住这几个命令就够了:
| 命令 | 作用 | 类比 nodejs |
|---|---|---|
go mod init <name> |
初始化项目 | npm init |
go run main.go |
直接运行(不产出文件) | node main.js |
go build |
编译成二进制 | tsc 或 pkg |
go build -o app.exe |
编译并指定输出名 | — |
go install |
编译并装到 GOPATH/bin | npm install -g |
go get <pkg> |
下载依赖 | npm install |
go fmt |
格式化代码 | prettier |
go vet |
静态检查 | eslint |
go test |
跑测试 | npm test |
试一下编译命令:
go build -o hello.exe main.go
会在当前目录生成 hello.exe(约 2MB)。直接运行:
hello.exe
这就是 Go 的杀手锏:编译出来的二进制自带所有依赖,不需要装 Go 也能跑。这点完胜 Node.js(需要装 Node + node_modules)。
1.8 Node.js ↔ Go 对照表
| 概念 | Node.js | Go | 备注 |
|---|---|---|---|
| 包管理 | npm | go mod | Go 没有中央注册中心,用 Git 仓库地址 |
| 初始化 | npm init |
go mod init <name> |
Go 必须给模块名 |
| 依赖清单 | package.json |
go.mod |
|
| 锁文件 | package-lock.json |
go.sum |
|
| 装依赖 | npm install xxx |
go get xxx |
|
| 运行 | node xxx.js |
go run xxx.go |
Go 不产生二进制 |
| 编译打包 | webpack / pkg | go build |
Go 产出单一可执行文件 |
| 入口 | 文件从上到下 | func main() |
Go 必须有 main 函数 |
| 输出 | console.log |
fmt.Println |
|
| 格式化字符串 | 模板字符串 ` ` | fmt.Sprintf("%s", x) |
Go 用 C 风格占位符 |
1.9 包与 import 快速了解
你可能一直在想:前面写的
package main和import "fmt"到底是什么?go mod init又是干嘛的?这一节把这些最小够用的概念一次讲清楚,让你后续章节不再一头雾水。⚠️ 这是「速成版」,只讲前 8 章会用到的最小集。第 09 章会系统讲 internal 包、项目结构、依赖管理等进阶内容。
1.9.1 package —— 每个文件的「身份证」
你注意到了吗——每个 .go 文件第一行都是 package xxx。这行叫包声明,告诉 Go「这个文件属于哪个包」。
package main // ← 这个文件属于 main 包
包是什么? 你可以把它理解成「一组相关代码的名字」。就像 JS 里一个文件夹是一个模块,Go 里一个目录就是一个包。
1.9.2 package main 的特殊性
为什么我们的程序都写 package main?因为 main 是个特殊名字:
package main+func main()= 这是一个可执行程序(能编译成 .exe)package xxx(其他名字)= 这是一个库,给别人 import 用,不能直接运行
// main.go —— 可执行程序
package main // ← main 是特殊包
func main() { // ← 必须有 main 函数(程序入口)
fmt.Println("hi")
}
对比 Node.js:Node.js 的入口是「从上到下执行文件」,Go 的入口是「找 package main 里的 func main」。
1.9.3 import —— 借用别人的代码
你写 import "fmt" 就是告诉 Go:「我要用 fmt 这个包」。fmt 是标准库(Go 自带)的格式化输出包。
import "fmt" // 导入单个
import ( // 导入多个(推荐这种写法)
"fmt"
"os"
"strings"
)
然后用的时候要加包名前缀:
fmt.Println("hi") // fmt 包的 Println 函数
os.Getwd() // os 包的 Getwd 函数
⚠️ Go 不允许导入未使用的包——如果你写了 import "os" 但代码里没用 os,直接编译报错。这是 Go 强制的简洁性(不像 JS 那样可以 import 了不用)。
1.9.4 大小写决定「能不能被别人用」
这是 Go 最独特的设计:首字母大写的标识符能被别的包访问,小写的只能在本包内用。
package mathutil
func Add(a, b int) int { ... } // 大写 A:别的包能用 mathutil.Add
func helper() { ... } // 小写 h:只有 mathutil 包内能用
package main
import "xxx/mathutil"
mathutil.Add(1, 2) // ✅ 大写,能用
// mathutil.helper() // ❌ 小写,访问不到
为什么用大小写而不是 public/private 关键字? Go 觉得这样更简洁——一眼就能看出某个东西是公开还是私有。这个规则后续会大量遇到,记住「大写=公开,小写=私有」就行。
1.9.5 go mod —— 项目的「身份证」
还记得 1.5 节你跑了 go mod init 吗?它生成了 go.mod 文件:
module github.com/yourname/ch01-hello
go 1.22
这是什么?
module那行:这个项目的全局唯一名字(类似 npm 包名)go 1.22:这个项目用的 Go 版本
类比 Node.js:
go.mod≈package.json(项目配置)module 名≈ npm 包名go mod init≈npm init
后续装第三方库时,go.mod 会自动记录依赖(类似 package.json 的 dependencies)。
1.9.6 go run vs go build
| 命令 | 作用 | 类比 Node.js |
|---|---|---|
go run main.go |
直接运行(不生成文件) | node main.js |
go build |
编译成二进制 | (JS 没有直接对应,类似 webpack 打包) |
go run 是开发时用的(快),go build 是发布时用的(生成独立的 .exe,拷到任何机器都能跑,不需要装 Go)。
💬 评论 0
还没有评论,快来抢沙发吧~