Mojo 错误处理实战:基于 manual/errors 示例目录全面解析 try/except、类型化错误与上下文管理器

📅 发布时间:2026/9/10 1:58:40
Mojo 错误处理实战:基于 manual/errors 示例目录全面解析 try/except、类型化错误与上下文管理器
Mojo 错误处理实战基于 manual/errors 示例目录全面解析 try/except、类型化错误与上下文管理器【免费下载链接】mojoThe Modular Platform (includes MAX Mojo)项目地址: https://gitcode.com/GitHub_Trending/mo/mojo本文围绕 Mojo 仓库文档站代码目录 Mojo/docs/site/code/manual/errors/ 展开该目录收录了 Mojo Manual「Errors, error handling, and context managers」章节 中所有示例的完整可运行源码与单元测试。读完本文你将掌握 Mojo 将错误建模为“值”替代返回值而非栈展开异常的核心机制、try/except/else/finally四子句的完整语义、自定义类型化错误typed errors与Never类型、MODULAR_DEBUG堆栈跟踪开关以及__enter__()/__exit__()自定义上下文管理器的全部写法并能直接用 Bazel 目标复现每个示例。目录定位手册示例代码与测试的“权威副本”Mojo/docs/site/code/manual/errors/README.md 明确说明了该目录的用途它包含 Errors, error handling, and context managers 章节 中引用的全部代码示例与测试。目录内每个.mojo文件都是一个独立可编译的 Mojo 应用与手册中的代码片段一一对应因此手册中展示的输入输出可以直接在仓库里复现验证。按 README 的目录清单核心文件包括文件作用handle_error.mojo演示 Mojotry-except结构的完整示例stacktrace_error.mojo用于文档说明如何启用堆栈跟踪生成stacktrace_error_capture.mojo演示在处理错误时以编程方式捕获堆栈跟踪context_mgr.mojo一个无条件无错误感知的 Mojo 上下文管理器conditional_context_mgr.mojo一个带错误特殊处理的有条件上下文管理器此外还有一组使用 Mojo 测试框架编写的单元测试文件用于验证上述应用中的函数。README 中提到test_incr.mojo针对handle_error.mojo中incr()函数的测试而从当前仓库实际文件看test_handle_error.mojo 才是与handle_error.mojo配套的单测文件——它针对该文件中定义的process_record()编写测试说明示例代码经历了一次从incr()到process_record()的重构README 的目录说明尚未同步更新。设计总纲错误是“值”不是异常展开理解这个目录所有示例的前提是手册开篇阐述的核心设计见 errors.mdx 开头Mojo 将错误表示为值——具体来说是函数的替代返回值alternate return values。与 C、Java 这类语言的栈展开异常不同Mojo 错误不需要昂贵的调用栈展开其运行时开销仅相当于多返回并检查一个Bool。这一设计带来两个直接后果可在无异常机制的环境中使用——例如 GPU 内核堆栈跟踪不会自动采集——采集需要堆分配默认关闭这解释了后文MODULAR_DEBUG一节。错误传播规则同样简单若当前函数有try/except处理器执行在处理器处恢复否则错误向调用方传播直至被捕获若始终无人处理程序以非零退出码终止并打印Unhandled exception caught during execution: record not found这条提示语会在下文的多个示例输出中反复出现。抛错基础Error类型与raises声明内置Error类型是大多数 Mojo 代码的默认错误类型携带一段文本消息。两种等价的抛错写法# These are equivalent raise Error(file not found) raise file not found字符串字面量是编译器提供的语法糖会被自动包装为Error。要让函数“可能抛错”必须在签名中声明raisesdef read_file_fn(path: String) raises - String: if not path: raise path cannot be empty return contents of pathMojo 函数默认不抛错raises带或不带具体类型使函数成为抛错函数且每个函数至多声明一个错误类型——编译器会强制检查函数体内每条raise是否与声明类型匹配。try/except/else/finally四子句完整语义Mojo 的完整错误处理语法为try: # Code that might raise an error except e: # Runs if an error occurs else: # Runs if no error occurs finally: # Always runs, regardless of outcome约束是except与finally至少出现其一else可选且一个try块只能有一个except子句。各子句的精确行为try——可能抛错的代码。无错则整块执行出错则执行停在raise点转交except若有或finally。except——仅当try内出错时运行。except e:会把错误绑定到变量e。else——仅当try无错时运行但若try块以continue、break或return退出else会被跳过。finally——无论结果如何都运行且在except/else之后执行即使其他子句以continue/break/return或新错误退出它依然执行。典型用途是在无论成败与否都必须释放的资源如文件句柄上做清理。用handle_error.mojo逐行验证每个子句handle_error.mojo 是四子句语义的完整演练场。process_record()针对三类输入抛不同的错调用方循环遍历一组 id 逐条触发各子句def process_record(id: Int) raises - String: if id 0: raise Error(invalid record ID: must be non-negative) if id 999: raise Error(record not found) return String(record_, id) def main(): try: for id in [5, 0, 1001, -3, 42]: var result: String try: print() print(try id:, id) if id 0: continue result process_record(id) except e: if invalid in String(e): print(except fatal:, e) raise e print(except handled:, e) else: print(else success:, result) finally: print(finally done with id:, id) except e: print(\nre-raised error:, e)实际运行输出手册记录的原样输出try id: 5 else success: record_5 finally done with id: 5 try id: 0 finally done with id: 0 try id: 1001 except handled: record not found finally done with id: 1001 try id: -3 except fatal: invalid record ID: must be non-negative finally done with id: -3 re-raised error: invalid record ID: must be non-negative这段输出精确对应了前述每条子句规则值得逐条对照id 5成功else运行随后finally运行。id 0continue直接跳出try块except与else均被跳过只有finally运行——这是验证else跳过规则的关键用例。id 1001process_record()抛错except处理后执行继续进入下一轮迭代。id -3except识别出 invalid 后重新抛出re-raise错误传播到外层try/except。注意两点finally在错误传播前仍会执行重新抛出终止了循环因此id 42永远不会被处理。重新抛出与转移语义在except子句里把捕获到的错误传给raise即可重抛也可以在except里抛一个不同的错误try: var result process_record(-1) except e: print(Logging error:, e) raise e # re-raise细节值得注意重新抛出默认是拷贝错误——由于消息和可选的堆栈跟踪都是引用计数的拷贝代价很低。若想避免拷贝可用转移符号raise e^而对于不符合ImplicitlyCopyable的自定义错误类型重新抛出时必须使用转移符号。单元测试test_handle_error.mojo如何锁定边界行为配套的 test_handle_error.mojo 用std.testing的assert_raises把“恰好在哪条边界抛错”固化为测试from handle_error import process_record from std.testing import assert_equal, assert_raises, TestSuite def test_process_record_success() raises: assert_equal(process_record(0), record_0) assert_equal(process_record(5), record_5) assert_equal(process_record(999), record_999) def test_process_record_not_found() raises: with assert_raises(containsrecord not found): _ process_record(1000) with assert_raises(containsrecord not found): _ process_record(1001) def test_process_record_invalid_id() raises: with assert_raises(containsinvalid record ID: must be non-negative): _ process_record(-1) with assert_raises(containsinvalid record ID: must be non-negative): _ process_record(-3) def main() raises: TestSuite.discover_tests[__functions_in_module()]().run()这里体现了一个重要事实assert_raises(contains...)本身就是一个上下文管理器with语句它断言被包裹的调用会抛出包含指定子串的错误——这是上下文管理器与错误处理两大主题交汇的标准库用法assert_raises也出现在手册的上下文管理器小节中。测试边界选得很讲究999恰好成功、1000恰好触发 record not found、-1触发 invalid把process_record()的三条分支全部锁死。类型化错误Typed Errors把错误当作结构化数据当错误需要携带结构化的字段如错误码 描述或需要零堆分配地用于 GPU 内核时Mojo 允许用struct 直接充当错误类型——不需要特殊基类。手册推荐实现Writabletrait使错误在被打印或导致程序终止时输出可读消息fieldwise_init struct ValidationError(Copyable, Writable): var field: String var reason: String def write_to(self, mut writer: Some[Writer]): writer.write(ValidationError(, self.field, ): , self.reason)fieldwise_init装饰器会为每个字段生成一个带参的__init__()因此既可位置构造ValidationError(username, too short)也可关键字构造。声明与捕获方式def validate_username(username: String) raises ValidationError - String: if username.byte_length() 0: raise ValidationError(fieldusername, reasoncannot be empty) if username.count_codepoints() 3: raise ValidationError( fieldusername, reasonmust be at least 3 characters ) return username捕获时编译器从被调函数自动推断错误类型except e:中的e就是完整的ValidationError值可直接访问字段、无需转换try: var name validate_username() except e: # e is a ValidationError — access fields directly print(Error in field e.field : e.reason)Error in field username: cannot be empty注意 Mojo不支持except ErrorType as e:这种显式类型语法——类型永远由被调函数推断要处理两种不同错误类型就写两个try块。完整的可运行版本在 typed_errors.mojo。表示多个错误条件枚举式变体与Variant由于每个函数只能声明一个错误类型一个函数若可能以多种方式失败需要在一个类型内表达多个条件。仓库给出了两条路线路线一枚举式错误类型enumerated_errors.mojo——单 struct 整型_variant字段 comptime常量别名fieldwise_init struct FileError(Equatable, ImplicitlyCopyable, Writable): var _variant: Int # Compile-time constant variants comptime not_found FileError(_variant1) comptime permission_denied FileError(_variant2) comptime already_exists FileError(_variant3) def variant_name(self) - String: if self._variant 1: return not_found elif self._variant 2: return permission_denied elif self._variant 3: return already_exists return unknown def write_to(self, mut writer: Some[Writer]): writer.write(FileError., self.variant_name())因为FileError只有一个Int字段且符合Equatable编译器会自动合成__eq__()处理端可以直接比较变体try: print(open_file(/secret)) except e: if e FileError.not_found: print(Not found:, e) elif e FileError.permission_denied: print(Permission denied:, e)路线二Variant类型variant_errors.mojo——当每种条件需要携带不同的数据时使用。标准库Variant把各条件的独立 struct 合并成一个错误类型from std.utils import Variant fieldwise_init struct NotFoundError(Copyable, Writable): var path: String def write_to(self, mut writer: Some[Writer]): writer.write(file not found: , self.path) fieldwise_init struct PermissionError(Copyable, Writable): var path: String var required_role: String def write_to(self, mut writer: Some[Writer]): writer.write( permission denied on , self.path, (requires , self.required_role, ), ) comptime FileError Variant[NotFoundError, PermissionError]构造时用Variant包装内层错误处理时用.isa[T]()判定条件、用e[T]取出带完整类型的内层错误def open_file(path: String) raises FileError - String: if not path: raise FileError(NotFoundError()) if path /secret: raise FileError(PermissionError(/secret, admin)) return Contents of path # 处理端 try: print(open_file(/secret)) except e: if e.isa[NotFoundError](): print(Not found:, e[NotFoundError]) elif e.isa[PermissionError](): print(Access denied:, e[PermissionError])Access denied: permission denied on /secret (requires admin)选型经验只区分条件、不带差异化数据时用枚举式更简单高效每种条件带不同字段时用Variant。另外手册特别提醒类型化错误在 GPU/嵌入式目标上同样可用前提是避免String这类堆分配类型。Never类型编译期表达“必抛”与“必不抛”Never是一个没有任何初始化器、无法被实例化的类型用于错误签名中表达两种对立的编译期保证raises YourErrorType - Never——函数总是抛出、绝不返回值适用于panic()这类无条件报错函数raises Never - ReturnType——函数绝不抛出、总是返回值等价于干脆不写raises。# Always raises, never returns def panic(msg: String) raises - Never: raise Error(msg) def get_value_or_panic(maybe: Optional[Int]) raises - Int: if maybe: return maybe.value() # Never substitutes for Int in this branch panic(value is missing)由于Never可以替代任意类型编译器允许把- Never函数放在需要返回值的位置——get_value_or_panic的第二个分支没有return却通过了“必须返回Int”的类型检查。而raises Never的等价性never_type.mojo# These two signatures are equivalent: def safe_add(a: Int, b: Int) raises Never - Int: return a b def safe_add(a: Int, b: Int) - Int: return a b这一点在参数化raises下一节中尤其有用当传入的函数参数不抛错时编译器会推断出raises Never。参数化 raises让调用方“继承”被调函数的错误类型parametric_raises.mojo 展示了用编译期参数把错误类型从函数参数透传给调用方的写法def run_action ErrorType: AnyType thin raises ErrorType - Int) raises ErrorType - Int: return action()ErrorType由实参函数推断传入抛NetworkError的函数run_action就抛NetworkError传入抛ParseError的函数就抛ParseErrordef fetch_data() raises NetworkError - Int: raise NetworkError(code404) def parse_config() raises ParseError - Int: raise ParseError(position42) # ErrorType inferred as NetworkError try: _ run_action(fetch_data) except e: print(Network failure:, e) # ErrorType inferred as ParseError try: _ run_action(parse_config) except e: print(Parse failure:, e)若传入的函数不抛错编译器把ErrorType推断为Neverrun_action本身变成非抛错函数连try都不需要def get_value() - Int: return 99 # ErrorType inferred as Never — no try block needed var result run_action(get_value) print(Got value:, result)Got value: 99类型化错误与内置Error的混用规则真实代码库往往两种风格并存。error_interaction.mojo 是手册给出的完整交互示例其中三条规则务必掌握1. 在 API 边界把Error包装为类型化错误def validate_with_error(value: Int) raises - Int: if value 0: raise value cannot be negative return value def wrapped_validate(value: Int) raises ValidationError - Int: try: return validate_with_error(value) except e: raise ValidationError(fieldvalue, reasonString(e))2. 避免裸raises造成类型擦除。调用类型化函数却只声明裸raises时编译器会忘记具体错误类型调用方拿到的是Error而非ValidationErrore.field无法编译运行时消息虽然仍显示ValidationError因为Writable输出被保留但结构化字段访问已经丢失。若错误在本地被捕获字段访问依然完好——类型擦除只影响穿过裸raises函数向上传播的未捕获错误。3. 同一个try块内不能混用不同错误类型# This doesnt compile def mixed() raises ValidationError: try: _ error_func() # raises Error _ typed_func() # raises ValidationError except e: print(e)编译器报错cannot call function that may raise Error in a context that supports an error type of ValidationError。解决方案就是拆成多个try块或在边界处做包装。堆栈跟踪默认关闭按需开启正因为 Mojo 错误是替代返回值而非栈展开异常堆栈跟踪采集不自动发生——它需要堆分配、有运行时开销所以默认禁用。且要注意这是内置Error类型的专属能力类型化错误目前不会采集堆栈跟踪是在Error.__init__()内部收集的自定义 struct 没有等价钩子。stacktrace_error.mojo 是一个三层调用链专门用于演示def func2() raises - None: raise Error(Intentional error) def func1() raises - None: func2() def main() raises: func1()默认设置下mojo build会优化并剥离符号即使开启跟踪也只能得到无符号地址的版本mojo build stacktrace_error.mojo MODULAR_DEBUGstack-trace-on-error ./stacktrace_error#0 0x... llvm::sys::PrintStackTrace(llvm::raw_ostream, int) #1 0x... KGEN_CompilerRT_GetStackTrace #2 0x... main (./stacktrace_error...) Unhandled exception caught during execution: Intentional error开启堆栈跟踪的开关是环境变量MODULAR_DEBUGstack-trace-on-error要得到带符号的有用跟踪还必须以--debug-level full或-g编译mojo build --debug-level full stacktrace_error.mojo MODULAR_DEBUGstack-trace-on-error ./stacktrace_error#0 0x... llvm::sys::PrintStackTrace(llvm::raw_ostream, int) #1 0x... KGEN_CompilerRT_GetStackTrace #2 0x... Error.__init__... .../builtin/error.mojo:159:38 #3 0x... stacktrace_error::func2() stacktrace_error.mojo:14:16 #4 0x... stacktrace_error::func1() stacktrace_error.mojo:18:10 #5 0x... stacktrace_error::main() stacktrace_error.mojo:22:10 #6 0x... __wrap_and_execute_raising_main... .../builtin/_startup.mojo:88:18 #7 0x... main .../builtin/_startup.mojo:103:4 Unhandled exception caught during execution: Intentional error带调试符号后跟踪完整呈现调用链main()→func1()→func2()→Error.__init__()及源码位置。两个适用限制分段错误segfault时 Mojo 本来就会生成堆栈跟踪而用mojo run直接运行即使加--debug-level full也不会产生符号化跟踪必须mojo build后运行编译出的二进制。以编程方式捕获堆栈跟踪stacktrace_error_capture.mojo 演示了在except子句里绑定Error实例并调用get_stack_trace()返回Optional[String]def func2() raises - None: raise Error(Intentional error) def func1() raises - None: func2() def main() raises: try: func1() except e: print(e) print(- * 20) var stack_trace e.get_stack_trace() if stack_trace: print(stack_trace.value()) else: print(No stack trace available)以mojo build --debug-level full编译并设置MODULAR_DEBUGstack-trace-on-error运行时输出完整的 8 帧跟踪不启用跟踪时get_stack_trace()返回None输出退化为Intentional error -------------------- No stack trace available这就是该示例在 BUILD.bazel 中被注册为modular_run_binary_teststacktrace_error_capture_test的原因在无MODULAR_DEBUG的默认测试环境下运行它验证程序不崩溃、优雅地打印 No stack trace available。上下文管理器让资源清理与错误处理解耦上下文管理器管理文件、网络连接等资源保证即使出错也能正确释放、防止泄漏。最典型的反面教材是手写文件操作var f open(input_file, r) var content f.read() # ... f.close()若read()抛错close()就永远不会执行写场景更糟——操作系统可能把输出缓存在内存中直到close()程序崩溃会导致缓冲数据丢失。try/finally可以补救而with语句则是最干净的写法with open(input_file, r) as f: var content f.read() # Process the content as neededwith还天然支持多个上下文管理器并行with open(input_file, r) as f_in, open(output_file, w) as f_out: var input_text f_in.read() var output_text input_text.upper() f_out.write(output_text)标准库里常见的上下文管理器还有FileHandle、NamedTemporaryFile、TemporaryDirectory、BlockingScopedLock以及前文测试用到的assert_raises。而自定义上下文管理器只需实现两个双下划线方法__enter__()——进入with时由with语句调用负责初始化状态并返回上下文管理器本身__exit__()——with代码块完成执行时调用哪怕以continue/break/return结束。它运行后上下文管理器即被销毁。若块内抛错__exit__()在任何错误处理被try/except捕获或程序终止之前运行。不需要释放资源的上下文管理器甚至可以省略__exit__()。示例一Timer——无条件上下文管理器context_mgr.mojo 实现一个打印with块耗时的Timerimport std.sys import std.time fieldwise_init struct Timer(ImplicitlyCopyable): var start_time: Int def __init__(out self): self.start_time 0 def __enter__(mut self) - Self: self.start_time Int(time.perf_counter_ns()) return self def __exit__(mut self): var end_time time.perf_counter_ns() var elapsed_time_ms round( Float64(end_time - self.start_time) / 1e6, 3 ) print(Elapsed time:, elapsed_time_ms, milliseconds) def main() raises: with Timer(): print(Beginning execution) time.sleep(1.0) if len(sys.argv()) 1: raise simulated error time.sleep(1.0) print(Ending execution)仓库中的实际源文件使用std.time.perf_counter_ns()/std.sys.argv()全限定写法与手册中的简写形式等价。两种运行方式的输出对比恰好验证了“出错时__exit__()依然执行”的承诺mojo context_mgr.mojoBeginning execution Ending execution Elapsed time: 2010.0 millisecondsmojo context_mgr.mojo failBeginning execution Elapsed time: 1002.0 milliseconds Unhandled exception caught during execution: simulated error第二例中with块在第一个sleep后抛出 simulated error耗时约 1000ms 的Elapsed time仍然打印__exit__()生效随后错误无人处理程序以该错误终止。配套单测在 test_context_mgr.mojo。示例二ConditionalTimer——带错误感知的__exit__()重载__exit__(self)处理“无错完成”的场景若想对with块中发生的Error做条件处理可额外实现一个带Error参数的重载它会在出错时替代无参版本被调用def __exit__(self, error: Error) raises - Bool返回值语义三选一返回True抑制该错误返回False重新抛出或直接抛出另一个新错误。conditional_context_mgr.mojo 演示“只抑制特定错误、其余照常传播”import std.time fieldwise_init struct ConditionalTimer(ImplicitlyCopyable): var start_time: Int def __init__(out self): self.start_time 0 def __enter__(mut self) - Self: self.start_time Int(time.perf_counter_ns()) return self def __exit__(mut self): var end_time time.perf_counter_ns() var elapsed_time_ms round( Float64(end_time - self.start_time) / 1e6, 3 ) print(Elapsed time:, elapsed_time_ms, milliseconds) def __exit__(mut self, e: Error) - Bool: if String(e) just a warning: print(Suppressing error:, e) self.__exit__() return True else: print(Propagating error) self.__exit__() return False def flaky_identity(n: Int) raises - Int: if (n % 4) 0: raise really bad elif (n % 2) 0: raise just a warning else: return n def main() raises: for i in range(1, 9): with ConditionalTimer(): print(\nBeginning execution) print(i , i) time.sleep(0.1) if i 3: print(continue executed) continue var j flaky_identity(i) print(j , j) print(Ending execution)运行输出Beginning execution i 1 j 1 Ending execution Elapsed time: 105.0 milliseconds Beginning execution i 2 Suppressing error: just a warning Elapsed time: 106.0 milliseconds Beginning execution i 3 continue executed Elapsed time: 106.0 milliseconds Beginning execution i 4 Propagating error Elapsed time: 106.0 milliseconds Unhandled exception caught during execution: really bad这段输出同时验证了三件事i 2时 just a warning 被抑制、循环继续i 3时continue正常触发无参__exit__()耗时照打i 4时 really bad 不被抑制__exit__()先打印耗时再让错误终止程序。配套单测在 test_conditional_context_mgr.mojo。示例三ResourceGuard——在__exit__()中处理类型化错误__exit__(self, error: Error)重载只能处理内置Error要处理类型化错误需实现带编译期错误类型参数的泛型版本def __exit__ErrType: AnyType - Bool该方法直接收到完整类型的错误值并可结合反射reflection在编译期检查错误类型reflect[ErrType].name()取类型名comptime if conforms_to(ErrType, Writable)判断是否可通过Writable接口访问错误消息。resource_guard.mojo 是完整可运行的实现from std.reflection import * fieldwise_init struct ConnectionError(Copyable, Writable): var message: String def write_to(self, mut writer: Some[Writer]): writer.write(ConnectionError: , self.message) struct ResourceGuard(ImplicitlyCopyable): var name: String var suppress_errors: Bool def __init__(out self, name: String, suppress_errors: Bool False): self.name name self.suppress_errors suppress_errors def __enter__(self) - Self: print(Acquiring:, self.name) return self def __exit__(self): print(Releasing:, self.name, (no error)) def __exit__ErrType: AnyType - Bool: comptime type_name reflect[ErrType].name() print(Releasing:, self.name) print( Error type:, type_name) comptime if conforms_to(ErrType, Writable): print( Message:, err) return self.suppress_errors该文件的main()覆盖三种路径无错误时调用__exit__(self)并打印 Releasing: database (no error)类型化错误未被抑制时由外层try/except捕获suppress_errorsTrue时__exit__[ErrType]返回True程序继续执行。关键输出Acquiring: cache Releasing: cache Error type: ConnectionError Message: ConnectionError: connection timed out Continued after suppressed errorBazel 构建与测试如何复现本目录的全部示例Mojo/docs/site/code/manual/errors/BUILD.bazel 为该目录建立了完整的可运行目标体系README 描述的三类目标当前文件里已全部落地且覆盖更多示例mojo_binary每个独立应用一个目标名称为去扩展名的文件名如handle_error、context_mgr、stacktrace_errordeps统一指向mojo//:stdmodular_run_binary_test把某个应用作为测试目标直接运行并断言其行为——handle_error_test运行handle_error不应有未处理错误stacktrace_error_capture_test验证无跟踪环境下程序优雅降级typed_errors_test、never_type_run_test、resource_guard_test等同理mojo_test单元测试目标将应用源文件与测试源文件一起编译、以测试文件为main——如handle_error_unit_testhandle_error.mojotest_handle_error.mojo、context_mgr_test、conditional_context_mgr_test、error_interaction_test、variant_errors_test等。从目标结构可以推断出该目录的测试分层思路modular_run_binary_test验证端到端行为程序输出与退出路径正确mojo_test验证单元级契约边界值、错误消息子串。BUILD.bazel 末尾还保留了一组标注 Retained Phase 1 files — unique test coverage not replicated by doc examples 的目标typed_errors_edge_cases、typed_errors_testing及对应测试即早期为覆盖文档示例未涵盖的边角行为而保留的补充测试。复现方式前提是本仓库已完成构建工具链准备在仓库根目录使用 Bazel 运行对应目标即可例如运行handle_error应用bazel run //Mojo/docs/site/code/manual/errors:handle_error或运行单元测试bazel test //Mojo/docs/site/code/manual/errors:handle_error_unit_test。小结这个目录的价值在于把 errors 章节手册 的每个论断都物化为可运行、可测试的代码Error作为值的轻量语义、try/except/else/finally的精确执行顺序含continue/break/return对else的跳过规则、Never的双向编译期保证、ErrorType参数化透传、MODULAR_DEBUGstack-trace-on-error与--debug-level full组合下的符号化跟踪以及从Timer到ConditionalTimer再到泛型ResourceGuard逐级递进的上下文管理器三件套。配合 BUILD.bazel 中的mojo_binary/modular_run_binary_test/mojo_test三层目标它是学习 Mojo 错误处理最权威的一手材料。【免费下载链接】mojoThe Modular Platform (includes MAX Mojo)项目地址: https://gitcode.com/GitHub_Trending/mo/mojo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考