Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
251 changes: 251 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,254 @@ zig build
cd course/code/15/build_system
zig build
```

## 文档编写规范

### 文档与代码分离原则

本项目要求**代码示例必须与 Markdown 文档分离**,不允许将代码内联到 Markdown 中。这样做的目的是:

1. **可测试性**:所有代码示例都能通过 `zig build` 进行编译验证
2. **版本兼容性**:不同 Zig 版本可以维护各自的代码实现
3. **代码质量**:通过单元测试确保示例代码的正确性

### 添加新文档章节的完整流程

以添加一个新的教程章节为例,完整流程如下:

#### 步骤 1:创建代码示例文件

**路径**: `course/code/15/<topic>.zig`(15 为当前活跃版本)

代码文件结构规范:

```zig
const std = @import("std");

// 主入口函数,用于运行所有示例
pub fn main() !void {
Example1.main();
Example2.main();
try Example3.main();
}

// 使用结构体封装每个代码片段
const Example1 = struct {
// #region example1_anchor
// 这里是将在文档中显示的代码
const SomeType = struct {
field: u32,
};

pub fn main() void {
const val: SomeType = .{ .field = 42 };
std.debug.print("value: {}\n", .{val.field});
}
// #endregion example1_anchor
};

const Example2 = struct {
// #region example2_anchor
// 另一个代码片段
pub fn main() void {
// ...
}
// #endregion example2_anchor
};

// 文件末尾添加单元测试
test "example1 test" {
// 测试 Example1 的功能
}

test "example2 test" {
// 测试 Example2 的功能
}
```

**关键规范**:

- 使用 `#region <anchor_name>` 和 `#endregion <anchor_name>` 标记代码片段
- 每个逻辑片段封装在独立的结构体中
- 提供 `pub fn main()` 用于运行时验证
- 提供 `test` 用于单元测试验证
- anchor 名称使用 `snake_case` 风格

#### 步骤 2:创建 Markdown 文档

**路径**: `course/<category>/<topic>.md`

文档结构规范:

```markdown
---
outline: deep
---

# 章节标题

> 简短的章节描述或引言

正文内容...

## 小节标题

解释性文字...

<<<@/code/release/<topic>.zig#example1_anchor

更多解释...

<<<@/code/release/<topic>.zig#example2_anchor
```

**代码引用语法**:

- `<<<@/code/release/<file>.zig#<anchor>` - 引用指定锚点的代码片段
- `release` 是符号链接,指向当前最新稳定版本(如 15)
- 锚点名称必须与代码文件中的 `#region` 名称完全匹配

#### 步骤 3:更新导航配置

**路径**: `course/.vitepress/sidebar.ts`

在适当的章节中添加新页面:

```typescript
{
text: "进阶学习",
items: [
// ... 其他条目
{
text: "新章节标题",
link: "/advanced/new-topic",
},
],
},
```

#### 步骤 4:验证和格式化

```bash
# 1. 验证代码编译
zig build

# 2. 运行代码测试
zig build test

# 3. 格式化所有文件
bun format

# 4. 检查格式
bun check

# 5. 本地预览文档
bun dev
```

### 代码片段标记详解

#### 基本标记

```zig
// #region anchor_name
const Example = struct {
// 代码内容
};
// #endregion anchor_name
```

#### 嵌套标记(用于显示不同详细程度)

```zig
// #region more_example
const std = @import("std");

// #region default_example
const Point = struct {
x: i32,
y: i32,
};
// #endregion default_example

pub fn main() void {
const pt: Point = .{ .x = 1, .y = 2 };
std.debug.print("({}, {})\n", .{ pt.x, pt.y });
}
// #endregion more_example
```

在 Markdown 中可以选择性引用:

```markdown
::: code-group

<<<@/code/release/example.zig#default_example [default]

<<<@/code/release/example.zig#more_example [more]

:::
```

### 文档样式规范

#### Markdown 格式

- 使用 `---` 分隔的 front matter,通常包含 `outline: deep`
- 一级标题 `#` 用于页面主标题
- 二级标题 `##` 用于主要章节
- 三级标题 `###` 用于子章节

#### 提示框语法

```markdown
:::info 🅿️ 提示
提示内容
:::

:::warning 警告
警告内容
:::

:::details 可折叠内容标题
详细内容
:::
```

#### 中英文排版

- 中英文之间添加空格:`这是 Zig 语言`
- 技术术语首次出现时标注英文:`**结果位置语义(Result Location Semantics)**`
- 代码相关使用反引号:`` `comptime` ``

### 多版本代码维护

当需要为不同 Zig 版本维护不同代码时:

1. 在对应版本目录创建代码文件:`course/code/14/<topic>.zig`、`course/code/15/<topic>.zig`
2. 如果版本间完全兼容,使用符号链接避免重复
3. 在 Markdown 中始终使用 `release` 引用,自动指向最新版本

### 完整示例:添加"结果位置语义"章节

```
1. 创建代码文件
course/code/15/result-location.zig
- 包含所有示例的结构体封装
- 使用 #region/#endregion 标记
- 添加 main() 函数和单元测试

2. 创建文档文件
course/advanced/result-location.md
- front matter 配置
- 使用 <<<@/code/release/result-location.zig#anchor 引用代码

3. 更新导航
course/.vitepress/sidebar.ts
- 在"进阶学习"部分添加条目

4. 验证
zig build # 编译验证
bun format # 格式化
bun dev # 本地预览
```
4 changes: 4 additions & 0 deletions course/.vitepress/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ export default [
text: "类型转换",
link: "/advanced/type_cast",
},
{
text: "结果位置语义",
link: "/advanced/result-location",
},
{
text: "内存管理",
link: "/advanced/memory_manage",
Expand Down
119 changes: 119 additions & 0 deletions course/advanced/result-location.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
---
outline: deep
---

# 结果位置语义

> Result Location Semantics 是 Zig 类型系统的核心机制之一,它允许编译器根据上下文自动推断类型。

在 Zig 中,许多表达式的类型不是由表达式本身决定的,而是由表达式的**使用方式**决定的。这种机制被称为**结果位置语义(Result Location Semantics)**。

## 什么是结果位置语义

结果位置语义是指编译器根据表达式结果的**存储位置**(即"结果位置")来推断表达式类型的机制。

简单来说,当你写 `.{ .x = 1, .y = 2 }` 这样的表达式时,编译器会查看这个值将被赋给什么类型的变量,然后自动推断出正确的类型。

<<<@/code/release/result-location.zig#basic_inference

## 结果类型

**结果类型(Result Type)** 是编译器期望表达式产生的类型。它由表达式的上下文决定:

### 变量声明

当变量有显式类型声明时,右侧表达式的结果类型就是该变量的类型:

<<<@/code/release/result-location.zig#result_type_variable

### 函数返回值

函数的返回类型决定了 `return` 表达式的结果类型:

<<<@/code/release/result-location.zig#result_type_return

### 函数参数

函数参数类型决定了调用时传入表达式的结果类型:

<<<@/code/release/result-location.zig#result_type_param

### 结构体字段默认值

结构体字段的类型决定了默认值表达式的结果类型:

<<<@/code/release/result-location.zig#result_type_field_default

## 结果位置

**结果位置(Result Location)** 是指表达式结果将被存储的内存位置。Zig 编译器会将结果位置的信息传递给子表达式,这使得某些优化成为可能。

### 嵌套结构的结果位置传播

结果位置信息会传播到嵌套的子表达式:

<<<@/code/release/result-location.zig#result_location_nested

## 声明字面量

**声明字面量(Decl Literals)** 是 Zig 0.14.0 引入的语法特性。它扩展了枚举字面量语法 `.foo`,使其不仅可以引用枚举成员,还可以引用目标类型上的任何声明。

### 基本用法

<<<@/code/release/result-location.zig#decl_literal_basic

由于 `val` 的类型是 `S`,编译器知道 `.default` 应该在 `S` 的命名空间中查找,因此 `.default` 等价于 `S.default`。

### 在结构体字段默认值中使用

声明字面量在设置字段默认值时特别有用:

<<<@/code/release/result-location.zig#decl_literal_field_default

### 调用函数

声明字面量也支持调用函数:

<<<@/code/release/result-location.zig#decl_literal_function

### 与错误联合类型配合

声明字面量支持通过 `try` 调用返回错误联合的函数:

<<<@/code/release/result-location.zig#decl_literal_error_union

## 避免错误的字段默认值

声明字面量的一个重要应用是避免**错误的字段默认值(Faulty Default Field Values)**问题。

### 问题示例

考虑以下代码:

<<<@/code/release/result-location.zig#faulty_default_problem

这里的问题是 `ptr` 和 `len` 是相互关联的,但默认值允许用户只覆盖其中一个,导致数据不一致。

### 使用声明字面量的解决方案

<<<@/code/release/result-location.zig#faulty_default_solution

## 标准库中的应用

从 Zig 0.14.0 开始,标准库中的许多类型都采用了声明字面量模式。

### ArrayListUnmanaged

<<<@/code/release/result-location.zig#stdlib_arraylist

### GeneralPurposeAllocator

<<<@/code/release/result-location.zig#stdlib_gpa

## 字段和声明不可重名

Zig 0.14.0 引入了一项限制:容器类型(`struct`、`union`、`enum`、`opaque`)的字段和声明不能同名。

<<<@/code/release/result-location.zig#naming_conflict

这个限制是为了消除 `MyType.foo` 到底是访问字段还是声明的歧义。
2 changes: 1 addition & 1 deletion course/basic/advanced_type/struct.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@

在前面我们学习了结构体字面量的完整语法 `StructName{ .field = value }`。当 Zig 编译器能够从上下文推断出结构体类型时,可以省略类型名称,使用简写语法 `.{ .field = value }`。

这种机制被称为**结果位置语义(Result Location Semantics)**。
这种机制被称为**[结果位置语义(Result Location Semantics)](../../advanced/result-location.md)**。

<<<@/code/release/struct.zig#struct_init_inferred

Expand Down
Loading
Loading