1

每次我以为我终于理解了 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.objectFieldsAllor std.objectFields,隐藏字段在之后可见或完全丢失。

在不触及隐藏的“财产”的情况下,我将/如何做到这一点?我理解我的问题是,我在这里使用了对象理解并且(参考错误消息)那些“对象理解不能有隐藏字段”......但据我了解 jsonnet,一些东西理解是唯一的创建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 
}
4

3 回答 3

1

你可以通过继承实现你想要的。

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 中的对象替换了其他语言的对象(结构/类实例)和映射(字典)。尽管这两个概念是统一的,但 OOP 特性并不总是能很好地与数据结构特性配合使用。

通常您想将每个对象视为:

  • 一个数据对象,保持所有字段可见并避免自我/超级。您可以轻松地汇总处理这些字段。
  • OOP 对象或结构。您可以使用selfand super,隐藏字段等。您可以手动处理每个字段,因为每个字段可能具有完全不同的含义和行为。

预计数据对象包含 OOP 对象,反之亦然。当一个物体处于某个中间地带时,就会出现尴尬。

但据我了解jsonnet,一些理解是创建for循环的唯一方法,对吧?

理解并不特别。不要将它们视为命令式语言中的“for 循环”。数组推导基本上是 std.map 和 std.filter 的语法糖(具有任意嵌套)。

于 2021-10-29T19:42:05.640 回答
0

按照上面的@sbarzowski 评论(我宁愿说完整的课程),顺便说一句,确保您使用的是go-jsonnetfwiw (brew install go-jsonnet在 macos 上),您可以通过将最后一行代码修改为来欺骗可见性“合并”:

[...]

local stack2 = applyModifications(stack);
   
{
  modified: stack + stack2 
}
于 2021-10-31T13:09:31.897 回答
0

@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

于 2021-11-03T13:30:09.527 回答