恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Folly Format 指南:folly::format 类型安全格式化设施的语法、实现与扩展
首页
资讯中心
/
Folly Format 指南:folly::format 类型安全格式化设施的语法、实现与扩展
Folly Format 指南:folly::format 类型安全格式化设施的语法、实现与扩展
发布时间:2026/9/10 23:56:45
Folly Format 指南folly::format 类型安全格式化设施的语法、实现与扩展【免费下载链接】follyAn open-source C library developed and used at Facebook.项目地址: https://gitcode.com/GitHub_Trending/fol/follyfolly::format是 FacebookMeta开源的 C 库 folly 提供的文本格式化设施其规范语言与 Python 的str.format类似用于将字符串、整数、浮点数以及动态类型的folly::dynamic对象安全地组装成可读文本。本文以仓库中的官方文档 folly/docs/Format.md 为主体结合 folly/Format.h、folly/FormatArg.h、folly/Format-inl.h 等源码实现完整讲解格式串语法、格式规范、容器取值、错误处理与自定义类型扩展帮助读者在项目里直接落地这套类型安全的格式化方案。快速上手folly/Format.h提供了一个快速、强大、类型安全且灵活的文本格式化设施默认即可格式化字符串、整数、浮点数以及动态类型的folly::dynamic对象并能从随机访问容器与字符串键映射中取值。在许多场景下format比sprintf更快并且完全类型安全。以下示例直接取自官方文档可快速入门using folly::format; using folly::sformat; // format() 产生的对象可直接流入流中无需创建中间字符串 // {} 按默认格式取下一个参数。 std::cout format(The answers are {} and {}, 23, 42); // The answers are 23 and 42 // 如果只需要字符串直接使用 sformat。 std::string result sformat(The answers are {} and {}, 23, 42); // The answers are 23 and 42 // 要输出字面量 { 或 }将其加倍即可。 std::cout format({} {{}} {{{}}}, 23, 42); // 23 {} {42} // 参数可以不按顺序引用甚至可以多次引用。 std::cout format(The answers are {1}, {0}, and {1} again, 23, 42); // The answers are 42, 23, and 42 again // 不引用全部参数也完全没问题。 std::cout format(The only answer is {1}, 23, 42); // The only answer is 42 // 可以从可索引容器随机访问序列、整数键映射以及字符串键映射中取值。 std::vectorint v {23, 42}; std::mapstd::string, std::string m { {what, answer} }; std::cout format(The only {1[what]} is {0[1]}, v, m); // The only answer is 42 // format 支持 pair 与 tuple。 std::tupleint, std::string, int t {42, hello, 23}; std::cout format({0} {2} {1}, t); // 42 23 hello // 支持宽度、对齐、任意填充字符以及各种格式说明符语义与 printf 类似。 // X10以 X 填充、左对齐、宽度 10。 std::cout format({:X10} {}, hello, world); // helloXXXXX world // 字段宽度可以是运行时值而不必写在格式串里。 int x 6; std::cout format({:-^*}, x, hi); // --hi-- // 显式参数配合动态宽度使用时值参数与宽度参数都必须给出索引。 std::cout format({2:^*0}, 9, unused, 456); // 456 // 支持 printf 风格格式说明符。 std::cout format({0:05d} decimal {0:04x} hex, 42); // 00042 decimal 002a hex // Formatter 对象可借助 folly::to / folly::toAppend见 folly/Conv.h // 写入字符串也可调用 appendTo() 与 str() 方法。 std::string s format(The only answer is {}, 42).str(); std::cout s; // The only answer is 42 // 小数精度用法。 std::cout format(Only 2 decimals is {:.2f}, 23.34134534535); // Only 2 decimals is 23.34格式串语法格式串format的完整文法如下{ [arg_index] [[ key ]] [: format_spec] }各组成部分说明arg_index待格式化参数的索引默认取下一个参数。注意一份格式串要么全部使用默认参数索引要么全部使用显式索引二者不能混用以免引起歧义。源码中的校验见 folly/test/FormatTest.cpp例如sformat({0} {} {1}, 0, 1, 2)会抛出BadFormatArg错误信息为may not have both default and explicit arg indexes。key当参数是容器C 风格数组或指针、std::array、vector、deque、map时用key选取要格式化的元素支持随机访问序列、整数键映射与字符串键映射。多级 key 也支持各层之间用.分隔例如对mapstring, mapstring, string m{[foo.bar]}会选择m[foo][bar]。参数索引越界或 key 不存在时抛出异常详见后文错误处理一节。format_spec格式规范见下一节。格式规范格式规范format_spec的文法如下[[fill] align] [sign] [#] [0] [width] [,] [. precision] [.] [type]各组成部分逐项说明均取自官方文档fill仅当同时指定align时才允许用于填充的字符 空格与0零较为常用默认填充字符是空格。align对齐方式取值为、、、^之一左对齐大多数对象的默认对齐方式右对齐数字的默认对齐方式在符号之后、有效数字之前填充用于打印如-0000120这种形式仅对数字有效^居中对齐。sign符号控制取值为、-、空格仅对数字有效正数或零时输出负数时输出--负数时输出-否则不输出默认行为 空格正数或零时输出一个空格负数时输出-。#输出进制前缀八进制为0二进制为0b或0B十六进制为0x或0X仅对整数有效。0符号之后补零等价于把fill与align指定为0仅对数字有效。width最小字段宽度。可以是*表示字段宽度由某个参数给出默认取下一个参数即待格式化值前面的那个参数也可以在*后跟显式参数索引。从源码看FormatArg用kDefaultWidth -1表示未指定、kDynamicWidth -2表示动态宽度见 folly/FormatArg.h。动态宽度相关约束同样有测试覆盖sformat({:*}, 1.2)报dynamic field width argument must be integralsformat({:*0}, 12, ok)报cannot provide width arg index without value arg indexsformat({0:*}, 12, ok)报cannot provide value arg index without width arg index。,逗号输出逗号作为千位分隔符仅对整数有效且仅限十进制输出。测试用例见 folly/test/FormatTest.cpp 的separatorDecimalInteger、separatorNumber、separatorUnit系列。precision整数不允许使用对浮点值表示小数点后的位数f或F呈现或有效数字个数g或G对其他类型表示最大字段大小截断后续字符。.在 precision 之后使用或代替 precision强制输出尾部小数点以明确这是浮点值。type呈现格式见下一节。呈现格式Presentation Formats字符串folly::StringPiece、std::string、folly::fbstring、const char*s默认。整数b以二进制基 2输出指定#时带0b前缀B以二进制基 2输出指定#时带0B前缀c作为字符输出强转为chard以十进制基 10输出默认o以八进制基 8输出O以八进制基 8输出与o相同x以十六进制基 16输出大于 9 的数字用小写字母X以十六进制基 16输出大于 9 的数字用大写字母nlocale 感知输出当前与d相同。bool默认以字符串true或false输出也允许使用整数呈现格式。char与其他整数相同但默认呈现是c而非d。浮点float、doublelong double未实现e以e作为指数符号的科学计数法E以E作为指数符号的科学计数法f定点表示F定点表示与f相同g通用表示根据数值大小选择f或e默认G通用表示根据数值大小选择f或Enlocale 感知的g当前与g相同%百分比先乘以 100再以f形式显示。Formatter 的多种输出方式format()返回的是一个Formatter对象而不是字符串这是它区别于sprintf的关键设计。Formatter对象的头文件注释明确指出它持有左值参数的引用同时接管临时对象的生命周期并且不拷贝传入的格式串因此不能直接构造使用必须经由format(...)入口获得见 folly/Format.h。针对该对象可以直接流入流operator已针对Formatter重载见 folly/Format.h逐段写出而无需创建中间字符串转为字符串调用.str()方法或通过folly::to/folly::toAppend见 folly/Conv.h写入字符串追加到已有字符串调用.appendTo(str)str可以是std::string、fbstring等 folly 字符串类型folly/Format.h直接格式化进字符串指针format(foo, {} {}, 42, 23)这是toAppend(format(...), foo)的快捷方式folly/Format.h。如果只想要字符串结果直接使用sformat(fmt, args...)它在内部构造Formatter后立即调用.str()返回folly/Format.h。容器取值与动态对象可索引容器与字符串键映射格式串中的[key]语法对应FormatArg内部的键拆分逻辑splitKey()按.拆分多级 keysplitIntKey()则把 key 解析为整数folly/FormatArg.h。容器支持通过偏特化机制分派整数可索引容器std::array、std::vector、std::deque、整数键的std::map/std::unordered_map由IndexableTraits描述对应的FormatValue偏特化通过splitIntKey()取元素folly/Format-inl.h字符串键映射键类型为std::string、fbstring、StringPiece的std::map/std::unordered_map由KeyableTraits描述通过splitKey()取元素folly/Format-inl.h。因此文档中的format(The only {1[what]} is {0[1]}, v, m)实际走的是先取参数 1 的what键再取参数 0 的下标 1两条取数链路。越界行为由测试确认sformat({[5]}, ints)对越界下标抛出std::out_of_rangesformat({[nope]}, map)对不存在的键同样抛出std::out_of_rangefolly/test/FormatTest.cpp。pair 与 tupleFormatValue对std::pairA, B与std::tupleArgs...有专门偏特化folly/Format-inl.h因此format({0} {2} {1}, t)这类写法才得以生效。dynamic 对象folly::dynamic是 folly 的动态类型值官方文档把它列为默认可格式化对象之一。其实现位于 folly/json/dynamic-inl.hFormatValuedynamic的format()按dynamic的实际类型分派——NULLT走空指针输出、BOOL走bool、INT64走int64_t、STRING走字符串、DOUBLE走浮点而ARRAY用整数 key 取元素、OBJECT用字符串 key 取元素。这使得format({[name]}, dynamicObj)这样的写法可以直接作用在 JSON 风格的动态对象上。扩展为自定义类型提供 FormatValue 特化format的可扩展性是官方文档明确支持的特性为folly::FormatValue提供特化即可让自定义类型参与格式化。文档建议参考folly/Format.h、folly/FormatArg.h并以 folly/json/dynamic-inl.h 中folly::dynamic的现成特化作为实现范例。扩展要点见 folly/Format.h 的注释FormatValueT以引用折叠后的T构造该引用保证在FormatValue对象销毁前一直有效因此可以持有引用或指针而无需拷贝必须定义template class Callback void format(FormatArg arg, Callback cb) const;arg以非 const 引用给出允许就地修改例如包裹已有转换但修改默认值或在从容器取元素时移除 keycb是输出回调可以多次调用甚至不调用用于输出空字符串。Formatter类还有第二层扩展点通过继承BaseFormatter并重写doFormatArg与recordUsedArg可以自定义对位置参数的实际格式化行为folly/Format.h。测试文件中的TestExtendingFormatter正是这样做的它在派生类里重写doFormatArg先把每个参数按默认规则格式化再用fmt::format({{{}}}, result)包上一层花括号folly/test/FormatTest.cppCustom测试则验证了自定义类型KeyValue特化后配合{:10}、{:.10}、{:X23}、{:X23}等宽度/对齐/截断规范的组合行为folly/test/FormatTest.cpp。错误处理与防御性工具非法格式串与 BadFormatArg格式串解析与校验在FormatArg中完成非法用法统一抛出BadFormatArg继承自std::invalid_argumentfolly/FormatArg.h。测试用例BogusFormatString系统性地验证了这些错误路径folly/test/FormatTest.cpp单独出现的}single } in format string缺少结尾}missing ending }负数参数索引argument index must be non-negative显式索引与默认索引混用may not have both default and explicit arg indexes动态宽度参数不是整数dynamic field width argument must be integral参数索引越界argument index out of range, maxN。缺失键与 FormatKeyNotFoundException当字符串键映射中找不到 key 时KeyableTraitsAssoc::at会抛出专门的FormatKeyNotFoundException继承std::out_of_rangefolly/Format-inl.h。该类特意把 key 放在异常消息末尾使异常类型保持小巧且可 noexcept 拷贝folly/Format.h。defaulted()越界时返回默认值folly::defaulted(container, defaultValue)把容器包装成DefaultValueWrapper使越界下标或缺失键不再抛异常而是返回指定默认值folly/Format.h。例如文档中的用法format([no_such_key], defaulted(map, 42))会得到42。该包装对可索引容器folly/Format-inl.h、字符串键映射folly/Format-inl.h以及dynamicfolly/json/dynamic-inl.h均有专门实现后者在数组下标越界或对象键缺失时输出默认值。底层实现要点FormatArg一次解析、处处复用FormatArg是格式化的核心中间结构folly/FormatArg.h它持有格式串引用不拷贝字符并把fill、align、sign、basePrefix、thousandsSeparator、trailingDot、width、widthIndex、precision、presentation等解析结果全部展开为字段。对齐与符号分别用Align、Sign枚举表达非法值由validate(Type)在类型校验阶段拦截。编译期查表优化在 folly/Format.cpp 中对齐表、符号表、十六进制大小写各一、八进制、二进制的转换均以constexpr构造的查表实现如make_array_with256(...)把常见的数字到 ASCII 转换压成一次查表这也是文档所称许多场景下比sprintf更快的实现基础。数字格式化的两条路径format_value::formatNumber把符号、进制前缀等前缀与数字主体分开处理以支持PAD_AFTER_SIGN这类符号后填充的对齐方式folly/Format-inl.h。整数FormatValue的统一实现把所有计算转为无符号进行再自行附加前缀与符号并特别规避了无符号取负的未定义行为folly/Format-inl.h。浮点double的实现folly/Format.cpp默认精度为 6 位当用户写裸{}无任何说明符与精度时走最短往返shortest round-trip表示以保持数值精度而显式给出说明符或精度时走基于精度的路径精度上限与 double-conversion 保持一致小数后最多 100 位、指数最多 120 位。long double未实现这是官方文档明确说明的边界。延迟输出模型Formatter采用回调式输出format()不立即生成字符串而是把格式串 参数引用打包成Formatter对象直到真正写入流、追加到字符串或调用.str()时才逐段计算folly/Format.h。这既避免了多余中间字符串也让直接流式输出成为可能同时Formatter不可拷贝、只能由format()工厂构造移动构造私有从机制上防止了悬垂引用风险。现状与迁移提示需要说明的是源码头部注释明确指出folly::format已被 fmt 取代推荐使用#include fmt/core.hfolly/Format.h。folly::format入口本身也带有[[deprecated(Use fmt::format instead of folly::format ...)]]标记folly/Format.h建议新代码直接使用fmt::format以获得更好的性能、更短的编译时间以及与std::format的兼容性。仓库中的示例程序 folly/docs/examples/folly/Format.cpp 也已改用fmt::format如fmt::format(The answer to {} is {}, life, 42)得到The answer to life is 42fmt::format({:.2f}, 3.1415926535)得到3.14。不过folly::format的格式串语法、容器取值、defaulted()防御式默认值以及FormatValue扩展模型依然是理解 folly 格式化体系与迁移路径的最佳教材在维护存量 folly 代码时这份文档与上述源码、测试folly/test/FormatTest.cpp共同构成了最完整的参考资料。【免费下载链接】follyAn open-source C library developed and used at Facebook.项目地址: https://gitcode.com/GitHub_Trending/fol/folly创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考