From 18f20079fc848472aa208c6c3110e49688690e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=AE=E7=AC=91?= Date: Fri, 27 Dec 2024 09:57:11 +0800 Subject: [PATCH] [nix/zh-cn] Add translation (#5220) --- zh-cn/nix.md | 359 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 359 insertions(+) create mode 100644 zh-cn/nix.md diff --git a/zh-cn/nix.md b/zh-cn/nix.md new file mode 100644 index 00000000..3298aafd --- /dev/null +++ b/zh-cn/nix.md @@ -0,0 +1,359 @@ +--- +name: Nix +filename: learnnix-cn.nix +contributors: + - ["Chris Martin", "http://chris-martin.org/"] + - ["Rommel Martinez", "https://ebzzry.io"] + - ["Javier Candeira", "https://candeira.com/"] +translators: + - ["Smile", "https://wiki.dev-hub.top"] +--- + +Nix 是一个为 [Nix 包管理器](https://nixos.org/nix/) 和 [NixOS](https://nixos.org/) 开发的简单函数式语言。 + +你可以使用 [nix-instantiate](https://nixos.org/nix/manual/#sec-nix-instantiate) 或 [`nix repl`](https://nixos.org/nix/manual/#ssec-relnotes-2.0) 来评估 Nix 表达式。 + +```nix +with builtins; [ + + # 注释 + #========================================= + + # 行内注释看起来像这样。 + + /* 多行注释 + 看起来像这样。 */ + + + # 布尔值 + #========================================= + + (true && false) # 与 + #=> false + + (true || false) # 或 + #=> true + + (if 3 < 4 then "a" else "b") # 条件 + #=> "a" + + + # 整数和浮点数 + #========================================= + + # 有两种数值类型:整数和浮点数 + + 1 0 42 (-3) # 一些整数 + + 123.43 .27e13 # 一对浮点数 + + # 运算将保留数值类型 + + (4 + 6 + 12 - 2) # 加法 + #=> 20 + (4 - 2.5) + #=> 1.5 + + (7 / 2) # 除法 + #=> 3 + (7 / 2.0) + #=> 3.5 + + + # 字符串 + #========================================= + + "字符串字面量用双引号括起来。" + + " + 字符串字面量可以跨越 + 多行。 + " + + '' + 这被称为“缩进字符串”字面量。 + 它智能地去除前导空白。 + '' + + '' + a + b + '' + #=> "a\n b" + + ("ab" + "cd") # 字符串连接 + #=> "abcd" + + # 反引号允许你在字符串中嵌入值。 + ("Your home directory is ${getEnv "HOME"}") + #=> "Your home directory is /home/alice" + + + # 路径 + #========================================= + + # Nix 有一个用于路径的原始数据类型。 + /tmp/tutorials/learn.nix + + # 相对路径在解析时相对于它出现的文件解析为绝对路径。 + tutorials/learn.nix + #=> /the-base-path/tutorials/learn.nix + + # 路径必须至少包含一个斜杠,因此同一目录中的文件的相对路径需要一个 ./ 前缀, + ./learn.nix + #=> /the-base-path/learn.nix + + # 如果你希望 / 运算符表示除法,它必须被空格包围。 + + 7/2 # 这是一个路径字面量 + (7 / 2) # 这是整数除法 + + + # 导入 + #========================================= + + # 一个 nix 文件包含一个没有自由变量的顶级表达式。一个导入表达式评估为它导入的文件的值。 + (import /tmp/foo.nix) + + # 导入也可以通过字符串指定。 + (import "/tmp/foo.nix") + + # 导入路径必须是绝对路径。路径字面量会自动解析,因此这没问题。 + (import ./foo.nix) + + # 但字符串不会这样。 + (import "./foo.nix") + #=> 错误:字符串‘foo.nix’不代表绝对路径 + + + # Let + #========================================= + + # `let` 块允许我们将值绑定到变量。 + (let x = "a"; in + x + x + x) + #=> "aaa" + + # 绑定可以相互引用,并且它们的顺序无关紧要。 + (let y = x + "b"; + x = "a"; in + y + "c") + #=> "abc" + + # 内部绑定会覆盖外部绑定。 + (let a = 1; in + let a = 2; in + a) + #=> 2 + + + # 函数 + #========================================= + + (n: n + 1) # 添加 1 的函数 + + ((n: n + 1) 5) # 同一个函数,应用于 5 + #=> 6 + + # 没有命名函数的语法,但它们可以像任何其他值一样通过 `let` 块绑定。 + (let succ = (n: n + 1); in succ 5) + #=> 6 + + # 一个函数恰好有一个参数。 + # 多个参数可以通过柯里化实现。 + ((x: y: x + "-" + y) "a" "b") + #=> "a-b" + + # 我们还可以有命名函数参数, + # 我们将在引入集合后再讨论。 + + + # 列表 + #========================================= + + # 列表用方括号表示。 + + (length [1 2 3 "x"]) + #=> 4 + + ([1 2 3] ++ [4 5]) + #=> [1 2 3 4 5] + + (concatLists [[1 2] [3 4] [5]]) + #=> [1 2 3 4 5] + + (head [1 2 3]) + #=> 1 + (tail [1 2 3]) + #=> [2 3] + + (elemAt ["a" "b" "c" "d"] 2) + #=> "c" + + (elem 2 [1 2 3]) + #=> true + (elem 5 [1 2 3]) + #=> false + + (filter (n: n < 3) [1 2 3 4]) + #=> [ 1 2 ] + + + # 集合 + #========================================= + + # “集合”是一个无序的字符串键映射。 + { foo = [1 2]; bar = "x"; } + + # . 运算符从集合中提取一个值。 + { a = 1; b = 2; }.a + #=> 1 + + # ? 运算符测试一个键是否存在于集合中。 + ({ a = 1; b = 2; } ? a) + #=> true + ({ a = 1; b = 2; } ? c) + #=> false + + # // 运算符合并两个集合。 + ({ a = 1; } // { b = 2; }) + #=> { a = 1; b = 2; } + + # 右边的值覆盖左边的值。 + ({ a = 1; b = 2; } // { a = 3; c = 4; }) + #=> { a = 3; b = 2; c = 4; } + + # rec 关键字表示一个“递归集合”, + # 其中属性可以相互引用。 + (let a = 1; in { a = 2; b = a; }.b) + #=> 1 + (let a = 1; in rec { a = 2; b = a; }.b) + #=> 2 + + # 嵌套集合可以分段定义。 + { + a.b = 1; + a.c.d = 2; + a.c.e = 3; + }.a.c + #=> { d = 2; e = 3; } + + # 集合是不可变的,因此你不能重新定义一个属性: + { + a = { b = 1; }; + a.b = 2; + } + #=> 属性 'a.b' 在 (string):3:5 处已在 (string):2:11 处定义 + + # 然而,即使属性本身已被直接赋值,属性的集合成员也可以分段定义。 + { + a = { b = 1; }; + a.c = 2; + } + #=> { a = { b = 1; c = 2; }; } + + + # With + #========================================= + + # `with` 块的主体在集合的映射绑定到变量时进行评估。 + (with { a = 1; b = 2; }; + a + b) + # => 3 + + # 内部绑定会覆盖外部绑定。 + (with { a = 1; b = 2; }; + (with { a = 5; }; + a + b)) + #=> 7 + + # 本教程的第一行以 "with builtins;" 开始, + # 因为 builtins 是一个包含所有内置函数(length、head、tail、filter 等)的集合。 + # 这使我们不必写 "builtins.length" 而只需写 "length"。 + + + # 集合模式 + #========================================= + + # 当我们需要将多个值传递给函数时,集合很有用。 + (args: args.x + "-" + args.y) { x = "a"; y = "b"; } + #=> "a-b" + + # 这可以用集合模式更清晰地写出来。 + ({x, y}: x + "-" + y) { x = "a"; y = "b"; } + #=> "a-b" + + # 默认情况下,模式在包含额外键的集合上失败。 + ({x, y}: x + "-" + y) { x = "a"; y = "b"; z = "c"; } + #=> error: anonymous function called with unexpected argument ‘z’ + + # 添加 ", ..." 允许忽略额外的键。 + ({x, y, ...}: x + "-" + y) { x = "a"; y = "b"; z = "c"; } + #=> "a-b" + + # 整个集合可以使用 `@` 绑定到一个变量 + (args@{x, y}: args.x + "-" + args.y) { x = "a"; y = "b"; } + #=> "a-b" + + # 错误 + #========================================= + + # `throw` 导致评估中止并显示错误消息。 + (2 + (throw "foo")) + #=> error: foo + + # `tryEval` 捕获抛出的错误。 + (tryEval 42) + #=> { success = true; value = 42; } + (tryEval (2 + (throw "foo"))) + #=> { success = false; value = false; } + + # `abort` 类似于 throw,但它是致命的;它无法被捕获。 + (tryEval (abort "foo")) + #=> error: evaluation aborted with the following error message: ‘foo’ + + # `assert` 如果为真,则评估为给定值; + # 否则它会抛出一个可捕获的异常。 + (assert 1 < 2; 42) + #=> 42 + (assert 1 > 2; 42) + #=> error: assertion failed at (string):1:1 + (tryEval (assert 1 > 2; 42)) + #=> { success = false; value = false; } + + + # 不纯性 + #========================================= + + # 因为构建的可重复性对 Nix 包管理器至关重要, + # 函数式纯度在用于描述 Nix 包的 Nix 语言中得到了强调。 + # 但也有一些不纯之处。 + + # 您可以引用环境变量。 + (getEnv "HOME") + #=> "/home/alice" + + # trace函数用于调试。它将第一个参数打印到stderr,并计算第二个参数。 + (trace 1 2) + #=> trace: 1 + #=> 2 + + # 您可以将文件写入Nix存储。尽管不纯,但这相当安全,因为文件名是从其内容的哈希中派生的。您可以从任何地方读取文件。在此示例中,我们将文件写入存储,然后再读出。 + (let filename = toFile "foo.txt" "hello!"; in + [filename (readFile filename)]) + #=> [ "/nix/store/ayh05aay2anx135prqp0cy34h891247x-foo.txt" "hello!" ] + + # 我们还可以将文件下载到Nix存储中。 + (fetchurl "https://example.com/package-1.2.3.tgz") + #=> "/nix/store/2drvlh8r57f19s9il42zg89rdr33m2rm-package-1.2.3.tgz" + +] +``` + +### 进一步阅读 + +* [Nix Manual - Nix表达式语言](https://nixos.org/nix/manual/#ch-expression-language) +* [James Fisher - Nix 示例 - Part 1: The Nix expression language](https://medium.com/@MrJamesFisher/nix-by-example-a0063a1a4c55) +* [Susan Potter - Nix Cookbook - Nix 示例](https://ops.functionalalgebra.com/nix-by-example/) +* [Zero to Nix - Nix教程](https://zero-to-nix.com/) +* [Rommel Martinez - Nix 家族简介](https://web.archive.org/web/20210121042658/https://ebzzry.io/en/nix/#nix)