2026-06-07 11:08:10 +08:00
|
|
|
|
---
|
2026-06-07 12:14:39 +08:00
|
|
|
|
tags: [go, golang, go基础语法, go程序结构]
|
|
|
|
|
|
create time: 2026-06-07 15:00
|
2026-06-07 11:08:10 +08:00
|
|
|
|
---
|
|
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
# Go 语言代码结构
|
2026-06-07 11:08:10 +08:00
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
## 概述
|
2026-06-07 11:08:10 +08:00
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
本文介绍 Go 程序的最基本组成:包声明、导入、`main` 函数和注释,并通过 Hello World 示例带你跑通第一个 Go 程序。
|
|
|
|
|
|
|
|
|
|
|
|
## 正文
|
|
|
|
|
|
|
|
|
|
|
|
### 一个 Go 程序由什么构成?
|
|
|
|
|
|
|
|
|
|
|
|
在深入语法细节之前,先思考一个问题:**"如果让你写一个能打印 'Hello, World!' 的 Go 程序,你知道它最少需要几行代码?"**
|
|
|
|
|
|
|
|
|
|
|
|
答案是 **5 行**(不算空行和注释)。下面这个最小可运行的 Go 程序展示了所有核心要素:
|
2026-06-07 11:08:10 +08:00
|
|
|
|
|
|
|
|
|
|
```go
|
2026-06-07 12:14:39 +08:00
|
|
|
|
package main // 1. 包声明
|
2026-06-07 11:08:10 +08:00
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
import "fmt" // 2. 导入包
|
2026-06-07 11:08:10 +08:00
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
func main() { // 3. main 函数(程序入口)
|
|
|
|
|
|
fmt.Println("Hello, World!") // 4. 调用函数 + 自动换行
|
2026-06-07 11:08:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
2026-06-07 12:14:39 +08:00
|
|
|
|
|
|
|
|
|
|
> [!question] ❓ 思考
|
|
|
|
|
|
> - `package main` 为什么必须是第一行非注释代码?
|
|
|
|
|
|
> - 如果去掉 `import "fmt"`,程序还能编译通过吗?
|
|
|
|
|
|
> - `main()` 函数可以带参数吗?如果不写 `()` 会怎样?
|
|
|
|
|
|
|
|
|
|
|
|
每一行的作用如下:
|
|
|
|
|
|
|
|
|
|
|
|
| 要素 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `package main` | 声明包名。`main` 包表示这是一个**可执行程序**(而非库) |
|
|
|
|
|
|
| `import "fmt"` | 导入标准库 `fmt`,提供格式化输入输出功能 |
|
|
|
|
|
|
| `func main()` | 程序的**唯一入口**。可执行程序的 `main` 包必须有且仅有一个 `main` 函数 |
|
|
|
|
|
|
| `/* ... */` / `//` | 多行注释 / 单行注释,编译时被忽略 |
|
|
|
|
|
|
| `fmt.Println(...)` | 将内容输出到控制台,末尾自动添加 `\n` |
|
|
|
|
|
|
|
|
|
|
|
|
> [!tip] 💡 Print vs Println
|
|
|
|
|
|
> `fmt.Print` 不会自动换行,`fmt.Println` 会在末尾追加 `\n`。两者都支持变量插值:`fmt.Println(arr, name, age)` 会用默认格式打印所有参数。
|
|
|
|
|
|
|
|
|
|
|
|
### 运行你的第一个程序
|
|
|
|
|
|
|
|
|
|
|
|
保存为 `hello.go` 后,在终端执行:
|
|
|
|
|
|
|
2026-06-07 11:08:10 +08:00
|
|
|
|
```shell
|
|
|
|
|
|
$ go run hello.go
|
|
|
|
|
|
Hello, World!
|
|
|
|
|
|
```
|
2026-06-07 12:14:39 +08:00
|
|
|
|
|
|
|
|
|
|
`go run` 会**编译并立即执行**。如果想单独生成二进制文件,用 `go build`:
|
|
|
|
|
|
|
2026-06-07 11:08:10 +08:00
|
|
|
|
```shell
|
2026-06-07 12:14:39 +08:00
|
|
|
|
$ go build hello.go # 生成 ./hello 二进制文件
|
|
|
|
|
|
$ ./hello # 运行
|
2026-06-07 11:08:10 +08:00
|
|
|
|
Hello, World!
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
> [!note] 📝 go run vs go build
|
|
|
|
|
|
> `go run` 适合快速调试;`go build` 生成独立二进制文件,方便部署和分发。
|
2026-06-07 11:08:10 +08:00
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
### 包与文件的关系
|
2026-06-07 11:08:10 +08:00
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
这是新手最容易困惑的地方。记住三条规则:
|
2026-06-07 11:08:10 +08:00
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
> [!warning] ⚠️ 常见误区
|
|
|
|
|
|
> 1. **文件名 ≠ 包名**:`helloworld.go` 可以是 `package main`
|
|
|
|
|
|
> 2. **文件夹名 ≠ 包名**:目录叫 `myMath`,包名可以是 `mathclass`
|
|
|
|
|
|
> 3. **同目录 = 同包**:同一个文件夹下的 `.go` 文件必须属于同一个包,否则编译报错
|
2026-06-07 11:08:10 +08:00
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
```mermaid
|
|
|
|
|
|
graph LR
|
|
|
|
|
|
A["项目根目录"] --> B["hello/"]
|
|
|
|
|
|
B --> B1["helloworld.go → package main"]
|
|
|
|
|
|
A --> C["mymath/"]
|
|
|
|
|
|
C --> C1["myMath1.go → package mathClass"]
|
|
|
|
|
|
C --> C2["myMath2.go → package mathClass"]
|
2026-06-07 11:08:10 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
**关键点**:`myMath1.go` 和 `myMath2.go` 虽然在不同文件中,但包名都是 `mathClass`,它们共享这个包的命名空间。
|
|
|
|
|
|
|
|
|
|
|
|
### 导出与未导出标识符
|
|
|
|
|
|
|
|
|
|
|
|
Go 没有 `public` / `private` 关键字,而是用**大小写**控制可见性:
|
|
|
|
|
|
|
|
|
|
|
|
> [!note] 📝 导出规则
|
|
|
|
|
|
> - **大写字母开头** → 导出(exported),其他包可以访问,类似 `public`
|
|
|
|
|
|
> - **小写字母开头** → 未导出(unexported),仅限本包内部使用,类似 `private`
|
2026-06-07 11:08:10 +08:00
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
|
package mathClass
|
2026-06-07 12:14:39 +08:00
|
|
|
|
|
|
|
|
|
|
// Add 是大写开头 → 其他包可以调用
|
|
|
|
|
|
func Add(x, y int) int {
|
2026-06-07 11:08:10 +08:00
|
|
|
|
return x + y
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
// sub 是小写开头 → 只能在 mathClass 包内使用
|
|
|
|
|
|
func sub(x, y int) int {
|
2026-06-07 11:08:10 +08:00
|
|
|
|
return x - y
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
> [!warning] ⚠️ 注意
|
|
|
|
|
|
> 如果你导入了一个包却没用它的任何导出符号,Go 编译器会直接报错:`imported and not used`。这强制你保持代码整洁。
|
2026-06-07 11:08:10 +08:00
|
|
|
|
|
2026-06-07 12:14:39 +08:00
|
|
|
|
## 关联笔记
|
|
|
|
|
|
- [[hzh/GolangStar/Go语言基础/Go语言命名规范]]
|
|
|
|
|
|
- [[hzh/GolangStar/Go语言基础/Go语言变量]]
|