Nix 备忘清单 === Nix 快速参考备忘单,旨在帮助编写基础的 Nix 代码。Nix 是一个纯函数式包管理器和 NixOS 系统的基础语言。 类型与语法 --- ### 字符串 ```nix let x = "单行字符串"; y = '' 多行字符串 支持换行和缩进 ''; z = '' 前导空格会被自动处理 这行会保持缩进 ''; in ``` #### 字符串插值 ```nix let name = "世界"; greeting = "你好,${name}!"; in ``` #### 转义字符 ```nix let escaped = '' 引号:\"hello\",换行:\n,制表符:\t ''; in ``` ### 整数 ```nix let x = -123; y = 123; # 支持不同进制 hex = 0xFF; # 十六进制: 255 bin = 0b1010; # 二进制: 10 oct = 0o755; # 八进制: 493 in ``` ### 浮点数 ```nix let x = -0.32; y = 0.45; scientific = 1.23e-4; # 科学记数法 inf = 1.0 / 0.0; # 无穷大 in ``` ### 布尔值 ```nix let x = true; y = false; # 布尔运算 and_result = true && false; # false or_result = true || false; # true not_result = !true; # false in ``` ### 空值 ```nix let x = null; # null 表示缺失值 # 类似于其他语言的 None 或 undefined in ``` ### 路径 ```nix let absolute = /usr/bin/env; # 绝对路径 relative = ./config.nix; # 相对路径 home = ~/Documents; # 家目录路径 # 路径会在构建时自动复制到 Nix store in ``` ### 属性集 ```nix let x = { name = "张三"; age = 25; address = { city = "北京"; district = "朝阳区"; }; }; y = { c = 3; }; # 递归属性集 rec_set = rec { x = 1; y = x + 1; # 可以引用同级属性 }; in ``` 参见 [属性集操作](#属性集) ### 列表 ```nix let numbers = [ 1 2 3 4 5 ]; mixed = [ 1 "这是字符串" 23.0 null { name = "属性集"; } ]; # 列表可以包含任意类型的元素 nested = [ [ 1 2 ] [ 3 4 ] ]; in ``` ### 注释 #### ↓ 单行注释 ```nix # 这是单行注释 let x = 1; in x # 行末注释 ``` #### ↓ 多行注释 ```nix /* 这是多行注释 可以跨越多行 /* 可以嵌套 */ */ ``` 作用域管理 --- ### 定义局部变量 ```nix let x = 1; y = 2; z = x + y; # 可以引用前面定义的变量 in x + y + z # 返回 6 ``` #### 嵌套 let 表达式 ```nix let outer = 10; in let inner = 5; in outer + inner # 返回 15 ``` ### 将变量添加到作用域 ```nix let x = 1; y = 2; in { inherit x y; } # 继承多个变量 ``` #### ↓ 等价于 ```nix let x = 1; y = 2; in { x = x; y = y; } ``` ### 从属性集继承属性 ```nix let config = { host = "localhost"; port = 8080; ssl = true; }; in { inherit (config) host port; # 只继承特定属性 } ``` #### ↓ 等价于 ```nix let config = { host = "localhost"; port = 8080; ssl = true; }; in { host = config.host; port = config.port; } ``` ### 将所有属性引入作用域 ```nix let config = { host = "localhost"; port = 8080; database = "myapp"; }; in with config; "${host}:${toString port}/${database}" # 返回 "localhost:8080/myapp" ``` #### 注意事项 ```nix let x = 1; attrs = { x = 2; y = 3; }; in with attrs; x + y # x = 1 (局部变量优先级更高), y = 3 ``` 条件表达式 --- ### 基本条件表达式 ```nix let x = 10; result = if x > 0 then "正数" else if x < 0 then "负数" else "零"; in result ``` #### 布尔条件判断 ```nix let isEnabled = true; config = if isEnabled then { port = 8080; debug = true; } else { port = 80; debug = false; }; in config ``` #### 字符串条件判断 ```nix let env = "production"; database = if env == "production" then "prod-db.example.com" else if env == "staging" then "staging-db.example.com" else "localhost"; in database ``` ### 复杂条件判断 ```nix let user = { name = "张三"; age = 25; isAdmin = true; }; message = if user.isAdmin && user.age >= 18 then "管理员用户: ${user.name}" else "普通用户: ${user.name}"; in message ``` ### 条件表达式中的属性集 ```nix let env = "production"; config = if env == "development" then { debug = true; logLevel = "debug"; database.host = "localhost"; } else { debug = false; logLevel = "info"; database.host = "prod-db.example.com"; }; in config ``` 属性集 --- ### 定义属性集 ```nix let person = { name = "李四"; age = 30; skills = [ "编程" "设计" "管理" ]; contact = { email = "lisi@example.com"; phone = "138-0000-0000"; }; }; in person ``` ### 动态属性名 ```nix let key = "dynamicKey"; attrs = { ${key} = "动态值"; "static-key" = "静态值"; }; in attrs # { dynamicKey = "动态值"; static-key = "静态值"; } ``` ### 更新属性集 ```nix let base = { x = 1; y = 2; }; updated = base // { y = 3; z = 4; }; # 合并属性集 in updated # { x = 1; y = 3; z = 4; } ``` #### 深度合并 ```nix let config1 = { server = { host = "localhost"; port = 8080; }; database = { name = "test"; }; }; config2 = { server = { port = 9000; ssl = true; }; cache = { enabled = true; }; }; # 注意:// 操作符只进行浅合并 merged = config1 // config2; # server 属性会被完全替换,而不是深度合并 in merged ``` ### 检查属性是否存在 ```nix let person = { name = "王五"; age = 28; }; in { hasName = person ? name; # true hasEmail = person ? email; # false hasNested = person ? contact.email; # false (嵌套检查) } ``` ### 访问属性 ```nix let config = { server = { host = "localhost"; port = 8080; }; }; in { host = config.server.host; # 访问嵌套属性 port = config.server.port; } ``` #### 可选属性访问 ```nix let config = { server = { host = "localhost"; }; }; in { port = config.server.port or 3000; # 如果不存在则使用默认值 timeout = config.timeout or 30; # 30 ssl = config.server.ssl or false; # false } ``` 连接与插值 --- ### 连接列表 ```nix let list1 = [ 1 2 3 ]; list2 = [ 4 5 6 ]; combined = list1 ++ list2; # [ 1 2 3 4 5 6 ] # 多个列表连接 all = [ 0 ] ++ list1 ++ list2 ++ [ 7 8 ]; in all # [ 0 1 2 3 4 5 6 7 8 ] ``` ### 连接路径与字符串 ```nix let base = /usr/bin; executable = base + /python3; # /usr/bin/python3 # 路径与字符串连接 config_path = /etc + "/nginx/nginx.conf"; # /etc/nginx/nginx.conf # 字符串连接 greeting = "你好" + ",世界!"; # "你好,世界!" in { inherit executable config_path greeting; } ``` ### 字符串插值 ```nix let name = "张三"; age = 25; score = 95.5; in { greeting = "你好,${name}!"; info = "姓名:${name},年龄:${toString age}"; result = "考试成绩:${toString score}分"; # 复杂表达式插值 status = "用户 ${name} ${if age >= 18 then "已成年" else "未成年"}"; # 路径插值 config_file = "${./configs}/${name}.conf"; } ``` 函数 --- ### 简单函数 ```nix let # 单参数函数 increment = x: x + 1; double = x: x * 2; # 使用函数 result1 = increment 5; # 6 result2 = double 3; # 6 in { inherit result1 result2; } ``` ### 命名参数 ```nix let # 基本命名参数 createUser = {name, age, email}: { inherit name age email; id = builtins.hashString "md5" email; }; user = createUser { name = "张三"; age = 25; email = "zhangsan@example.com"; }; in user ``` #### 忽略额外参数 ```nix let # 使用 ... 忽略额外的参数 processConfig = {host, port, ...}: { url = "${host}:${toString port}"; }; result = processConfig { host = "localhost"; port = 8080; ssl = true; # 会被忽略 timeout = 30; # 会被忽略 }; in result # { url = "localhost:8080"; } ``` #### 默认参数值 ```nix let # 为参数提供默认值 createServer = { host ? "localhost", port ? 8080, ssl ? false }: { inherit host port ssl; url = let proto = if ssl then "https" else "http"; in "${proto}://${host}:${toString port}"; }; # 使用所有默认值 server1 = createServer {}; # 只覆盖 port server2 = createServer {port = 3000;}; # 覆盖多个参数 server3 = createServer { host = "example.com"; port = 443; ssl = true; }; in { inherit server1 server2 server3; } ``` #### 绑定到变量 ```nix let # 将整个参数集绑定到变量,同时解构部分参数 logMessage = { level, message, timestamp ? null }@args: { formatted = "[${level}] ${message}"; raw = args; # 保留原始参数集 hasTimestamp = args ? timestamp && timestamp != null; }; log = logMessage { level = "INFO"; message = "服务器启动成功"; user = "admin"; # 额外参数也会保存在 args 中 }; in log ``` ### 多参数函数 ```nix let # 柯里化函数 add = x: y: x + y; multiply = x: y: z: x * y * z; # 部分应用 add10 = add 10; # 等价于 y: 10 + y # 使用示例 result1 = add 3 4; # 7 result2 = add10 5; # 15 result3 = multiply 2 3 4; # 24 in { inherit result1 result2 result3; } ``` ### 高阶函数 ```nix let # 接受函数作为参数的高阶函数 applyTwice = f: x: f (f x); # 返回函数的高阶函数 createMultiplier = factor: x: x * factor; # 函数组合 compose = f: g: x: f (g x); # 使用示例 double = x: x * 2; increment = x: x + 1; result1 = applyTwice double 3; # 12 triple = createMultiplier 3; result2 = triple 5; # 15 doubleAndIncrement = compose increment double; result3 = doubleAndIncrement 4; # 9 in { inherit result1 result2 result3; } ``` ### 递归函数 ```nix let # 计算阶乘 factorial = n: if n <= 1 then 1 else n * factorial (n - 1); # 斐波那契数列 fibonacci = n: if n <= 1 then n else fibonacci (n - 1) + fibonacci (n - 2); # 列表长度计算 listLength = list: if list == [] then 0 else 1 + listLength (builtins.tail list); # 使用示例 fact5 = factorial 5; # 120 fib7 = fibonacci 7; # 13 len = listLength [1 2 3 4]; # 4 in { inherit fact5 fib7 len; } ``` ### 条件函数 ```nix let ```nix let # 根据条件选择不同的处理函数 processData = condition: data: let uppercaseProcessor = str: builtins.replaceStrings ["a" "e" "i" "o" "u"] ["A" "E" "I" "O" "U"] str; lengthProcessor = str: toString (builtins.stringLength str); reverseProcessor = str: let len = builtins.stringLength str; chars = builtins.genList (i: builtins.substring (len - 1 - i) 1 str) len; in builtins.concatStringsSep "" chars; in if condition == "uppercase" then uppercaseProcessor data else if condition == "length" then lengthProcessor data else if condition == "reverse" then reverseProcessor data else data; # 使用示例 text = "hello world"; result1 = processData "uppercase" text; result2 = processData "length" text; result3 = processData "reverse" text; in { inherit result1 result2 result3; } ``` ### 函数工厂 ```nix let # 创建验证器函数的工厂 createValidator = rules: value: let checkRule = rule: if rule.type == "minLength" then builtins.stringLength value >= rule.value else if rule.type == "maxLength" then builtins.stringLength value <= rule.value else if rule.type == "contains" then builtins.match ".*${rule.value}.*" value != null else true; results = map checkRule rules; allValid = builtins.all (x: x) results; in { valid = allValid; value = value; errors = builtins.filter (rule: !checkRule rule) rules; }; # 创建特定的验证器 emailValidator = createValidator [ { type = "minLength"; value = 5; } { type = "contains"; value = "@"; } { type = "contains"; value = "."; } ]; passwordValidator = createValidator [ { type = "minLength"; value = 8; } { type = "maxLength"; value = 32; } ]; # 使用示例 email_result = emailValidator "user@example.com"; password_result = passwordValidator "mypassword123"; in { inherit email_result password_result; } ``` ### 函数式编程工具 ```nix let # 映射函数 mapList = f: list: if list == [] then [] else let head = f (builtins.head list); tail = mapList f (builtins.tail list); in [ head ] ++ tail; # 过滤函数 filterList = predicate: list: if list == [] then [] else let head = builtins.head list; tail = builtins.tail list; filtered_tail = filterList predicate tail; in if predicate head then [ head ] ++ filtered_tail else filtered_tail; # 归约函数 reduceList = f: initial: list: if list == [] then initial else let head = builtins.head list; tail = builtins.tail list; in reduceList f (f initial head) tail; # 使用示例 numbers = [ 1 2 3 4 5 ]; doubled = mapList (x: x * 2) numbers; evens = filterList (x: x mod 2 == 0) numbers; sum = reduceList (acc: x: acc + x) 0 numbers; product = reduceList (acc: x: acc * x) 1 numbers; in { inherit doubled evens sum product; } ``` 内置函数 --- ### 类型检查函数 ```nix let value = "hello"; in { isString = builtins.isString value; # true isInt = builtins.isInt value; # false isBool = builtins.isBool true; # true isList = builtins.isList [1 2 3]; # true isAttrs = builtins.isAttrs {x = 1;}; # true isFunction = builtins.isFunction (x: x); # true } ``` ### 字符串操作函数 ```nix let text = "Hello, Nix World!"; in { length = builtins.stringLength text; # 18 substring = builtins.substring 7 3 text; # "Nix" split = builtins.split " " text; # 分割字符串 replace = builtins.replaceStrings ["Nix"] ["世界"] text; # "Hello, 世界 World!" # 大小写转换需要自定义实现 toLower = builtins.replaceStrings ["A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"] ["a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"] "HELLO"; } ``` ### 列表操作函数 ```nix let numbers = [1 2 3 4 5]; strings = ["apple" "banana" "cherry"]; in { length = builtins.length numbers; # 5 head = builtins.head numbers; # 1 tail = builtins.tail numbers; # [2 3 4 5] # 映射函数 doubled = map (x: x * 2) numbers; # [2 4 6 8 10] # 过滤函数 evens = builtins.filter (x: x mod 2 == 0) numbers; # [2 4] # 折叠函数 sum = builtins.foldl' (acc: x: acc + x) 0 numbers; # 15 # 元素查找 hasThree = builtins.elem 3 numbers; # true # 排序 sorted = builtins.sort (a: b: a < b) [3 1 4 1 5 9]; # [1 1 3 4 5 9] } ``` ### 属性集操作函数 ```nix let attrs = { a = 1; b = 2; c = 3; }; in { keys = builtins.attrNames attrs; # ["a" "b" "c"] values = builtins.attrValues attrs; # [1 2 3] hasAttr = builtins.hasAttr "b" attrs; # true # 映射属性值 doubled = builtins.mapAttrs (name: value: value * 2) attrs; # { a = 2; b = 4; c = 6; } # 过滤属性 filtered = builtins.filterAttrs (name: value: value > 1) attrs; # { b = 2; c = 3; } # 移除属性 removed = builtins.removeAttrs attrs ["b"]; # { a = 1; c = 3; } } ``` 导入与模块 --- ### 导入文件 ```nix let # 导入其他 Nix 文件 utils = import ./utils.nix; config = import ./config.nix; # 带参数导入 lib = import ; # 导入并传递参数 myModule = import ./module.nix { pkgs = import {}; config = { enableFeature = true; }; }; in { inherit utils config lib myModule; } ``` ### 模块定义 ```nix # module.nix 示例 { pkgs, config, ... }: { # 模块选项 options = { services.myapp = { enable = lib.mkOption { type = lib.types.bool; default = false; description = "启用 MyApp 服务"; }; port = lib.mkOption { type = lib.types.int; default = 8080; description = "MyApp 监听端口"; }; }; }; # 模块配置 config = lib.mkIf config.services.myapp.enable { systemd.services.myapp = { description = "MyApp 服务"; after = ["network.target"]; serviceConfig = { ExecStart = "${pkgs.myapp}/bin/myapp --port ${toString config.services.myapp.port}"; Restart = "always"; }; }; }; } ``` 包管理 --- ### 基本包定义 ```nix # default.nix 或 shell.nix { pkgs ? import {} }: pkgs.stdenv.mkDerivation { pname = "my-app"; version = "1.0.0"; src = ./.; # 当前目录作为源码 buildInputs = with pkgs; [ nodejs yarn ]; buildPhase = '' yarn install yarn build ''; installPhase = '' mkdir -p $out/bin cp -r dist/* $out/ makeWrapper ${pkgs.nodejs}/bin/node $out/bin/my-app \ --add-flags "$out/index.js" ''; meta = with pkgs.lib; { description = "我的应用程序"; homepage = "https://example.com"; license = licenses.mit; maintainers = with maintainers; [ "your-name" ]; }; } ``` ### 开发环境 ```nix # shell.nix { pkgs ? import {} }: pkgs.mkShell { buildInputs = with pkgs; [ # 开发工具 git nodejs yarn python3 # 系统库 pkg-config openssl # 数据库 postgresql redis ]; # 环境变量 shellHook = '' echo "欢迎进入开发环境!" export DATABASE_URL="postgresql://localhost/myapp" export REDIS_URL="redis://localhost:6379" # 自动启动服务 if ! pgrep -f "postgres" > /dev/null; then echo "启动 PostgreSQL..." postgres -D $HOME/postgres-data & fi ''; } ``` 常用工具函数 --- ### 递归函数 ```nix let # 计算阶乘 factorial = n: if n <= 1 then 1 else n * factorial (n - 1); # 列表求和 sumList = list: if list == [] then 0 else builtins.head list + sumList (builtins.tail list); # 深度合并属性集 deepMerge = a: b: let mergeAttr = name: let aVal = a.${name}; bVal = b.${name}; in if builtins.isAttrs aVal && builtins.isAttrs bVal then deepMerge aVal bVal else bVal; in a // b // builtins.listToAttrs ( map (name: { inherit name; value = mergeAttr name; }) (builtins.filter (name: builtins.hasAttr name a) (builtins.attrNames b)) ); in { fact5 = factorial 5; # 120 listSum = sumList [1 2 3 4 5]; # 15 merged = deepMerge { a = { x = 1; y = 2; }; c = 3; } { a = { y = 9; z = 4; }; d = 5; }; } ``` 错误处理 --- ### 断言 ```nix let version = "1.2.3"; # 基本断言 validVersion = assert builtins.stringLength version > 0; version; # 带消息的断言(通过 throw 实现) checkPort = port: if port < 1 || port > 65535 then throw "端口号必须在 1-65535 之间,当前值: ${toString port}" else port; # 条件检查 config = { port = checkPort 8080; host = if builtins.getEnv "HOST" != "" then builtins.getEnv "HOST" else "localhost"; }; in config ``` ### 异常处理 ```nix let # 安全的属性访问 safeGet = attrs: path: default: let keys = builtins.split "\\." path; getValue = obj: keyList: if keyList == [] then obj else if !builtins.isAttrs obj then default else if !builtins.hasAttr (builtins.head keyList) obj then default else getValue (obj.${builtins.head keyList}) (builtins.tail keyList); in getValue attrs keys; config = { database = { host = "localhost"; port = 5432; }; }; # 安全访问嵌套属性 dbHost = safeGet config "database.host" "default-host"; # "localhost" dbUser = safeGet config "database.user" "default-user"; # "default-user" in { inherit dbHost dbUser; } ``` 来源 --- - [Nix 手册](https://nixos.org/manual/nix/stable/) - 官方用户手册 - [NixOS 手册](https://nixos.org/manual/nixos/stable/) - NixOS 系统配置指南 - [Nixpkgs 手册](https://nixos.org/manual/nixpkgs/stable/) - 包管理指南 - [NixOS/nixpkgs](https://github.com/NixOS/nixpkgs) - 官方包仓库 - [NixOS/nix](https://github.com/NixOS/nix) - Nix 包管理器源码 - [Nix Pills](https://nixos.org/guides/nix-pills/) - 深入学习 Nix 的教程 - [nix-shell](https://nixos.org/manual/nix/stable/command-ref/nix-shell.html) - 创建开发环境 - [nix-build](https://nixos.org/manual/nix/stable/command-ref/nix-build.html) - 构建包 - [nix-env](https://nixos.org/manual/nix/stable/command-ref/nix-env.html) - 用户环境管理 - [nixos-rebuild](https://nixos.org/manual/nixos/stable/administration/administration.html) - 系统重构建 - [NixOS/marketing](https://github.com/nixos/marketing) _(github.com)_ - [Nix 语言官方文档](https://nixos.org/manual/nix/stable/expressions/language-values.html) _(nixos.org)_