如何用 folly result<T> 替代异常返回并用 or_unwind 传播错误

发布时间:2026/11/5 0:07:49

如何用 folly result<T> 替代异常返回并用 or_unwind 传播错误 如何用 folly result 替代异常返回并用 or_unwind 传播错误【免费下载链接】follyAn open-source C library developed and used at Facebook.项目地址: https://gitcode.com/GitHub_Trending/fol/folly在 C 服务代码里如果你希望某些关键路径不再抛异常、错误必须被显式检查和处理folly 的folly/result提供了resultT函数不再throw而是返回resultT其中要么装着值要么装着错误std::exception_ptr或 stopped取消状态。配合协程语法co_await or_unwind(...)未处理的错误会沿调用链向上传播类似 Rust 的?运算符。本文的任务是把一段抛异常的同步函数改写成resultT协程用or_unwind传播错误并在调用点用get_exception/get_rich_error_code完成处理与验证。前提C20 与协程支持result及相关宏由FOLLY_HAS_RESULT门控。在 Portability.h 中可以看到判定条件必须同时满足 C20FOLLY_CPLUSPLUS 202002L且编译启用了协程支持FOLLY_HAS_COROUTINES否则FOLLY_HAS_RESULT为 0result的协程能力包括or_unwind不可用。因此你的构建需要 C20 标准和支持协程的编译器。用到本场景需要包含的头文件#include folly/result/result.h // resultT, error_or_stopped, get_exception #include folly/result/coro.h // or_unwind, or_unwind_owning // 需要错误上下文时再加 #include folly/result/or_unwind_epitaph.hAPI 细节以头文件内的 docblock 为准完整用法见 result.md。第一步函数返回 result 错误不再 throwresultT返回的函数体写成协程即可。错误分支不throw而是返回error_or_stopped{异常对象}// 这个 result coro 就像一个返回 result 的普通同步函数 // 但它等价于函数体被 try {} catch(...) { // return error_or_stopped::from_current_exception(); } 包围 resultsize_t countGrapefruitSeeds() { // 若 getFruitBox() 返回 error 或 stopped // co_await or_unwind 会立即把该状态向上传播 auto box co_await or_unwind(getFruitBox()); auto boxRes box.findFruit(FruitTypes::GRAPEFRUIT); if (auto ex get_exceptionRottenFruit(boxRes)) { logDiscardedGrapefruit(ex); // ex 用起来像 const RottenFruit* return 0; } const auto grapefruit co_await or_unwind(boxRes); size_t numSeeds 0; // fetchSegments() 返回的不是 result它抛出的异常 // 会被捕获并打进本函数的返回值 auto segments grapefruit.fetchSegments(); for (auto segment : segments) { numSeeds (co_await or_unwind(segment.seeds())).size(); } co_return numSeeds; }这段代码来自 result.md 的 Use-case 1 示例其中getFruitBox、findFruit、RottenFruit等为示意符号替换为你自己的函数与异常类型即可。要点result协程而不是普通函数是异常边界函数体内任何未被捕获的异常都会被自动捕获进返回值调用方可以假定该函数不会向外抛异常除std::bad_alloc及参数拷贝/移动构造之外。resultT是[[nodiscard]]单写一句resultFoo()不处理会编译失败你必须显式co_await or_unwind(resultFoo())从机制上杜绝忘记检查返回值。不要给result协程加noexcept——文档明确说明这会导致参数构造抛异常或std::bad_alloc时std::terminate。第二步用 co_await or_unwind 向上传播or_unwind定义见 coro.h支持的类型有resultT、value_only_resultT和error_or_stopped。行为规则参数是值取出值返回是 error 或 stopped立即短路把该状态传给当前协程的 awaiter向上传播。取值方式影响拷贝co_await or_unwind(resFn())对右值返回T错误路径上exception_ptr以 move 传播约 1ns对左值co_await or_unwind(res)返回T错误路径上exception_ptr是拷贝约 7ns。错误路径热时用std::move(res)冷路径优先可读性。不要用auto ref co_await or_unwind(resFn())这是文档标注的已知悬垂问题见 result.md 的 Known issue 一节引用绑定到临时结果后在语句结束即失效。安全写法是auto val co_await or_unwind(resFn());按值存储、co_await or_unwind_owning(resFn())或先存结果再std::move传递。处理特定错误时用folly::get_exception替代try-catch多类错误用else if链式判断result handlesErrors() { auto r propagatesErrors(); if (auto* ex get_exceptionMyErr(r)) { // 处理 ex用起来像 const MyErr* } else { auto v co_await or_unwind(std::move(r)); // 未处理的 error 或 stopped 继续传播 } }配合rich_error体系见 rich_error.mdget_exceptionErr(res)返回一个指针-like 对象直接支持fmt和operator会打印错误码、消息、源码位置和传播上下文epitaph 栈。注意查询时写具体的Err类型不要写rich_errorErrif (auto err get_exceptionFruitError(res)) { // 注意不是 FruitError* // 打印 code、message、source location 与传播上下文 LOG(ERROR) Failed to peel fruit: err; }如果只需要错误码用get_rich_error_codeCode(container)返回std::optionalCode查不到 code不等于没有错误错误可能用了别的 code 或不支持 code 协议。可选用 epitaph 给错误附加传播上下文错误沿调用链传播时会丢失在哪一层出的问题。epitaph包装器可以给 error/stopped 状态附加一条消息和源码位置构建轻量错误栈or_unwind_epitaph是or_unwind(epitaph(...))的语法糖见 or_unwind_epitaph.h值路径上跳过 epitaph 零开销错误路径才附加// 来自 result.md co_return co_await or_unwind_epitaph( resultFn(), context {}, arg); // 等价的手写形式来自 rich_error.md co_await or_unwind(epitaph(resultFn(), in {} due to {}, place, reason));epitaph 是透明的get_exceptionEx()访问到的是底层错误而非包装器。热路径可以不加 epitaph——文档给出的当前开销约为 60ns属于可选项按需启用。验证跑仓库内的 demo 或按同样的模式检查仓库提供了一个可直接阅读的完整示例 demo/basketball.cpp它演示了错误产生make_coded_rich_error、带 epitaph 的传播or_unwind(epitaph(...))以及调用点的完整处理循环int main() { Player inbounder, pointGuard, shootingGuard; pointGuard.passingLaneBlocked true; while (true) { auto points runFastBreak(inbounder, pointGuard, shootingGuard); if (points.has_value()) { return points.value_or_throw(); } if (auto ex get_exceptionstd::exception(points)) { fmt::print(Debug log: {}\n, ex); } if (std::errc::resource_unavailable_try_again get_rich_error_codestd::errc(points)) { pointGuard.passingLaneBlocked false; fmt::print(retrying after clearing the lane\n); continue; } return 0; // Score no points (currently unreachable) } }main()里的has_value()/get_exception/get_rich_error_code三连就是验证错误处理的检查方式先区分值与错误再按类型查具体异常最后按 code 做分支demo 中std::errc只是示意文档特意注明真实代码不要拿std::errc当业务错误码。README.md 给出了该 demo 在错误路径上的文档示例输出不是每次运行都必须一致的固定日志源码位置和行号会随版本变化passing lane blocked - std::errc11 (Resource temporarily unavailable) result/demo/basketball.cpp:39 [via] fast break collapsed result/demo/basketball.cpp:47其中[via]后面就是 epitaph 添加的上下文。你自己的代码若也能打出错误消息 来源位置 [via] 传播上下文说明 rich error 与 epitaph 链路工作正常。限制与非协程替代路径以下约束来自文档直接影响你能怎么写调试构建下的硬性校验error_or_stopped若装入空std::exception_ptr或OperationCancelled在 debug 构建中会std::terminate见 result.h 顶部 docblock。取消应使用stopped_result/has_stopped()而不是抛OperationCancelled。value_or_throw()只用于边缘场景在result协程里它就是co_await or_unwind(res)的低效写法文档明确不推荐若写非协程的热路径函数先显式if (res.has_value())再用它让throw 分支不可能发生。非协程替代路径老编译器等确实不能用协程时可以写普通函数返回resultT调用方无感知差异但必须遵守基本不抛契约。result.md 给出的写法是用result_catch_all包住函数体内部错误用return rh.error_or_stopped();手动传播#include folly/result/result.h resultint plantSeeds(int n) { return result_catch_all([]() - resultint { if (n 0) { return error_or_stopped{std::logic_error{cannot plant 0 seeds}}; } int seedsLeft n; for (int i 0; i n; i) { auto rh digHole(i); if (auto ex get_exceptionHitBigRock(rh)) { continue; // 跳过这颗种子 } else if (!rh.has_value()) { return rh.error_or_stopped(); // 未处理的 error 或 stopped } rh.value_or_throw().plantSeed(i); --seedsLeft; } return seedsLeft; }); }性能预期文档基准供决策参考错误传播是 O(1ns) 级而throw超过 1µsor_unwind错误路径为 3-30ns值路径每个函数调用多约 1 个分支的开销。富错误整体比整数错误码慢约 10 倍、比抛异常快 10-200 倍高频错误条件可考虑immortal_rich_errorconstexpr 单例构造/销毁 5ns。需要与异步folly::coro任务互操作时同一套语法仍然成立res co_await value_or_error_or_stopped(task())拿到result后照常co_await or_unwind(res)纯向上传播异常则继续用co_await co_nothrow(childTask())。与旧Try代码的互操作通过result_to_try()/try_to_result()完成选型依据见 design_notes.md。【免费下载链接】follyAn open-source C library developed and used at Facebook.项目地址: https://gitcode.com/GitHub_Trending/fol/folly创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/11/5 3:32:12

基于PyTorch的农作物病虫害识别:迁移学习与图像分类实战

简介:农作物病虫害识别系统是一份基于机器学习(Python)的完整毕业设计项目,适合计算机、人工智能等相关专业学生用于课程设计、论文实验或期末项目,也适合作为图像分类入门的工程范例。资源共477个文件,压缩…

2026/11/5 7:15:08

基于RPA的企微私域管理系统架构与实战复盘

2026年是农历丙午马年,对不少做私域运营的团队来说,新年的头等大事不是换slogan,而是把手里越来越重的人工活真正“盘活”。企业微信的客户联系能力越来越强,可日常运营里的手工环节也跟着多了:加好友要导入&#xff0…

2026/11/5 13:25:11

基于ADS122U04IPWR与STM32F427ZI的工业测温方案设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 13:20:10

Dubbo服务下线实时告警:基于ZooKeeper Watch的轻量级监控方案

简介:这是一套面向Java分布式系统运维与开发人员的Dubbo服务高可用监控解决方案,聚焦于Provider异常下线的实时感知与告警响应。资源通过Zookeeper监听机制实现服务状态变更捕获,结合邮件通知模块,在不侵入原有Dubbo代码的前提下&…

2026/11/5 13:20:10

SSM超市管理系统源码解析:从分层架构到本地部署与业务修改

简介:这份资源是面向高校计算机专业学生与Java初学者的一套SSM框架课程设计完整项目,围绕超市管理场景,帮助读者完成从框架整合到业务模块落地的实战练习,适合作为毕业设计或课程作业的参考方案。压缩包共792个文件,约…

2026/11/5 13:20:10

SSM超市管理系统实战:从课设跑通到二次开发全解析

简介:这份资源是面向高校计算机相关专业学生与Java入门开发者的SSM课程设计参考项目,围绕超市管理场景,解决商品、库存、销售等业务模块从设计到落地的实践需求,适合作为课程作业、毕业设计原型或SSM框架练手案例。压缩包共792个文…

2026/11/5 13:15:07

PIPE4.3.0安装排错:JDK版本、JAVA_HOME与Petri验证

简介:PIPE 4.3.0 是一款基于 Petri 网的图形化建模与仿真软件,面向软件工程、系统分析与教学实验场景,帮助读者完成并发、同步与竞争等系统行为的建模、动态仿真及性质分析。压缩包共 2391 个文件,约 28.43MB,包含大量…

2026/11/5 13:15:07

用栈实现队列:双栈结构与工程实践

1. 栈与队列的相爱相杀第一次看到这个题目时,我正坐在星巴克啃着牛角包。用栈实现队列?这就像用筷子喝汤——不是不行,但总觉得哪里怪怪的。栈和队列这对数据结构里的欢喜冤家,一个后进先出(LIFO)&#xff…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑