如何在 jsonnet 中做正确的 for 循环?
how to do proper for-loops in jsonnet?
每次我以为我终于理解了jsonnet,它就来打我的脸...-.-
我有如下内容:
local applyModifications(kp) = {
[topLvlKey]: {
[subKey]: myfunction(kp[topLvlKey][subKey])
for subKey in std.objectFieldsAll(kp[topLvlKey])
},
for topLvlKey in std.objectFieldsAll(kp)
};
我想遍历对象前 2 层内的所有内容并在那里应用一些函数...
基本上可行...但是取决于我使用 std.objectFieldsAll
还是 std.objectFields
,隐藏字段之后是可见的还是完全丢失。
我如何would/could在不触及隐藏的“属性”的情况下做到这一点?
我知道我的问题是,我在这里使用对象理解并且(指错误消息)那些“对象理解不能有隐藏字段”......
但据我了解 jsonnet,something-comprehensions 是创建 for 循环的唯一方法,对吧?
测试代码:
// vim: set ts=2 sw=2 expandtab :
local myfunction(o) = o {
spec+: {
foo: 'bar'
}
};
local applyModifications(kp) = {
[topLvlKey]: {
[subKey]: myfunction(kp[topLvlKey][subKey])
for subKey in std.objectFieldsAll(kp[topLvlKey])
},
for topLvlKey in std.objectFieldsAll(kp)
};
local stack = {
fooService: {
fooResource: {
kind: 'PrometheusRule',
spec: {
groups: [
{ name: 'fooGroup', rules: [{ alert: 'fooAlert', expr: 'fooExpr' }] },
{ name: 'barGroup', rules: [{ alert: 'fooAlert', expr: 'fooExpr' }] },
],
},
},
},
fooService2:: {
fooResource: {
kind: 'PrometheusRule',
spec: {
groups: [
{ name: 'fooGroup', rules: [{ alert: 'fooAlert', expr: 'fooExpr' }] },
{ name: 'barGroup', rules: [{ alert: 'fooAlert', expr: 'fooExpr' }] },
],
},
},
},
};
local stack2 = applyModifications(stack);
{
modified: stack2
}
你可以通过继承来实现你想要的。
local applyModifications(obj, f) =
obj + {
[x] : f(obj[x]) for x in std.objectFieldsAll(obj)
}
;
applyModifications({
visible: "foo",
hidden:: "bar",
}, function(x) x + " modified")
为清楚起见,这是单关卡,但创建两关卡版本应该很简单(如果您有任何问题,请告诉我)。
它起作用的原因是 :
是“默认可见性”,它采用它覆盖的字段的可见性。 (你也有带 ::
的强制可见字段)。
也就是说,您处于尴尬的境地,通常可以避免。 Jsonnet 中的对象替换了其他语言的对象(struct / class 实例)和映射(dict)。尽管这两个概念是统一的,但 OOP 特性并不总是能与数据结构特性很好地配合。
通常您希望将每个对象视为:
- 一个数据对象,保持所有字段可见,避免self/super。您可以轻松地汇总处理这些字段。
- OOP 对象或结构。您可以使用
self
和 super
,隐藏字段等。您手动处理每个字段,因为每个字段都可以具有完全不同的含义和行为。
希望数据对象包含 OOP 对象,反之亦然。当一个物体处于中间地带时,尴尬就会随之而来。
But as far as I understand jsonnet, something-comprehensions are the only way to create for-loops, right?
感悟并不特殊。不要将它们视为命令式语言中的“for 循环”。数组理解基本上是 std.map 和 std.filter(具有任意嵌套)的语法糖。
按照上面的@sbarzowski 评论(我宁愿说的完整课程),顺便说一句,确保你使用的是 go-jsonnet
fwiw(brew install go-jsonnet
在 macOS 上),你可以欺骗可见性通过将最后一行代码修改为“合并”:
[...]
local stack2 = applyModifications(stack);
{
modified: stack + stack2
}
@sbarzowski:
我花了一些时间来理解差异并采用我的示例的解决方案(2 个循环),但这是我得到的并且似乎有效:
local applyModifications(kp) = kp + {
[topLvlKey]: kp[topLvlKey] + {
[subKey]: myfunction(kp[topLvlKey][subKey])
for subKey in std.objectFieldsAll(kp[topLvlKey])
},
for topLvlKey in std.objectFieldsAll(kp)
};
PS: 我正在使用 go jsonnet v0.17.0
每次我以为我终于理解了jsonnet,它就来打我的脸...-.-
我有如下内容:
local applyModifications(kp) = {
[topLvlKey]: {
[subKey]: myfunction(kp[topLvlKey][subKey])
for subKey in std.objectFieldsAll(kp[topLvlKey])
},
for topLvlKey in std.objectFieldsAll(kp)
};
我想遍历对象前 2 层内的所有内容并在那里应用一些函数...
基本上可行...但是取决于我使用 std.objectFieldsAll
还是 std.objectFields
,隐藏字段之后是可见的还是完全丢失。
我如何would/could在不触及隐藏的“属性”的情况下做到这一点? 我知道我的问题是,我在这里使用对象理解并且(指错误消息)那些“对象理解不能有隐藏字段”...... 但据我了解 jsonnet,something-comprehensions 是创建 for 循环的唯一方法,对吧?
测试代码:
// vim: set ts=2 sw=2 expandtab :
local myfunction(o) = o {
spec+: {
foo: 'bar'
}
};
local applyModifications(kp) = {
[topLvlKey]: {
[subKey]: myfunction(kp[topLvlKey][subKey])
for subKey in std.objectFieldsAll(kp[topLvlKey])
},
for topLvlKey in std.objectFieldsAll(kp)
};
local stack = {
fooService: {
fooResource: {
kind: 'PrometheusRule',
spec: {
groups: [
{ name: 'fooGroup', rules: [{ alert: 'fooAlert', expr: 'fooExpr' }] },
{ name: 'barGroup', rules: [{ alert: 'fooAlert', expr: 'fooExpr' }] },
],
},
},
},
fooService2:: {
fooResource: {
kind: 'PrometheusRule',
spec: {
groups: [
{ name: 'fooGroup', rules: [{ alert: 'fooAlert', expr: 'fooExpr' }] },
{ name: 'barGroup', rules: [{ alert: 'fooAlert', expr: 'fooExpr' }] },
],
},
},
},
};
local stack2 = applyModifications(stack);
{
modified: stack2
}
你可以通过继承来实现你想要的。
local applyModifications(obj, f) =
obj + {
[x] : f(obj[x]) for x in std.objectFieldsAll(obj)
}
;
applyModifications({
visible: "foo",
hidden:: "bar",
}, function(x) x + " modified")
为清楚起见,这是单关卡,但创建两关卡版本应该很简单(如果您有任何问题,请告诉我)。
它起作用的原因是 :
是“默认可见性”,它采用它覆盖的字段的可见性。 (你也有带 ::
的强制可见字段)。
也就是说,您处于尴尬的境地,通常可以避免。 Jsonnet 中的对象替换了其他语言的对象(struct / class 实例)和映射(dict)。尽管这两个概念是统一的,但 OOP 特性并不总是能与数据结构特性很好地配合。
通常您希望将每个对象视为:
- 一个数据对象,保持所有字段可见,避免self/super。您可以轻松地汇总处理这些字段。
- OOP 对象或结构。您可以使用
self
和super
,隐藏字段等。您手动处理每个字段,因为每个字段都可以具有完全不同的含义和行为。
希望数据对象包含 OOP 对象,反之亦然。当一个物体处于中间地带时,尴尬就会随之而来。
But as far as I understand jsonnet, something-comprehensions are the only way to create for-loops, right?
感悟并不特殊。不要将它们视为命令式语言中的“for 循环”。数组理解基本上是 std.map 和 std.filter(具有任意嵌套)的语法糖。
按照上面的@sbarzowski 评论(我宁愿说的完整课程),顺便说一句,确保你使用的是 go-jsonnet
fwiw(brew install go-jsonnet
在 macOS 上),你可以欺骗可见性通过将最后一行代码修改为“合并”:
[...]
local stack2 = applyModifications(stack);
{
modified: stack + stack2
}
@sbarzowski:
我花了一些时间来理解差异并采用我的示例的解决方案(2 个循环),但这是我得到的并且似乎有效:
local applyModifications(kp) = kp + {
[topLvlKey]: kp[topLvlKey] + {
[subKey]: myfunction(kp[topLvlKey][subKey])
for subKey in std.objectFieldsAll(kp[topLvlKey])
},
for topLvlKey in std.objectFieldsAll(kp)
};
PS: 我正在使用 go jsonnet v0.17.0