在 C++ 中优雅地处理 JSON:nlohmann/json 库实践指南

JSON (JavaScript Object Notation) 作为一种轻量级的数据交换格式,在现代软件开发中扮演着重要角色。在 C++ 开发中,nlohmann/json 库因其易用性和灵活性而广受欢迎。本文将通过实例介绍如何使用这个强大的库进行 JSON 数据的序列化和反序列化操作。

环境准备

首先,我们需要配置项目环境。这里使用 CMake 作为构建系统:

cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
project("nlohmann_json_test" CXX)
find_package(nlohmann_json CONFIG REQUIRED)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(nlohmann_json_test nlohmann_json_test.cpp)
target_link_libraries(nlohmann_json_test PRIVATE nlohmann_json::nlohmann_json)

数据结构定义

在示例中,我们定义了三个主要的数据结构:

struct Address {
std::string street;
std::string number;
std::string postcode;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(Address, street, number, postcode);
};
struct Person {
std::string name;
int age;
std::vector<Address> addresses;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(Person, name, age, addresses);
};
struct ApiResult {
bool success;
std::string message;
json data;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(ApiResult, success, message, data);
};

这里的关键是使用 NLOHMANN_DEFINE_TYPE_INTRUSIVE 宏,它自动为我们的结构体生成序列化和反序列化的代码。这大大简化了 JSON 转换过程,无需手动编写转换逻辑。

JSON 序列化示例

让我们看看如何将 C++ 对象序列化为 JSON:

Person person = {
"John Doe",
20,
{
{"Main St", "123", "12345"},
{"Second St", "456", "67890"}
}
};
// 序列化为 JSON
json j = person;
std::cout << j.dump(4) << std::endl;

序列化结果:

{
"addresses": [
{
"number": "123",
"postcode": "12345",
"street": "Main St"
},
{
"number": "456",
"postcode": "67890",
"street": "Second St"
}
],
"age": 20,
"name": "John Doe"
}

JSON 反序列化示例

同样简单,我们可以将 JSON 字符串反序列化为 C++ 对象:

json j2 = R"(
{
"name": "Jane Doe",
"age": 25,
"addresses":[
{
"street":"jiangxia",
"number":"258",
"postcode":"54321"
},
{
"street":"wuchang",
"number":"369",
"postcode":"12345"
}
]
}
)"_json;
Person person2;
j2.get_to(person2);

API 响应封装示例

在实际开发中,我们经常需要处理 API 响应。这里展示了如何使用 ApiResult 结构体封装不同类型的响应:

// 成功响应,携带数据
ApiResult ar1;
ar1.success = true;
ar1.message = "success";
ar1.data = person;
json jar1 = ar1;
// 错误响应
ApiResult ar2;
ar2.success = false;
ar2.message = "A fatal error has occurred";
ar2.data = nullptr;
json jar2 = ar2;

这将产生如下 JSON 输出:

成功响应:

{
"data": {
"addresses": [...],
"age": 20,
"name": "John Doe"
},
"message": "success",
"success": true
}

错误响应:

{
"data": null,
"message": "A fatal error has occurred",
"success": false
}

主要特点和优势

  1. 简单直观的 API:通过 NLOHMANN_DEFINE_TYPE_INTRUSIVE 宏,可以轻松实现序列化和反序列化。
  2. 类型安全:编译时类型检查,避免运行时错误。
  3. 灵活的数据处理:支持复杂的嵌套结构和各种数据类型。
  4. 现代 C++ 特性支持:与 C++11 及以上版本完全兼容。
  5. 错误处理:提供清晰的错误信息和异常处理机制。

注意事项

  1. 使用 NLOHMANN_DEFINE_TYPE_INTRUSIVE 时,需要确保所有成员变量都是可序列化的。
  2. 在处理大型 JSON 数据时,要注意内存使用。
  3. 对于非字符串类型的键,需要特别处理。
  4. C++20 提供了更简洁的结构体初始化语法,但要注意编译器支持情况。
posted @   非法关键字  阅读(894)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示