2

Jsonnet 的文档提到该+运算符可用于继承,或者按照教程中的措辞,用于组合对象

{
  a: 1,
  b: 2,
}
+
{
  a: 3
}

但是,我注意到 - 至少在像上面这样的简单情况下 - 简单地省略+运算符并编写由空格分隔的两个连续对象编译成相同的结果。也就是说,上面的程序和这个程序之间的输出没有区别:

{
  a: 1,
  b: 2,
}
{
  a: 3
}

我很困惑,因为我没有注意到文档中提到了这种隐式对象组合。我还注意到这种行为似乎是对象所独有的,并且不会发生在其他类型中。(特别是,尽管 Jsonnet 的一些特性从 Python 中汲取灵感,但您不能像在 Python 中那样将字符串与空格隐式连接。)

因此,一些问题:

  • 这甚至是预期的行为,还是错误?
  • 它在任何地方都有记录吗?
  • +将对象与显式运算符组合和将它们与空格隐式组合之间是否存在任何行为差异?
4

2 回答 2

1

一位同事推动我在教程的面向对象部分提到这一点:

让我们通过混合从一个模板中提取一些非常相似的鸡尾酒来使其更加具体,从而得出它们的相似之处。+运算符实际上隐含在这些示例中。在您编写的常见情况下foo + { ... },即 the+后面紧跟 a {,则+可以省略 the 。尝试在下面的 4 种情况下明确添加+

local templates = import 'templates.libsonnet';

{
  // The template requires us to override
  // the 'spirit'.
  'Whiskey Sour': templates.Sour {
    spirit: 'Whiskey',
  },

  // Specialize it further.
  'Deluxe Sour': self['Whiskey Sour'] {
    // Don't replace the whole sweetner,
    // just change 'kind' within it.
    sweetener+: { kind: 'Gomme Syrup' },
  },

  Daiquiri: templates.Sour {
    spirit: 'Banks 7 Rum',
    citrus+: { kind: 'Lime' },
    // Any field can be overridden.
    garnish: 'Lime wedge',
  },

  "Nor'Easter": templates.Sour {
    spirit: 'Whiskey',
    citrus: { kind: 'Lime', qty: 0.5 },
    sweetener+: { kind: 'Maple Syrup' },
    // +: Can also add to a list.
    ingredients+: [
      { kind: 'Ginger Beer', qty: 1 },
    ],
  },
}

所以,隐式对象组合:

  • 是合法的
  • 已记录,但似乎仅在教程和正式规范中,目前不在语言参考中
  • 具有与 相同的行为+,除了它仅在第二个操作数以 a 开头时可用{,而不是在它是变量时可用。
于 2020-09-08T11:29:07.170 回答
0

它在 Google GCL 和 Borgcfg 模板语言中也是如此。第一个子句的值是一个地图/模板对象。附加子句 { a: 3 } 只是对前面映射/模板对象中现有值的覆盖。我想这也是设计者对 jsonnet 的意图,因为它也来自 Google。

仅供参考,Borg/GCL 中的 + 运算符做得更糟,它在组合地图之前评估运算符两侧的所有内容,这使得它在大多数情况下实际上毫无用处。在 GCL/Borgcfg 中,您通常想要的是获取一个包含函数的模板,编辑一些,然后通过对影响函数的变量的新赋值来实例化它,这在 + 运算符之后是不可能的,因为它会焊接/绑定所有在合并映射之前立即将变量放入模板中 - 太早了 - 使其几乎没有用处 - 这是 GCL 的早期语言设计者所犯的错误。

于 2021-01-20T01:54:02.650 回答