Folly DynamicConverter 完全指南:dynamic 与强类型 C++ 对象的双向转换
Folly DynamicConverter 完全指南dynamic 与强类型 C 对象的双向转换【免费下载链接】follyAn open-source C library developed and used at Facebook.项目地址: https://gitcode.com/GitHub_Trending/fol/follyfolly::dynamic是 Folly 提供的运行时动态类型值常与 JSON 解析配合使用但解析结果缺乏编译期类型约束。DynamicConverter以convertToT(dynamic)/toDynamic(x)两个模板函数为核心在folly::dynamic与算术类型、字符串、容器、映射乃至用户自定义类之间建立类型安全的转换通道。读完本文你将掌握convertTo的完整用法、容器/映射的类型判定规则以及通过模板特化让自定义类型无缝接入这套转换体系的具体方法。本文主体基于 folly/docs/DynamicConverter.md并结合 folly/json/DynamicConverter.h 的实现细节与 folly/json/test/DynamicConverterTest.cpp 的测试用例进行印证。一、DynamicConverter 是什么当dynamic对象中存放的数据具有已知结构时把它转换为对应的强类型well-typedC 表示会非常有用。DynamicConverter正是为此而设计它提供了一组覆盖面很广的类型转换将dynamic对象变换为其类型明确的 C 表示从而在保留 JSON/dynamic灵活性的同时获得编译期的类型检查与更直观的访问方式。典型应用场景是与 folly/json.h 配合先用 JSON 解析得到folly::dynamic再用convertToT把该 JSON 值转换成类型明确的对象结构。正如 folly/docs/Dynamic.md 在介绍完dynamic的基础类型转换后所指出的更复杂的转换请参见 DynamicConverter。从源码结构看公共 API 位于 folly/json/DynamicConverter.h顶层 folly/DynamicConverter.h 是一个shim兼容头文件它对外暴露两个入口convertToT(const dynamic)把dynamic转换成语义为 T 的强类型值toDynamic(const T)反向操作把任意类型 T 转换回dynamic。template typename T T convertTo(const dynamic); template typename T dynamic toDynamic(const T);二、基本用法convertTo使用方式非常简单把一个dynamic传进模板化的convertTo即可。原文档给出的经典示例是把「vector of vector of int」从dynamic还原dynamic d { { 1, 2, 3 }, { 4, 5 } }; // a vector of vector of int auto vvi convertTofbvectorfbvectorint(d);仓库自带的可直接运行示例 folly/docs/examples/folly/DynamicConverter.cpp 与此等价并使用 GTest 验证结果TEST(converter, demo) { dynamic arrayOfArrayOfInt dynamic::array(dynamic::array(1, 3, 5), dynamic::array(2, 4, 6)); auto concrete convertTostd::vectorstd::vectorint(arrayOfArrayOfInt); EXPECT_EQ(concrete[0][2], 5); }三、支持的目标类型convertTo原生支持以下几类目标类型算术类型int64_t、unsigned short、bool、double等。由 folly/json/DynamicConverter.h 中的特化可知整型走folly::toT(d.asInt())浮点走folly::toT(d.asDouble())布尔走d.asBool()枚举类型也受支持先转换为底层整型再static_cast回枚举。字符串folly::fbstring与std::string均通过d.asString()取得。容器与映射容器如std::vectorT、folly::fbvectorT、std::setT、std::mapK, V、std::unordered_mapK, V等支持任意深度嵌套。此外源码实现还额外支持dynamic本身恒等转换convertTodynamic(d)原样返回std::pairF, S从长度为 2 的数组或单键对象构造以及 Optional / 指针类类型folly::Optional、std::optional、std::unique_ptr等null转换为空 Optional。对应的行为都有测试覆盖在 folly/json/test/DynamicConverterTest.cpp 的arithmeticTypes、simpleBuiltins、optional等用例中。四、容器与映射的自动判定规则convertToType会自动把Type判定为容器当且仅当同时满足以下三个条件具有Type::value_type具有Type::iterator存在一个接受两个 InputIterator 的构造函数。满足容器判定后转换通过调用它的 InputIterator 构造函数来完成对于数组型dynamic用d.begin()/d.end()对于对象型dynamic则用d.items().begin()/d.items().end()迭代键值对。在此基础上convertToType会把Type判定为映射map当且仅当具有Type::key_type具有Type::mapped_typevalue_type是pairconst key_type, mapped_type。这一判定逻辑在源码中有精确对应dynamicconverter_detail命名空间内的is_container、is_map、is_associative、is_range等 traits 模板见 folly/json/DynamicConverter.h而测试文件开头的静态断言验证了这些 traits 的判定结果例如static_assert(is_containerstd::vectorint::value); static_assert(is_containerstd::setint::value); static_assert(is_containerstd::mapint, int::value); static_assert(!is_containerint::value); static_assert(is_mapstd::mapint, int::value); static_assert(!is_mapstd::setint::value);4.1 数组源与对象源映射转换时convertToC兼容两种dynamic形态对象型dynamic如dynamic::object(1, one)(2, two)与数组型如dynamic::array(dynamic::array(3, three), dynamic::array(4, four))后者每个元素是键值对数组。测试用例simpleMap、mapKeyedByString分别覆盖了这两种输入形态。需要特别留意的是关联容器如std::unordered_map的转换实现刻意先构造空容器再insert以避免迭代器抛异常时直接初始化造成内存损坏代码注释与 ASan 相关测试用例asanExceptionCaseUmap、asanExceptionCaseUset都印证了这一细节。4.2 嵌套容器与复杂结构容器转换是递归的dynamic的每个元素再经convertTovalue_type转换。测试用例nestedContainers展示了fbvectorstd::vectoruint8_t与std::mapdouble, std::vectorfolly::fbstring这类深层嵌套的转换crazy用例甚至构造了五层嵌套的vectorunordered_mapbool, vectorsetstring进行往返验证。五、自定义类型模板特化 DynamicConverter如果你希望convertTo能够处理自己的自定义类只需为DynamicConverter提供一个包含静态方法convert的模板特化并且必须把特化放进folly命名空间。原文档示例——把 JSON 风格对象还原成词法分析器中的Tokenstruct Token { int kind_; fbstring lexeme_; explicit Token(int kind, const fbstring lexeme) : kind_(kind), lexeme_(lexeme) {} }; namespace folly { template struct DynamicConverterToken { static Token convert(const dynamic d) { int k convertToint(d[KIND]); fbstring lex convertTofbstring(d[LEXEME]); return Token(k, lex); } }; }该示例同时也是仓库测试用例example的组成部分见 folly/json/test/DynamicConverterTest.cpp 中的Token特化与TEST(DynamicConverter, example)它先用dynamic::object(KIND, 2)(LEXEME, a token)构造输入再断言convertToToken能正确还原kind_与lexeme_。特化生效后自定义类型还能作为容器元素参与递归转换——测试用例customClass展示了convertTostd::vectorA从数组dynamic构造出A的 vector其中A也是通过DynamicConverterA特化支持的。从实现层面看特化机制基于主模板template typename T, typename Enable void struct DynamicConverter;默认形态刻意不实现即对未支持类型产生编译错误而非运行时失败convertTo的入口实现为DynamicConvertertypename std::remove_cvT::type::convert(d)因此const修饰的模板参数也能正常处理测试用例consts覆盖了const double、const std::string、const bool等。六、反向转换toDynamic 与 DynamicConstructor与convertTo相对toDynamic(x)负责把强类型对象转换回dynamic其分派目标是DynamicConstructorC::construct(x)。源码中预置了以下特化恒等dynamic原样返回枚举转换为底层整型dynamic映射迭代paird.insert(toDynamic(key), toDynamic(value))产出对象型dynamic其他 range逐个push_back(toDynamic(item))产出数组型dynamicstd::pair转换为双元素数组Optional / 指针类有值转toDynamic(*x)空值转dynamic()即nullstd::vectorbool特殊处理避免迭代器返回的 proxy 无法绑定到auto的问题。测试用例construct系统地验证了这些反向转换例如vectorint→ 数组、mapstring, pairstring,int→ 嵌套对象/数组、vectorOptionalint{3, none, 4}→dynamic::array(3, dynamic(), 4)、枚举 → 底层整型等。这意味着convertTo与toDynamic配合使用即可实现强类型数据与 JSON 形态数据的双向无损转换如simpleVectorBool用例的convertTodecltype(bools)(d)往返一致。七、类型不匹配与异常行为转换并非无条件成功当dynamic的运行时类型与目标类型不符时会抛出folly::TypeError。测试用例给出了具体证据convertTostd::unordered_mapint, int(dynamic::array(1))抛TypeError数组元素不是键值对convertTostd::unordered_setint(dynamic::array(1, dynamic::array(), 3))抛TypeError数值范围溢出时抛std::range_error如把超出int32_t上限的int64_t转成int32_t。另外dynamicconverter_detail::Dereferencer对数组迭代器遇到对象型dynamic或反之会主动throw_exceptionTypeError(array, dynamic::Type::OBJECT)保证错误在第一时间暴露而非静默产生错误数据。容器转换中途抛异常时测试用例doubleDestroy验证了构造次数与析构次数一致即异常安全、不会发生资源泄漏或双重释放。八、总结DynamicConverter的价值在于把 Folly 的「动态类型」世界与「强类型」世界打通解析侧convertToT把 JSON 解析出的folly::dynamic一键还原为vector、map、pair、Optional 乃至自定义业务类型序列化侧toDynamic把强类型数据反推回dynamic再交给 JSON 输出扩展侧在folly命名空间内特化DynamicConverterT提供静态convert即可让任何自定义类型接入且自动获得容器递归转换能力。配合 folly/json/test/DynamicConverterTest.cpp 中覆盖全面且可直接参考的测试用例以及可运行的示例 folly/docs/examples/folly/DynamicConverter.cpp你可以在自己的代码中快速、安全地建立 JSON ↔ 强类型对象的转换管线。【免费下载链接】follyAn open-source C library developed and used at Facebook.项目地址: https://gitcode.com/GitHub_Trending/fol/folly创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考