【问题标题】:how to do proper for-loops in jsonnet?如何在 jsonnet 中进行正确的 for 循环?
【发布时间】:2021-10-29 15:05:41
【问题描述】:

每次我觉得我终于理解了 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,隐藏字段之后是可见的还是完全丢失。

如果不触及隐藏的“属性”,我将/可以如何做到这一点? 我知道我的问题是,我在这里使用了对象理解并且(参考错误消息)那些“对象理解不能有隐藏字段”...... 但据我了解 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 
}

【问题讨论】:

    标签: jsonnet


    【解决方案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 特性并不总是能很好地与数据结构特性配合使用。

    通常你想把每个对象都看作:

    • 一个数据对象,保持所有字段可见,避免self/super。您可以轻松地对字段进行聚合处理。
    • OOP 对象或结构。您可以使用 selfsuper,隐藏字段等。您可以手动处理每个字段,因为每个字段可能具有完全不同的含义和行为。

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

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

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

    【讨论】:

    • 我认为@Heiko Finzel 的全部观点是«它起作用的原因是 : 是“默认可见性”,它采用它覆盖的字段的可见性。» doesn't 似乎是这里的情况,使用 go-jsonnet v0.17.0 运行您的示例确实 显示 隐藏字段,请注意,如果被覆盖,它的行为符合预期“非动态”结构。
    • «用 go-jsonnet v0.17.0 运行您的示例确实也显示了隐藏字段» 嗯...我似乎在工作(“可见”是可见的,“隐藏的”是隐藏的)当我运行它。您是否从我的答案中运行了确切的 sn-p?
    • 是的,逐字粘贴,gist.github.com/jjo/db3fb25330dde66e6c8e848e8fdc107e的会话“日志”
    • WTbF!,刚刚意识到 brew install jsonnet 实际上安装了 cpp-jsonnet, 显示了这个问题,安装 go-jaonnet 反而做了正确的事情(!)
    【解决方案2】:

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

    [...]
    
    local stack2 = applyModifications(stack);
       
    {
      modified: stack + stack2 
    }
    

    【讨论】:

    • 似乎没有解决我的问题。如果我使用 std.objectFieldsAll:stack + stack2 是一个 noop,stack2 + stack 将重置我的更改。如果我使用 std.objectFields:我确信它应该可以解决我的问题,但由于我不明白的原因没有解决。
    【解决方案3】:

    @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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-24
      • 1970-01-01
      • 2015-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-16
      相关资源
      最近更新 更多