nlohmann/json update() 详解:C++ 中 JSON 对象的覆盖更新与递归合并

发布时间:2026/9/8 21:05:07
nlohmann/json update() 详解:C++ 中 JSON 对象的覆盖更新与递归合并 nlohmann/json update() 详解C 中 JSON 对象的覆盖更新与递归合并【免费下载链接】jsonJSON for Modern C项目地址: https://gitcode.com/GitHub_Trending/js/jsonupdate()是 nlohmann::basic_json 提供的对象级合并接口对应 Pythondict.update的语义把一个 JSON 对象或迭代器区间中的所有键值对写入当前对象可选择性地对嵌套对象做递归合并。本文基于仓库 API 文档 update.md 及源码实现include/nlohmann/json.hpp、tests/src/unit-modifiers.cpp完整讲解两个重载的签名、merge_objects参数语义、异常行为、复杂度与迭代器失效规则并给出可运行的示例代码和典型配置合并场景。函数签名与核心语义update()有两个重载均定义于nlohmann::basic_jsonjson是它的别名// (1) void update(const_reference j, bool merge_objects false); // (2) void update(const_iterator first, const_iterator last, bool merge_objects false);重载 (1)把 JSON 对象j中的所有键值对插入当前对象重载 (2)把迭代器区间[first, last)中的所有键值对插入当前对象。两者的合并策略由merge_objects控制merge_objects false默认已存在的键直接被覆盖不做任何深度合并merge_objects true双方都存在、且源侧值为对象时对同名键递归合并其余情况照常覆盖。此外还有一个容易被忽视的规则如果当前 JSON 值是null调用update()前它会先被隐式转换为空对象然后才执行插入。这意味着json j; j.update(other);是合法的不需要先j json::object()。文档明确指出该函数设计动机是 Python 的dict.update()习惯 Python 字典合并的开发者可以直接迁移心智模型。merge_objects 参数深度解析merge_objects是update()最有价值的参数也是理解其实现的关键。参数方向说明jin要读取键值对来源的 JSON 对象merge_objectsintrue时双方都存在且源侧值为对象的键会被递归合并其他值一律按覆盖处理。默认falsefirstin待插入元素区间的起点lastin待插入元素区间的终点从源码看include/nlohmann/json.hpp单头文件版本见 single_include/nlohmann/json.hpp核心循环逻辑是for (auto it first; it ! last; it) { if (merge_objects it.value().is_object()) { auto it2 m_data.m_value.object-find(it.key()); // Only recurse when the existing value is itself an object. // Otherwise overwrite, matching the documented all other values // are overwritten as usual behavior (see #5402). if (it2 ! m_data.m_value.object-end() it2-second.is_object()) { it2-second.update(it.value(), true); #if JSON_DIAGNOSTICS it2-second.set_parents(); #endif continue; } } m_data.m_value.object-operator[](it.key()) it.value(); ... }可以确认几个精确的实现细节递归条件是三重的merge_objects为true、源侧值it.value()是对象、且当前对象中该键已存在并且现有值也是对象三者同时满足才递归调用update(..., true)只要有一项不满足就退化为覆盖例如现有值是数组而新值是对象直接整体替换不会报错实现中对「现有值非对象时覆盖」的行为带有明确注释引用了上游 issue #5402说明这是被刻意规范过的语义而非偶然行为开启JSON_DIAGNOSTICS宏后合并过程会同步维护父指针set_parents()用于异常诊断定位。参数校验与异常行为update()按如下顺序做校验同样见 include/nlohmann/json.hpp若当前值为null先隐式转为空对象若当前值不是对象例如 array、string抛出type_error.312消息形如cannot use update() with string重载 (2) 额外校验first与last必须属于同一个JSON 值否则抛出invalid_iterator.210消息为iterators do not fit迭代器指向的对象若不是 object抛出type_error.312。异常安全性为基本保证basic guarantee若操作中途抛出异常JSON 值可能已被部分修改——即合并不是原子的调用方不应假设失败后对象保持原样。单元测试 tests/src/unit-modifiers.cpp 的update()小节对这些分支逐一做了断言例如CHECK_THROWS_WITH_AS(j_array.update(j_object1), [json.exception.type_error.312] cannot use update() with array, json::type_error); CHECK_THROWS_WITH_AS(j_object1.update(j_object1.begin(), j_object2.end()), [json.exception.invalid_iterator.210] iterators do not fit, json::invalid_iterator);这印证了文档中异常表的每一条都有对应回归测试覆盖。复杂度两个重载的时间复杂度相同O(N·log(size() N))其中 N 为待插入元素个数。这与底层对象容器std::map的operator[]写入的对数查找/插入代价一致merge_objects true时递归合并会按子树深度叠加该代价。迭代器失效规则对ordered_json向对象添加值可能触发底层重新分配此时所有迭代器包括end()和所有元素引用全部失效。使用ordered_json调用update()时不要在合并过程中持有迭代器或引用对默认的std::map后端json向对象插入元素通常只失效end()迭代器但建议同样保守处理。示例一两个对象合并覆盖与递归合并的对比以下示例来自 docs/mkdocs/docs/examples/update.cpp#include iostream #include iomanip #include nlohmann/json.hpp using json nlohmann::json; using namespace nlohmann::literals; int main() { // create two JSON objects json o1 R( {color: red, price: 17.99, names: {de: Flugzeug}} )_json; json o2 R( {color: blue, speed: 100, names: {en: plane}} )_json; json o3 o1; // add all keys from o2 to o1 (updating color, replacing names) o1.update(o2); // add all keys from o2 to o1 (updating color, merging names) o3.update(o2, true); // output updated object o1 and o3 std::cout std::setw(2) o1 \n; std::cout std::setw(2) o3 \n; }输出见 docs/mkdocs/docs/examples/update.output{ color: blue, names: { en: plane }, price: 17.99, speed: 100 } { color: blue, names: { de: Flugzeug, en: plane }, price: 17.99, speed: 100 }两段输出的差异正好演示了两种模式o1.update(o2)中names被o2的names整体替换de丢失o3.update(o2, true)中names被递归合并同时保留de与en。示例二使用迭代器区间的重载重载 (2) 允许只合并部分键值对示例见 docs/mkdocs/docs/examples/update__range.cppjson o1 R( {color: red, price: 17.99, names: {de: Flugzeug}} )_json; json o2 R( {color: blue, speed: 100, names: {en: plane}} )_json; json o3 o1; // add all keys from o2 to o1 (updating color, replacing names) o1.update(o2.begin(), o2.end()); // add all keys from o2 to o1 (updating color, merging names) o3.update(o2.begin(), o2.end(), true);行为与示例一完全一致输出见 docs/mkdocs/docs/examples/update__range.output但区间形式让只取部分键成为可能例如o1.update(o2.begin(), std::next(o2.begin(), 2))可以只合并前两个键。注意区间必须来自同一个对象混用两个不同对象的首尾迭代器会触发invalid_iterator.210。实战场景默认配置与用户配置的合并文档给出了一个典型应用场景——用户设置覆盖默认设置。假设应用的可配置项默认值为{ color: red, active: true, name: {de: Maus, en: mouse} }用户只想选择性覆盖其中一部分{ color: blue, name: {es: ratón} }用update完成默认值与用户值的合并auto user_settings json::parse(config.json); auto effective_settings get_default_settings(); effective_settings.update(user_settings);结果中用户设置的键覆盖默认值其余键保留默认{ color: blue, active: true, name: {es: ratón} }注意这里name被整体替换了——用户只给了es默认的de/en丢失。如果需要保留并递归合并嵌套对象把第二个参数设为trueauto user_settings json::parse(config.json); auto effective_settings get_default_settings(); effective_settings.update(user_settings, true);{ color: blue, active: true, name: {de: Maus, en: mouse, es: ratón} }这个模式适用于任何层次化配置 选择性覆盖的场景应用配置、服务网格参数、国际化文案等配合merge_objects true可以在不牺牲默认值的完整性的前提下应用用户补丁。与相关 API 的区分insert向数组/对象插入指定键值或区间已存在的键不会被覆盖语义与update()互补merge_patch按 RFC 7386 语义应用 JSON Merge Patch其中null表示删除键与update()的覆盖语义不同更多对象修改手法参见 Modifying values 专题文档。版本历史update()自3.0.0引入merge_objects参数在3.10.5加入。因此使用递归合并能力时需要确认所用版本不低于 3.10.5。小结update()用两个重载、一个布尔参数覆盖了 JSON 对象合并的两大需求浅层覆盖merge_objects false与递归深合并merge_objects true。使用时需要记住三点null会被隐式转成空对象因此对空值调用是安全的非对象调用会抛type_error.312、混用迭代器会抛invalid_iterator.210失败时对象可能已被部分修改且ordered_json下合并会使全部迭代器失效。对于配置系统这类需要默认值打底、用户值覆盖、嵌套结构保留的场景update(other, true)是目前 nlohmann/json 中最直接的实现手段。【免费下载链接】jsonJSON for Modern C项目地址: https://gitcode.com/GitHub_Trending/js/json创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询