Nix 快速参考备忘单,旨在帮助编写基础的 Nix 代码。Nix 是一个纯函数式包管理器和 NixOS 系统的基础语言。
let
x = "单行字符串";
y = ''
多行字符串
支持换行和缩进
'';
z = ''
前导空格会被自动处理
这行会保持缩进
'';
in
let
name = "世界";
greeting = "你好,${name}!";
in
let
escaped = ''
引号:\"hello\",换行:\n,制表符:\t
'';
in
let
x = -123;
y = 123;
# 支持不同进制
hex = 0xFF; # 十六进制: 255
bin = 0b1010; # 二进制: 10
oct = 0o755; # 八进制: 493
in
let
x = -0.32;
y = 0.45;
scientific = 1.23e-4; # 科学记数法
inf = 1.0 / 0.0; # 无穷大
in
let
x = true;
y = false;
# 布尔运算
and_result = true && false; # false
or_result = true || false; # true
not_result = !true; # false
in
let
x = null;
# null 表示缺失值
# 类似于其他语言的 None 或 undefined
in
let
absolute = /usr/bin/env; # 绝对路径
relative = ./config.nix; # 相对路径
home = ~/Documents; # 家目录路径
# 路径会在构建时自动复制到 Nix store
in
let
x = {
name = "张三";
age = 25;
address = {
city = "北京";
district = "朝阳区";
};
};
y = { c = 3; };
# 递归属性集
rec_set = rec {
x = 1;
y = x + 1; # 可以引用同级属性
};
in
参见 属性集操作
let
numbers = [ 1 2 3 4 5 ];
mixed = [
1
"这是字符串"
23.0
null
{ name = "属性集"; }
];
# 列表可以包含任意类型的元素
nested = [ [ 1 2 ] [ 3 4 ] ];
in
# 这是单行注释
let x = 1; in x # 行末注释
/*
这是多行注释
可以跨越多行
/* 可以嵌套 */
*/
let
x = 1;
y = 2;
z = x + y; # 可以引用前面定义的变量
in
x + y + z # 返回 6
let
outer = 10;
in
let
inner = 5;
in
outer + inner # 返回 15
let
x = 1;
y = 2;
in
{ inherit x y; } # 继承多个变量
let
x = 1;
y = 2;
in
{ x = x; y = y; }
let
config = {
host = "localhost";
port = 8080;
ssl = true;
};
in
{
inherit (config) host port;
# 只继承特定属性
}
let
config = {
host = "localhost";
port = 8080;
ssl = true;
};
in
{
host = config.host;
port = config.port;
}
let
config = {
host = "localhost";
port = 8080;
database = "myapp";
};
in
with config;
"${host}:${toString port}/${database}" # 返回 "localhost:8080/myapp"
let
x = 1;
attrs = { x = 2; y = 3; };
in
with attrs;
x + y # x = 1 (局部变量优先级更高), y = 3
let
x = 10;
result = if x > 0
then "正数"
else if x < 0
then "负数"
else "零";
in
result
let
isEnabled = true;
config = if isEnabled
then { port = 8080; debug = true; }
else { port = 80; debug = false; };
in
config
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
let
user = { name = "张三"; age = 25; isAdmin = true; };
message = if user.isAdmin && user.age >= 18
then "管理员用户: ${user.name}"
else "普通用户: ${user.name}";
in
message
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
let
person = {
name = "李四";
age = 30;
skills = [ "编程" "设计" "管理" ];
contact = {
email = "lisi@example.com";
phone = "138-0000-0000";
};
};
in
person
let
key = "dynamicKey";
attrs = {
${key} = "动态值";
"static-key" = "静态值";
};
in
attrs # { dynamicKey = "动态值"; static-key = "静态值"; }
let
base = { x = 1; y = 2; };
updated = base // { y = 3; z = 4; }; # 合并属性集
in
updated # { x = 1; y = 3; z = 4; }
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
let
person = { name = "王五"; age = 28; };
in
{
hasName = person ? name; # true
hasEmail = person ? email; # false
hasNested = person ? contact.email; # false (嵌套检查)
}
let
config = {
server = {
host = "localhost";
port = 8080;
};
};
in
{
host = config.server.host; # 访问嵌套属性
port = config.server.port;
}
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
}
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 ]
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; }
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";
}
let
# 单参数函数
increment = x: x + 1;
double = x: x * 2;
# 使用函数
result1 = increment 5; # 6
result2 = double 3; # 6
in
{ inherit result1 result2; }
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
let
# 使用 ... 忽略额外的参数
processConfig = {host, port, ...}: {
url = "${host}:${toString port}";
};
result = processConfig {
host = "localhost";
port = 8080;
ssl = true; # 会被忽略
timeout = 30; # 会被忽略
};
in
result # { url = "localhost:8080"; }
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; }
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
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; }
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; }
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; }
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; }
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; }
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; }
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
}
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";
}
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]
}
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; }
}
let
# 导入其他 Nix 文件
utils = import ./utils.nix;
config = import ./config.nix;
# 带参数导入
lib = import <nixpkgs/lib>;
# 导入并传递参数
myModule = import ./module.nix {
pkgs = import <nixpkgs> {};
config = { enableFeature = true; };
};
in
{
inherit utils config lib myModule;
}
# 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";
};
};
};
}
# default.nix 或 shell.nix
{ pkgs ? import <nixpkgs> {} }:
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" ];
};
}
# shell.nix
{ pkgs ? import <nixpkgs> {} }:
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
'';
}
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; };
}
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
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; }