From 4250ad775e6a829ec8fbb7fdca1614919095733c Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 25 Sep 2025 10:18:40 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=A4=A7=E4=BF=AENix=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=E5=BF=AB=E9=80=9F=E5=85=A5=E9=97=A8=EF=BC=88=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E9=83=A8=E5=88=86=EF=BC=89=20-=20=E5=9C=A8=E6=AD=A3=E6=96=87?= =?UTF-8?q?=E5=BC=80=E5=A4=B4=E6=B7=BB=E5=8A=A0=E5=85=B3=E4=BA=8E=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=E7=9A=84=E8=AF=B4=E6=98=8E=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=85=B3=E4=BA=8E=E9=9B=86=E5=90=88=E7=9A=84=E8=AF=B4=E6=98=8E?= =?UTF-8?q?=20-=20=E4=BF=AE=E6=94=B9=20let=20=E7=BB=91=E5=AE=9A=E4=B8=80?= =?UTF-8?q?=E8=8A=82=20-=20=E5=B0=86=E7=BC=A9=E8=BF=9B=E4=B8=8E=E6=8D=A2?= =?UTF-8?q?=E8=A1=8C=E7=A7=BB=E5=8A=A8=E5=88=B0=E6=B3=A8=E9=87=8A=E9=83=A8?= =?UTF-8?q?=E5=88=86=20-=20=E8=B0=83=E6=95=B4=E7=AB=A0=E8=8A=82=E7=BB=93?= =?UTF-8?q?=E6=9E=84=20-=20=E4=B8=80=E4=BA=9B=E5=B0=8F=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tutorials/lang/QuickOverview.md | 143 ++++++++++++++-------------- 1 file changed, 69 insertions(+), 74 deletions(-) diff --git a/src/tutorials/lang/QuickOverview.md b/src/tutorials/lang/QuickOverview.md index ff647ae6..c839eefd 100644 --- a/src/tutorials/lang/QuickOverview.md +++ b/src/tutorials/lang/QuickOverview.md @@ -155,7 +155,36 @@ let a = builtins.div 2 0; b = 3; in b **好了,下面正式介绍 Nix 语法。** -## 名称和值 +## 注释、缩进与换行 +- 注释:在 Nix 语言中,用 `#` 表示注释,在它之后直到行末的部分都会被忽略。 +- 缩进与换行:与 Python 这种对缩进有要求的语言不同,在 Nix 语言中,大多数情况下,换行与缩进只是为了更好的可读性,并不影响代码的本质。 + +例如,下面有两段示例代码(你目前还不需要理解它们的含义),它们在本质上(也即在 Nix 解释器看来)并没有区别。 + +第一例: +```nix +foo = { a = 1; b = 2; } +``` + +第二例: +```nix +foo = { # 这是一句注释,放在代码末尾。 + # 这也是一句注释,单独占了一行。 + a = 1; # 这里即使不缩进,也不影响代码本质。 + b = 2; + # c = 3; # 这里的代码被注释掉了,相当于不存在。 +} +``` + + +::: warning +换行与空格一样具有分隔作用,请勿在不可分隔的地方胡乱断行。 + + +::: + +## 赋值与集合 +### 名称和值 我们可以使用 `=` 为名称绑定值,形成赋值语句。例如将名称 `foo` 赋值为 `123`: @@ -164,9 +193,10 @@ foo = 123 ``` -::: info 名称与变量的区别 -名称不等同常见编程语言中的变量。 -传统的赋值会改变变量的状态,而 Nix 语言中的名称一旦赋值(定义)就无法改变。 +::: info 名称与其它语言中变量的区别 +在很多语言中,赋值会改变变量的状态,而 Nix 语言中的名称一旦赋值(定义)就无法改变。 + +不过,将 Nix 中的名称称为变量也没问题。 ::: @@ -182,7 +212,7 @@ foo = 123 - 列表(list),例如 `[ 1 "tux" false ]` - 属性集(attribute set),例如 `{ a = 1; b = "tux"; c = false; }` -## 属性集 +### 属性集 在 Nix 语法中,属性集(简称集合)是最常见的数据类型之一,基本示例如下: @@ -203,26 +233,6 @@ foo = { - 集合以 `{` `}` 为边界,其内部为多个赋值语句,且各个赋值语句末尾必须添加 `;` 。 - -::: info 换行与缩进 -对于 Nix 语言,大多数情况下,换行与缩进只是为了更好的可读性。 - -例如,上述代码与下面的代码在本质上并没有区别: - -```nix -foo = { a = 1; b = 2; }; -``` - - -::: - - -::: warning -换行与空格一样具有分隔作用,请勿在不可分隔的地方胡乱断行。 - - -::: - 上述代码将 `foo` 的值定义为集合 `{ a = 1; b = 2; }` ,因此可称之为集合 `foo` 。 集合 `foo` 中有两个属性: @@ -258,7 +268,7 @@ foo.b.d = 3; ::: -## 递归属性集 +### 递归属性集 普通的属性集不支持递归引用,举个例子: ```nix @@ -286,7 +296,7 @@ rec { { a = 1; b = 3; } ``` -可以看到,结果中的 `a = 1` 在前面,`b = 2` 在后面。这种顺序实际上与任何其它因素(包括声明顺序、求值依赖关系)都无关,而只与**属性名称本身的排序**有关。例如,对 `rec { a = 1; b = 2; }` 与 `rec { b = 2; a = 1; }` 的求值,都会把 `a = 1` 放在前面,归因到底,这只是因为 `a` 在字母表中位于 `b` 之前罢了。(直接原因则与 Nix 解释器对名称排序所用到的算法或者调用的库有关,这里不再深入。) +可以看到,结果中的 `a = 1` 在前面,`b = 3` 在后面。这种顺序实际上与任何其它因素(包括声明顺序、求值依赖关系)都无关,而只与**属性名称本身的排序**有关。例如,对 `rec { a = 1; b = 2; }` 与 `rec { b = 2; a = 1; }` 的求值,都会把 `a = 1` 放在前面,归因到底,这只是因为 `a` 在字母表中位于 `b` 之前罢了。(直接原因则与 Nix 解释器对名称排序所用到的算法或者调用的库有关,这里不再深入。) 既然如此,将上面属性集里的两个元素位置对调: ```nix @@ -295,7 +305,7 @@ rec { a = 1; } ``` -你会发现,Nix 也能自动处理求值顺序,并不会因为 `a` 的声明被调整到后面而影响求值结果(与之前的完全一致,这里就不贴了)。这看起来相当“智能”,你甚至可以写得更复杂一些,比如 Nix 也能自动处理下面的例子(结果略): +你会发现,Nix 解释器能自动处理求值顺序,并不会因为 `a` 的声明被调整到后面而影响求值结果(与之前的完全一致,从略)。这看起来相当“智能”,你甚至可以写得更复杂一些,比如 Nix 解释器也能自动处理下面的例子(结果略): ```nix rec { c = a * 2 - b + d - 35; @@ -319,53 +329,44 @@ rec { b = «error: infinite recursion encountered»; } ``` -从这个输出来看,我们可以发现递归属性集内部在处理求值顺序的机制,确实是递归的,而如果递归陷入死循环就会报错。 - -## `let` 绑定 - -一个完整的 `let` 绑定有两个部分: `let` 绑定名称与值, `in` 使用名称。在 `let` -与 `in` 之间的语句中,你可以声明需要被复用的名称,并将其与值绑定。它们可以在 -`in` 之后的表达式中发挥作用: +由此可见,递归属性集内部处理求值顺序的机制,确实是递归的,而如果递归陷入死循环就会报错。 +### 列表 +之前我们学习了属性集,它含有多个元素,例如: ```nix -let - b = a + 1; - a = 1; -in - a + b +fruits = { + a = "apple"; + b = "orange"; + c = "banana"; +} ``` +上面的名称 `a` `b` `c` 或许可以有明确的含义,但有时我们不需要这些名称,而只关心后面的值,这种情况下就可以使用列表,例如: +```nix +fruits = [ "apple" "orange" "banana" ] +``` +需要注意语法细节: +- 列表以 `[` `]` 为边界,其内部为多个元素,每个元素都是值(value)而不是赋值语句。 +- 元素之间使用空格(或换行)分隔,各元素**不**以 `;` 结尾。 -引用到 `a` 的地方有两处,它们都会将 `a` "替换"成值来计算或赋值,类似于常量。 - - -::: tip -你不需要关心名称的声明顺序,不会出现名称未定义的情况。 - - -::: - -**`in` 后面只能跟随一个表达式,并且 `let` 绑定的名称只在该表达式是有效的的**,这 -里演示一个列表: +## let 绑定与属性访问 +### `let` 绑定 +有时我们希望定义一个变量,使其不影响全局,仅在局部生效。此时就可以使用 `let` 绑定,示例如下: ```nix let - b = a + 1; - c = a + b; a = 1; + b = 2; in - [ a b c ] + a + b # 结果是 2 ``` -输出的值为: - -```nix -[ 1 2 3 ] -``` +注意语法细节: +- `let` 与 `in` 之间的赋值语句以 `;` 结尾; +- `in` 之后**只有一个表达式**。 -::: danger 作用域 -**`let` 绑定是有作用域的,绑定的名称只能在作用域使用,或者说每个 `let` 绑定的名 -称只能在该表达式内使用:** +::: info 作用域 +`let` 绑定是有作用域的,绑定的名称只能在作用域使用,或者说每个 `let` 绑定的名称只能在该表达式内使用。例如下面的例子: ```nix { @@ -374,23 +375,16 @@ in } ``` -`x` 未定义: +由于 `b = x;` 不在作用域之内,会有报错如下: -```bash +``` error: undefined variable 'x' - - at «string»:3:7: - - 2| a = let x = 1; in x; - 3| b = x; - | ^ - 4| } ``` ::: -## 属性访问 +### 属性访问 使用 `.` 访问属性: @@ -419,7 +413,8 @@ in a.b.c ``` -## `with` 表达式 +## 语法糖 `with` 和 `inherit` +### `with` 表达式 `with` 表达式可以让你少写几次属性集的名称,是个语法糖: @@ -463,7 +458,7 @@ error: undefined variable 'x' 11| } ``` -## `inherit` 表达式 +### `inherit` 表达式 `inherit` 本意就是继承,我们可以使用它完成一对命名相同的名称和属性之间的赋值: From aaa4c29f538397dc0f822ae3c85b274604d4f15a Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 25 Sep 2025 10:58:08 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=A4=8D=E5=8E=9F=20let=20=E7=BB=91?= =?UTF-8?q?=E5=AE=9A=E4=B8=80=E8=8A=82=E4=B8=AD=E5=85=B3=E4=BA=8E=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E7=9A=84=E4=BE=8B=E5=AD=90=20=E5=9C=A8=E8=8B=A5?= =?UTF-8?q?=E5=B9=B2=E5=B0=8F=E8=8A=82=E5=BC=80=E5=A4=B4=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E8=AF=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tutorials/lang/QuickOverview.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/tutorials/lang/QuickOverview.md b/src/tutorials/lang/QuickOverview.md index c839eefd..f5acc0ff 100644 --- a/src/tutorials/lang/QuickOverview.md +++ b/src/tutorials/lang/QuickOverview.md @@ -156,6 +156,8 @@ let a = builtins.div 2 0; b = 3; in b **好了,下面正式介绍 Nix 语法。** ## 注释、缩进与换行 +注释、缩进与换行的语法与机制,对编程语言的风格有重要影响。本节将介绍 Nix 语言中的注释、缩进与换行。 + - 注释:在 Nix 语言中,用 `#` 表示注释,在它之后直到行末的部分都会被忽略。 - 缩进与换行:与 Python 这种对缩进有要求的语言不同,在 Nix 语言中,大多数情况下,换行与缩进只是为了更好的可读性,并不影响代码的本质。 @@ -184,6 +186,7 @@ foo = { # 这是一句注释,放在代码末尾。 ::: ## 赋值与集合 +与大多数编程语言类似,变量与值是 Nix 语言中最基础的概念。本节将会介绍 Nix 中如何为变量**赋值**,以及最常用的数据类型——**属性集**,继而引出**递归属性集**与**列表**的概念。 ### 名称和值 我们可以使用 `=` 为名称绑定值,形成赋值语句。例如将名称 `foo` 赋值为 `123`: @@ -349,6 +352,7 @@ fruits = [ "apple" "orange" "banana" ] - 元素之间使用空格(或换行)分隔,各元素**不**以 `;` 结尾。 ## let 绑定与属性访问 +前面关于变量的赋值与使用是非常基本的,我们还需要更灵活的处理方法。本节将会介绍用于定义局部变量的 **let 绑定**,以及风格简洁的**属性访问**。 ### `let` 绑定 有时我们希望定义一个变量,使其不影响全局,仅在局部生效。此时就可以使用 `let` 绑定,示例如下: @@ -362,7 +366,19 @@ in 注意语法细节: - `let` 与 `in` 之间的赋值语句以 `;` 结尾; -- `in` 之后**只有一个表达式**。 +- `in` 之后**只有一个表达式**。注意,这只是语法形式上的要求,并不代表 `let` 绑定的用处很有限,因为表达式本身可以很复杂,常见的是嵌套属性集。作为基本示例,下面演示刚刚学到的列表: +``` +let + b = a + 1; + c = a + b; + a = 1; +in + [ a b c ] +``` +求值的结果如下: +``` +[ 1 2 3 ] +``` ::: info 作用域 @@ -414,6 +430,7 @@ in ``` ## 语法糖 `with` 和 `inherit` +语法糖(syntactic sugar)是对语言功能没有影响,但更方便使用的一种语法。本节将介绍两种常用的语法糖 `with` 和 `inherit`。 ### `with` 表达式 `with` 表达式可以让你少写几次属性集的名称,是个语法糖: From fa57f278b297fde9d3684e4f5f8826b4983a689b Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 25 Sep 2025 11:01:26 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E7=BB=99=E4=BB=A3=E7=A0=81=E5=9D=97?= =?UTF-8?q?=E8=A1=A5=E4=B8=8Anix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tutorials/lang/QuickOverview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tutorials/lang/QuickOverview.md b/src/tutorials/lang/QuickOverview.md index f5acc0ff..a3a480af 100644 --- a/src/tutorials/lang/QuickOverview.md +++ b/src/tutorials/lang/QuickOverview.md @@ -367,7 +367,7 @@ in 注意语法细节: - `let` 与 `in` 之间的赋值语句以 `;` 结尾; - `in` 之后**只有一个表达式**。注意,这只是语法形式上的要求,并不代表 `let` 绑定的用处很有限,因为表达式本身可以很复杂,常见的是嵌套属性集。作为基本示例,下面演示刚刚学到的列表: -``` +```nix let b = a + 1; c = a + b; From 241f44ce44e2883421badb933cc716582f198ebb Mon Sep 17 00:00:00 2001 From: "Celestial.y" Date: Thu, 25 Sep 2025 11:35:49 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=9D=A2=E5=90=91?= =?UTF-8?q?=E7=BB=B4=E6=8A=A4=E8=80=85=E7=9A=84=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tutorials/lang/QuickOverview.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tutorials/lang/QuickOverview.md b/src/tutorials/lang/QuickOverview.md index a3a480af..27960574 100644 --- a/src/tutorials/lang/QuickOverview.md +++ b/src/tutorials/lang/QuickOverview.md @@ -10,6 +10,10 @@ ::: +
面向本文维护者的说明,单击以切换折叠/展开 +请留心说明顺序,讲 let 绑定时如果举了一个列表的例子,你需要确保前面已经正式介绍过列表。再如,讲 with 语法糖的时候同时用到 let 绑定和列表,那么这两个概念都需要在前面已经正式介绍过。否则,读者就会面对初次接触的语法或者概念而感到迷惑,这会严重影响学习效率。若出于顺序安排的其他合理性原因,实在无法避开在说明中涉及陌生的初见概念,可以提示读者相关部分不需要理解,后面会讲到。 +
+ Nix 作为语言,是一门简单的函数式语言,它被专门设计并用于 Nix 包管理器及相关生态 (NixOS、Home-Manager 等)。 From 9e2f48f677ea6faa07948c745d69fc1e009dbed5 Mon Sep 17 00:00:00 2001 From: "Celestial.y" Date: Thu, 25 Sep 2025 12:05:11 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=BB=B4=E6=8A=A4?= =?UTF-8?q?=E8=80=85=E8=AF=B4=E6=98=8E=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tutorials/lang/QuickOverview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tutorials/lang/QuickOverview.md b/src/tutorials/lang/QuickOverview.md index 27960574..64ff7311 100644 --- a/src/tutorials/lang/QuickOverview.md +++ b/src/tutorials/lang/QuickOverview.md @@ -10,8 +10,8 @@ ::: -
面向本文维护者的说明,单击以切换折叠/展开 -请留心说明顺序,讲 let 绑定时如果举了一个列表的例子,你需要确保前面已经正式介绍过列表。再如,讲 with 语法糖的时候同时用到 let 绑定和列表,那么这两个概念都需要在前面已经正式介绍过。否则,读者就会面对初次接触的语法或者概念而感到迷惑,这会严重影响学习效率。若出于顺序安排的其他合理性原因,实在无法避开在说明中涉及陌生的初见概念,可以提示读者相关部分不需要理解,后面会讲到。 +
仅面向本文维护者的说明,单击以切换折叠/展开 +本文在设计上是线性的,也即只需要读者具备一点点基础,就可以通过按顺序从头读到尾的方式完成本文的学习。因此,请留心说明顺序,例如讲 let 绑定时如果举了一个列表的例子,你需要确保前面已经正式介绍过列表。再如,讲 with 语法糖的时候同时用到 let 绑定和列表,那么这两个概念都需要在前面已经正式介绍过。否则,读者很可能会面对初次接触的语法或者概念而被卡住,这会严重影响学习效率甚至是完成率。若出于顺序安排的其他合理性原因,实在无法避开在说明中涉及陌生概念,可以提示读者相关部分不需要理解,后面会讲到。
Nix 作为语言,是一门简单的函数式语言,它被专门设计并用于 Nix 包管理器及相关生态