Skip to content

Commit 2a089ec

Browse files
committed
fix title
1 parent cad64e4 commit 2a089ec

File tree

1 file changed

+12
-11
lines changed

1 file changed

+12
-11
lines changed

content/post/2025-01-23-bonkers-comptime.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ author: xihale
44
date: 2025-01-23T12:00:00+08:00
55
---
66

7-
> 原文: <https://www.scottredig.com/blog/bonkers_comptime/>
8-
> 译注:原文中的代码快是交互式,翻译时并没有移植这一块。另外,由于 comptime 本身即是关键概念,并且下文的意思更侧重于 Zig comptime 的特性,故下文大多使用 comptime 代替(涵盖)编译时概念。
7+
> 原文: <https://www.scottredig.com/blog/bonkers_comptime/>
8+
9+
> 译注:原文中的代码快是交互式,翻译时并没有移植这一块。另外,由于 comptime 本身即是关键概念,并且下文的意思更侧重于 Zig comptime 的特性,故下文大多使用 comptime 代替编译时概念。
910
1011
## 引子
1112

@@ -17,7 +18,7 @@ date: 2025-01-23T12:00:00+08:00
1718

1819
为了明确起见,所有示例都是有效的 Zig 代码,但示例中的转换只是概念性的,它们并不是 Zig 实际的实现方式。
1920

20-
## 视角1: 忽略它
21+
## 视角0: 忽略它
2122

2223
我说我喜欢这个特性,却又立刻叫你忽略它,这确实有点怪。但我认为此处正是 Zig comptime 威力所体现的地方,所以我将从这里出发。Zig Zen 中的第三条是“倾向于阅读代码,而不是编写代码。”确实,能够轻松地阅读代码在各种情况下都很重要,因为它是建立概念理解的基础,而这种理解也是调试或修改代码所必需的。
2324

@@ -146,7 +147,7 @@ pub fn main() !void {
146147
}
147148
```
148149

149-
确实很简单。但是,每当讨论如何优化 Fizz Buzz 算法时,人们总是忽略一个事实:标准的 Fizz Buzz 问题只需要输出前100个数字的结果。既然输出是固定的,那为什么不直接预先计算出答案,然后输出呢?(由此,我时常认为那些有关优化讨论有些滑稽的。)
150+
确实很简单。但是,每当讨论如何优化 Fizz Buzz 算法时,人们总是忽略一个事实:标准的 Fizz Buzz 问题只需要输出前100个数字的结果。既然输出是固定的,那为什么不直接预先计算出答案,然后输出呢?(由此,我时常认为那些有关优化讨论有些滑稽的。)
150151
我们可以使用相同的 Fizz Buzz 函数来实现这一点。
151152

152153
```Zig
@@ -225,7 +226,7 @@ onst MyStruct = struct {
225226
inline for (comptime std.meta.fieldNames(MyStruct)) |field_name| {
226227
sum += @field(my_struct, field_name);
227228
}
228-
229+
229230
// 这可以展开为:
230231
{
231232
const field_name = "a";
@@ -249,7 +250,7 @@ onst MyStruct = struct {
249250
};
250251
```
251252

252-
上面的示例是我们手动展开后的示例,但这项工作是由 Zig 的 comptime 完成的。这使得我们可以直接独立而完整地编写出我们要实现的功能,而不需要添加"当你改变 `MyStruct` 的字段时,记得更新 sum 函数"这样的由于依赖于 `MyStruct` 具体字段而预防功能失效的注释。
253+
上面的示例是我们手动展开后的示例,但这项工作是由 Zig 的 comptime 完成的。这使得我们可以直接独立而完整地编写出我们要实现的功能,而不需要添加"当你改变 `MyStruct` 的字段时,记得更新 sum 函数"这样的由于依赖于 `MyStruct` 具体字段而预防功能失效的注释。
253254
基于 comptime 的版本在 `MyStruct` 的任何字段变更时都可以正确地自动处理。
254255

255256
## 视角4:Comptime 求值,运行时代码生成
@@ -310,8 +311,6 @@ const MyStruct = struct {
310311

311312
下有两例。第一个是一个元编程的示例,第二个是我们熟悉的 comptime 示例。这两个版本的代码有着相同的逻辑。
312313

313-
> 元编程
314-
315314
```Zig
316315
pub fn writeSumFn(
317316
writer: std.io.AnyWriter,
@@ -328,7 +327,7 @@ pub fn writeSumFn(
328327
}
329328
```
330329

331-
注意这里有两个转换:
330+
注意这里有两个转换:
332331
1. 在生成器中直接运行的代码是 comptime 的一部分
333332
2. 在生成器执行后输出的代码,成为运行时的一部分
334333

@@ -359,11 +358,11 @@ pub fn writeMyStructOfType(
359358
}
360359
```
361360

362-
以上 struct 字段的生成体现了上述两种转换(`conversions`)方式,并且将两者混合在了一行中。 字段的类型表达式由生成器/运行时完成,而字段本身则作为运行时代码使用的定义。
361+
以上 struct 字段的生成体现了上述两种转换方式,并且将两者混合在了一行中。 字段的类型表达式由生成器/运行时完成,而字段本身则作为运行时代码使用的定义。
363362

364363
在 comptime 下,引用类型名称的方式更加直接,可以直接使用函数,而不必将文本拼接成一个在代码生成中保持一致的名称。
365364

366-
这种观点有一个例外。 您可以创建字段名称在编译时就已确定的类型,但这样做需要调用一个内置函数,该函数包含一个字段定义列表。 因此,您无法在这些类型上定义方法等声明。 在实践中,这并不会限制代码的表达能力,但确实限制了你可以向其他代码公开哪些类型的 API。
365+
这种观点有一个例外。 您可以创建字段名称在编译时就已确定的类型,但这样做需要调用一个内置函数,该函数包含一个字段定义列表。 因此,您无法在这些类型上定义方法等声明。 在实践中,这并不会限制代码的表达能力,但确实限制了你可以向其他代码公开哪些类型的 API。
367366

368367
与本节相关的是文本宏,如 C 语言中的文本宏。你可以做的大多数正常事情都可以在 comptime 中完成,尽管它们很少采用类似的形式。 不过,文本宏并不能做所有允许做的事情。 例如,你不能决定不喜欢某个 Zig 关键字,然后让宏代替你自己的关键字。 我认为这是一个正确的决定,尽管对于那些习惯了这种能力的人来说,这是一个艰难的过渡。 此外,Zig 参考了半个世纪以来的程序员在这方面的探索,所以它的选择要理智得多。
369368

@@ -386,3 +385,5 @@ Zig 并非一个仅仅依赖 comptime 这一特性的语言。你可以在[官
386385

387386
Zig 的函数可以具有几种不同的返回类型。但是,这并不是依赖于编译器中的某些魔法的操作,而只是[典型的 comptime 的应用](https://github.com/ziglang/zig/blob/0.13.0/lib/std/start.zig#L508)
388387

388+
> 如果您希望就本篇文章向我提出意见或更正,请发送电子邮件至 [email protected]
389+
> 译者注:如果觉得翻译有问题,请提 PR 改正:<https://github.com/zigcc/zigcc.github.io>

0 commit comments

Comments
 (0)