You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nix语言字段递归使用疑问:为何部分场景可行部分不可行?

问题:Nix属性集内变量引用的误区

我在阅读Nix语言教程时看到如下极简包示例:

{ lib, stdenv, fetchurl }:
stdenv.mkDerivation rec {
  pname = "hello";
  version = "2.12";
  src = fetchurl {
    url = "mirror://gnu/${pname}/${pname}-${version}.tar.gz";
    sha256 = "1ayhp9v4m4rdhjmnl2bq3cibrbqqkgjbl3s7yk2nhlh8vj3ay16g";
  };
  meta = with lib; {
    license = licenses.gpl3Plus;
  };
}

注意其中fetchurl引用了同一属性集内定义的pname和version,但我自行测试如下代码时:

$ nix-instantiate --eval --strict --expr 'let f = {x}: x+x ; in { a=1; b=2; c=f {x=a;}; }'
error: undefined variable 'a'
       at «string»:1:42:
            1| let f = {x}: x+x ; in { a=1; b=2; c=f {x=a;}; }
             |                                          ^

出现了未定义变量的错误,想请教我存在哪些理解误区?


核心原因:rec关键字的作用

  • 示例代码里用了rec { ... }语法,这个关键字的作用是让属性集内的属性可以互相引用——在rec包裹的属性集中,每个属性定义时都能访问同一属性集里的其他属性(包括在它之前定义的)。
  • 你自己的代码里,{ a=1; b=2; c=f {x=a;}; }是普通属性集,没有rec修饰。普通属性集里的属性定义是上下文独立的,c的定义里的a会被当作外部变量查找,而不是当前属性集里的a,所以会报错“未定义变量”。

修正后的代码示例

如果要让你的代码能引用同一属性集内的a,只需要给外层属性集加上rec:

$ nix-instantiate --eval --strict --expr 'let f = {x}: x+x ; in rec { a=1; b=2; c=f {x=a;}; }'

执行后会返回正确结果:{ a = 1; b = 2; c = 2; }

额外说明

  • rec是Nix里专门用于创建递归属性集的语法,常见于mkDerivation的参数中,因为包定义里经常需要用pname、version拼接下载链接、输出路径等。
  • 注意不要滥用rec,如果属性之间出现循环引用(比如a = b; b = a;),会导致求值无限递归,触发错误。

内容的提问来源于Stack Exchange,提问作者Jan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 02:42:36