В чем разница между оператором + и std.mergePatch в Jso nnet? - PullRequest
3 голосов
/ 06 мая 2020

Jso nnet s std.mergePatch реализует RFC7396 , но в моем наивном тестировании я не обнаружил разницы между его поведением и оператором + ; например, оператор + соблюдает синтаксис x+. std.mergePatch - это , реализованное в самом Jso nnet, что, кажется, подразумевает, что он отличается от оператора +, который, как я предполагаю, является встроенным.

Что такое отличается семантика этих двух способов слияния?

1 Ответ

6 голосов
/ 07 мая 2020

Jso nnet s + и std.mergePatch - это совершенно разные операции. Оператор + работает только на одном уровне, а std.mergePatch рекурсивно просматривает объект и объединяет вложенные объекты. Проще всего объяснить на примере:

local foo = { a: {b1: {c1: 42}}},
      bar = { a: {b2: {c2: 2}}};
foo + bar

Вывод:

{
   "a": {
      "b2": {
         "c2": 2
      }
   }
}

Обратите внимание, что bar.a полностью заменяет foo.a. С + все поля во втором объекте имеют приоритет над полями в первом объекте. Сравните это с результатом использования std.mergePatch(foo, bar).

{
   "a": {
      "b1": {
         "c1": 42
      },
      "b2": {
         "c2": 2
      }
   }
}

Поскольку оба foo и bar имеют поле a, объединяется, и окончательные результаты содержат как b1, так и b2.

Итак, повторюсь, + - это «плоская» операция, которая заменяет поля первого объекта полями второго объекта.

Но это не конец истории. Вы упомянули синтаксис field+: value, и я попытаюсь объяснить, что он на самом деле делает. В Jso nnet + это не просто перезапись, а наследование в объектно-ориентированном смысле. Он создает объект, который является результатом наследования второго объекта от первого. Это немного экзотично c, чтобы иметь для этого оператор - во всех основных языках такие отношения определены статически. В Jso nnet, когда вы выполняете foo + bar, объект bar имеет доступ к материалам от foo до super:

{ a: 2 } + { a_plus_1: super.a + 1}

Это приводит к:

{
   "a": 2,
   "a_plus_1": 3
}

Вы можете использовать эту функцию, чтобы объединить поля глубже:

{ a: {b: {c1: 1}, d: 1}} +
{ a: super.a + {b: {c2: 2} } }

Результат:

{
   "a": {
      "b": {
         "c2": 2
      },
      "d": 1
   }
}

Это немного повторяется (это будет раздражать, если имя поля было длиннее). Итак, у нас есть хороший синтаксический сахар для этого:

{ a: {b: {c1: 1} , d: 1}} +
{ a+: {b: {c2: 2}} }

Обратите внимание, что в этих примерах мы выполняли слияние только для одного выбранного поля. Мы все же заменили значение a.b. Это гораздо более гибко, потому что во многих случаях вы не можете просто наивно объединить все внутри (иногда вложенный объект - это «atomi c» и его следует полностью заменить).

Версия в +: работает так же, как и версия с super. Тонкая разница в том, что +: фактически переводится во что-то вроде if field in super then super.field + val else val, поэтому оно также возвращает то же значение, когда super не указан вообще или не имеет этого конкретного поля. Например, {a +: {b: 42}} отлично оценивается как {a: { b: 42 }}.

Обязательная проповедь: хотя + очень мощный, пожалуйста, не злоупотребляйте им. Если вам нужно что-то параметризовать, подумайте об использовании функций вместо наследования.

...