Jsonnet对象推导式中局部变量无法访问的原因及正确用法
问题根因
这个报错是Jsonnet的语法解析规则和作用域规则共同导致的,核心原因有两个:
- 局部变量作用域特性:
local定义的是词法作用域的局部变量,不属于对象的挂载字段,因此无法通过self.前缀访问,只能在定义它的词法块内直接引用。 - 纯推导对象的语法解析歧义:当你返回的对象完全由推导规则生成(没有固定键的显式字段)时,如果对象内部的
local声明和后面的推导字段之间没有显式加逗号分隔,Jsonnet解释器会判定local声明所在的对象块已经结束,把后面的推导逻辑解析为独立的新对象字面量。这个新对象的作用域里自然不存在之前定义的neededVars变量,就会抛出未知变量错误。
你把推导逻辑放在variables字段下时能正常运行,是因为显式的固定键字段会让解释器正确识别前面的local属于当前对象的内部声明,作用域会覆盖对象内所有字段(包括字段里嵌套的推导逻辑),但这种写法会多一层variables包装,不符合你要的扁平结构需求。
另外你的代码里还有一处笔误:dict中的"var1: "value"缺少var1键名的闭合双引号,需要修正为"var1": "value",否则会触发语法错误。
正确实现方式
推荐两种符合你结构要求的写法,选任意一种即可:
写法1:将局部变量定义为函数级作用域(最稳妥,无解析歧义)
把neededVars的定义从对象内部移到函数内、对象字面量的外层,作为函数的局部变量,它的作用域会天然覆盖后面返回的推导对象,完全不会出现解析歧义:
getVariables(client, stage) :: // 函数级局部变量,作用域覆盖整个函数剩余部分 local neededVars = if stage == "build" then ["var1", "var2"] else if stage == "test" then ["var2"] else []; // 直接返回推导生成的扁平对象,符合输出结构要求 { [varName]: $.dict[client][varName] for varName in neededVars } dict:: { "customer1": { "var1": "value", "var2": "value2" } }
写法2:显式加逗号分隔对象内部的local和推导规则
如果你一定要把neededVars定义在对象内部,只需要在local声明的末尾加逗号,明确告诉解释器这个local是当前推导对象的内部成员,作用域就会正确覆盖后面的推导逻辑:
getVariables(client, stage) :: { local neededVars = if stage == "build" then ["var1", "var2"] else if stage == "test" then ["var2"] else [], // 必须加逗号,分隔local声明和后续推导规则 [varName]: $.dict[client][varName] for varName in neededVars } dict:: { "customer1": { "var1": "value", "var2": "value2" } }
内容的提问来源于stack exchange,提问作者Christian Müller
相关产品推荐
相关产品推荐

