将对象与 +(加号运算符)与空白组合

Combining objects with + (plus operator) vs whitespace

Jsonnet 的文档提到 + 运算符可用于 inheritance, or, as it's worded in the tutorial, to combine objects:

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

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

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

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

因此,一些问题:

一位同事建议我在教程的 Object Orientation 部分中提及这一点:

Let's make it more concrete by mixing deriving some cocktails that are quite similar from a template that draws out their similarities. The + operator is actually implicit in these examples. In the common case where you write foo + { ... }, i.e. the + is immediately followed by a {, then the + can be elided. Try explicitly adding the + in the 4 cases, below.

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 },
    ],
  },
}

因此,隐式对象组合:

  • 合法
  • 已记录,但似乎仅在教程和 formal spec 中,目前不在语言参考中
  • 的行为与 + 相同,只是它仅在第二个操作数以 { 开头时可用,而不是在它是变量时可用。

它在 Google GCL 和 Borgcfg 模板语言中也是这样工作的。第一个子句的值是一个 map/template 对象。附加子句 { a: 3 } 只是对前面 map/template 对象中现有值的覆盖。我想这也是设计师为 jsonnet 设计的,因为它也来自 Google.

仅供参考,Borg/GCL 中的 + 运算符做了更糟糕的事情,它在合并映射之前评估运算符两侧的所有内容,这使得它在大多数情况下几乎无用。在 GCL/Borgcfg 中,您通常想要的是获取一个内部包含函数的模板,编辑一些模板,然后通过对影响函数的变量进行新赋值来实例化它,这在 + 运算符之后是不可能的,因为 welds/binds 在合并映射之前立即将所有变量添加到模板中 -- 太早了 -- 使它的用处很小 -- 这是 GCL 早期语言设计者犯的错误。