"Nix 配置的精髓:如何在复杂的层级中找到正确的合并点。"
递归属性集:rec { ... }#
普通属性集不会把自身属性加入词法作用域。要按属性名相互引用,可以使用 rec,也可以先在 let 中定义共同绑定;外层有同名变量时普通属性集引用的是外层变量。
错误:
{
a = 1;
b = a + 1; # 报错:变量 a 找不到
}正确:
rec {
a = 1;
b = a + 1; # 结果为 b = 2
}属性合并的真相#
1. 使用 // (Merge)
这是 Nix 语言层面的合并。
let
defaults = { user = "guest"; shell = "/bin/sh"; };
overrides = { shell = "/bin/bash"; };
in defaults // overrides
# 结果:{ user = "guest"; shell = "/bin/bash"; }- 注意:
//是浅合并。如果两个 Set 里都有同名的嵌套 Set,后者会直接覆盖前者。
2. 使用 lib.mkMerge (NixOS 模块专用)
在 NixOS 配置文件中,我们很少直接用 //。NixOS 模块系统会自动帮你合并配置:
{
environment.systemPackages = [ pkgs.git ];
}
# 另一个模块中:
{
environment.systemPackages = [ pkgs.vim ];
}
# 结果:[ pkgs.git pkgs.vim ] (列表选项默认按模块规则合并;顺序可用 mkBefore/mkAfter 调整)点符号路径 (Dotted Path)#
为了减少 nesting,可以使用点符号直接定义深层属性。
长写法:
{
services = {
openssh = {
enable = true;
};
};
}简洁写法:
{
services.openssh.enable = true;
}实战案例:动态属性名#
通过 ${...} 可以动态生成属性名。
let
username = "alice";
in {
users.users."${username}" = {
isNormalUser = true;
};
}参考与延伸
根据技术笔记重新整理,示例使用通用名称。