[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fdocs":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fdocs":1138,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fdocs":1163},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":14,"pinned":15,"draft":15,"body":16,"seo":1134,"stem":1135,"id":1136,"extension":1137},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fdocs","第八章：测试、文档与质量","Rust 将测试和文档视为语言的一等公民。通过内置的测试框架，你可以在项目里编写单元测试、集成测试以及随文档一起运行的示例测试，三者共用 cargo test 命令。配合 cargo doc 生成文档，形成了一套确保代码质量与可维护性…","技能小册",[12,13],"rust","docs","2026-01-11",false,{"type":17,"value":18,"toc":1106},"minimark",[19,23,36,41,44,56,65,117,122,125,128,169,198,205,212,222,255,258,268,338,341,344,349,387,391,402,405,413,416,453,458,462,465,468,483,489,496,533,539,543,553,556,559,606,612,615,622,650,657,660,663,692,714,717,721,735,738,755,831,834,837,879,967,970,973,980,995,1015,1018,1025,1042,1045,1102],[20,21,8],"h1",{"id":22},"第八章测试文档与质量",[24,25,26,27,31,32,35],"p",{},"Rust 将测试和文档视为语言的一等公民。通过内置的测试框架，你可以在项目里编写单元测试、集成测试以及随文档一起运行的示例测试，三者共用 ",[28,29,30],"code",{},"cargo test"," 命令。配合 ",[28,33,34],{},"cargo doc"," 生成文档，形成了一套确保代码质量与可维护性的完整工作流。",[37,38,40],"h2",{"id":39},"_81-单元测试","8.1 单元测试",[24,42,43],{},"单元测试检验代码的局部功能，通常与被测试代码放在同一文件中，用条件编译隔离。",[45,46,48,51,52,55],"h3",{"id":47},"cfgtest-模块与-test-属性",[28,49,50],{},"#[cfg(test)]"," 模块与 ",[28,53,54],{},"#[test]"," 属性",[24,57,58,59,61,62,64],{},"单元测试通常放在源码文件底部、一个标有 ",[28,60,50],{}," 的模块里。这保证测试代码只在 ",[28,63,30],{}," 时编译，发布时完全排除。",[66,67,71],"pre",{"className":68,"code":69,"language":12,"meta":70,"style":70},"language-rust shiki shiki-themes material-theme-lighter github-light github-dark","#[cfg(test)]\nmod tests {\n    #[test]\n    fn it_works() {\n        assert_eq!(2 + 2, 4);\n    }\n}\n","",[28,72,73,81,87,93,99,105,111],{"__ignoreMap":70},[74,75,78],"span",{"class":76,"line":77},"line",1,[74,79,80],{},"#[cfg(test)]\n",[74,82,84],{"class":76,"line":83},2,[74,85,86],{},"mod tests {\n",[74,88,90],{"class":76,"line":89},3,[74,91,92],{},"    #[test]\n",[74,94,96],{"class":76,"line":95},4,[74,97,98],{},"    fn it_works() {\n",[74,100,102],{"class":76,"line":101},5,[74,103,104],{},"        assert_eq!(2 + 2, 4);\n",[74,106,108],{"class":76,"line":107},6,[74,109,110],{},"    }\n",[74,112,114],{"class":76,"line":113},7,[74,115,116],{},"}\n",[24,118,119,121],{},[28,120,54],{}," 属性标记测试函数。Cargo 会自动发现并运行所有带此属性的函数。",[45,123,124],{"id":124},"断言",[24,126,127],{},"Rust 提供多种断言宏来验证程序状态：",[129,130,131,145,161],"ul",{},[132,133,134,140,141,144],"li",{},[135,136,137],"strong",{},[28,138,139],{},"assert!(condition)","：断言条件为 ",[28,142,143],{},"true","，否则 panic。",[132,146,147,152,153,156,157,160],{},[135,148,149],{},[28,150,151],{},"assert_eq!(left, right)","：断言左右值相等（要求实现 ",[28,154,155],{},"PartialEq"," 和 ",[28,158,159],{},"Debug","，以便打印差异）。",[132,162,163,168],{},[135,164,165],{},[28,166,167],{},"assert_ne!(left, right)","：断言两个值不相等。",[66,170,172],{"className":68,"code":171,"language":12,"meta":70,"style":70},"#[test]\nfn test_add() {\n    assert_eq!(add(2, 3), 5);\n    assert!(add(1, -1) == 0);\n}\n",[28,173,174,179,184,189,194],{"__ignoreMap":70},[74,175,176],{"class":76,"line":77},[74,177,178],{},"#[test]\n",[74,180,181],{"class":76,"line":83},[74,182,183],{},"fn test_add() {\n",[74,185,186],{"class":76,"line":89},[74,187,188],{},"    assert_eq!(add(2, 3), 5);\n",[74,190,191],{"class":76,"line":95},[74,192,193],{},"    assert!(add(1, -1) == 0);\n",[74,195,196],{"class":76,"line":101},[74,197,116],{},[24,199,200,201,204],{},"断言失败时会自动打印出文件和行号，以及具体数值（对于 ",[28,202,203],{},"_eq"," 变体）。",[45,206,208,209],{"id":207},"期望-panicshould_panic","期望 panic：",[28,210,211],{},"#[should_panic]",[24,213,214,215,217,218,221],{},"当需要验证某段代码确实按预期 panic 时，使用 ",[28,216,211],{}," 属性。还可以添加 ",[28,219,220],{},"expected"," 参数，限定 panic 消息必须包含指定文本，避免因意外的 panic 而误判通过。",[66,223,225],{"className":68,"code":224,"language":12,"meta":70,"style":70},"#[test]\n#[should_panic(expected = \"index out of bounds\")]\nfn test_out_of_bounds() {\n    let v = vec![1, 2, 3];\n    let _ = v[99];\n}\n",[28,226,227,231,236,241,246,251],{"__ignoreMap":70},[74,228,229],{"class":76,"line":77},[74,230,178],{},[74,232,233],{"class":76,"line":83},[74,234,235],{},"#[should_panic(expected = \"index out of bounds\")]\n",[74,237,238],{"class":76,"line":89},[74,239,240],{},"fn test_out_of_bounds() {\n",[74,242,243],{"class":76,"line":95},[74,244,245],{},"    let v = vec![1, 2, 3];\n",[74,247,248],{"class":76,"line":101},[74,249,250],{},"    let _ = v[99];\n",[74,252,253],{"class":76,"line":107},[74,254,116],{},[45,256,257],{"id":257},"测试私有函数",[24,259,260,261,263,264,267],{},"因为 ",[28,262,50],{}," 模块可以访问其父模块（通过 ",[28,265,266],{},"super::","），所以能直接测试私有函数，无需破坏封装向外暴露接口。",[66,269,271],{"className":68,"code":270,"language":12,"meta":70,"style":70},"fn private_add(a: i32, b: i32) -> i32 {\n    a + b\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_private_add() {\n        assert_eq!(private_add(2, 3), 5);\n    }\n}\n",[28,272,273,278,283,287,293,297,301,306,311,316,322,328,333],{"__ignoreMap":70},[74,274,275],{"class":76,"line":77},[74,276,277],{},"fn private_add(a: i32, b: i32) -> i32 {\n",[74,279,280],{"class":76,"line":83},[74,281,282],{},"    a + b\n",[74,284,285],{"class":76,"line":89},[74,286,116],{},[74,288,289],{"class":76,"line":95},[74,290,292],{"emptyLinePlaceholder":291},true,"\n",[74,294,295],{"class":76,"line":101},[74,296,80],{},[74,298,299],{"class":76,"line":107},[74,300,86],{},[74,302,303],{"class":76,"line":113},[74,304,305],{},"    use super::*;\n",[74,307,309],{"class":76,"line":308},8,[74,310,292],{"emptyLinePlaceholder":291},[74,312,314],{"class":76,"line":313},9,[74,315,92],{},[74,317,319],{"class":76,"line":318},10,[74,320,321],{},"    fn test_private_add() {\n",[74,323,325],{"class":76,"line":324},11,[74,326,327],{},"        assert_eq!(private_add(2, 3), 5);\n",[74,329,331],{"class":76,"line":330},12,[74,332,110],{},[74,334,336],{"class":76,"line":335},13,[74,337,116],{},[24,339,340],{},"这是 Rust 提倡的“内部测试”风格：私有逻辑也可以充分覆盖。",[45,342,343],{"id":343},"控制测试执行",[24,345,346,348],{},[28,347,30],{}," 支持多种选项：",[129,350,351,361,367,377],{},[132,352,353,356,357,360],{},[28,354,355],{},"cargo test test_name"," 只运行名称中包含 ",[28,358,359],{},"test_name"," 的测试。",[132,362,363,366],{},[28,364,365],{},"cargo test -- --test-threads=1"," 单线程运行，避免并行干扰。",[132,368,369,372,373,376],{},[28,370,371],{},"cargo test -- --nocapture"," 显示被测试函数里的 ",[28,374,375],{},"println!"," 输出。",[132,378,379,382,383,386],{},[28,380,381],{},"cargo test -- --ignored"," 只运行被 ",[28,384,385],{},"#[ignore]"," 标记的测试。",[37,388,390],{"id":389},"_82-集成测试","8.2 集成测试",[24,392,393,394,397,398,401],{},"集成测试模拟外部使用者的场景，只测试公开 API。它们在项目根目录的 ",[28,395,396],{},"tests\u002F"," 目录中组织，每个 ",[28,399,400],{},".rs"," 文件被编译为一个独立的 crate。",[45,403,404],{"id":404},"目录结构",[66,406,411],{"className":407,"code":409,"language":410},[408],"language-text","my_project\u002F\n├── src\u002F\n│   └── lib.rs\n├── tests\u002F\n│   ├── integration_test.rs\n│   └── another_test.rs\n└── Cargo.toml\n","text",[28,412,409],{"__ignoreMap":70},[24,414,415],{},"每个测试文件都像是一个全新 crate，需要通过外部 crate 的方式引入被测库：",[66,417,419],{"className":68,"code":418,"language":12,"meta":70,"style":70},"\u002F\u002F tests\u002Fintegration_test.rs\nuse my_project;\n\n#[test]\nfn test_public_api() {\n    assert!(my_project::some_function(42));\n}\n",[28,420,421,426,431,435,439,444,449],{"__ignoreMap":70},[74,422,423],{"class":76,"line":77},[74,424,425],{},"\u002F\u002F tests\u002Fintegration_test.rs\n",[74,427,428],{"class":76,"line":83},[74,429,430],{},"use my_project;\n",[74,432,433],{"class":76,"line":89},[74,434,292],{"emptyLinePlaceholder":291},[74,436,437],{"class":76,"line":95},[74,438,178],{},[74,440,441],{"class":76,"line":101},[74,442,443],{},"fn test_public_api() {\n",[74,445,446],{"class":76,"line":107},[74,447,448],{},"    assert!(my_project::some_function(42));\n",[74,450,451],{"class":76,"line":113},[74,452,116],{},[24,454,455,457],{},[28,456,30],{}," 会运行单元测试、集成测试和文档测试，并分别报告三部分的结果。",[45,459,461],{"id":460},"只能测试公有-api","只能测试公有 API",[24,463,464],{},"集成测试文件独立于库 crate，不能直接访问私有模块或私有函数。这强迫开发者验证公开接口是否稳健可用。",[45,466,467],{"id":467},"公用工具函数",[24,469,470,471,474,475,478,479,482],{},"如果多个集成测试需要共享辅助函数，可以建立 ",[28,472,473],{},"tests\u002Fcommon\u002Fmod.rs","。Cargo 把 ",[28,476,477],{},"tests"," 目录下每个文件当作独立测试 crate，但 ",[28,480,481],{},"common"," 本身不是测试文件——只有作为模块被其他测试引用时，它才被编译。",[66,484,487],{"className":485,"code":486,"language":410},[408],"tests\u002F\n├── common\u002F\n│   └── mod.rs\n├── integration_test.rs\n",[28,488,486],{"__ignoreMap":70},[24,490,491,492,495],{},"在 ",[28,493,494],{},"integration_test.rs"," 中引用：",[66,497,499],{"className":68,"code":498,"language":12,"meta":70,"style":70},"mod common;\n\n#[test]\nfn test_with_setup() {\n    common::setup();\n    \u002F\u002F 进行测试\n}\n",[28,500,501,506,510,514,519,524,529],{"__ignoreMap":70},[74,502,503],{"class":76,"line":77},[74,504,505],{},"mod common;\n",[74,507,508],{"class":76,"line":83},[74,509,292],{"emptyLinePlaceholder":291},[74,511,512],{"class":76,"line":89},[74,513,178],{},[74,515,516],{"class":76,"line":95},[74,517,518],{},"fn test_with_setup() {\n",[74,520,521],{"class":76,"line":101},[74,522,523],{},"    common::setup();\n",[74,525,526],{"class":76,"line":107},[74,527,528],{},"    \u002F\u002F 进行测试\n",[74,530,531],{"class":76,"line":113},[74,532,116],{},[24,534,535,536,538],{},"这样 ",[28,537,481],{}," 不会作为测试单独运行，同时可以做好配置管理。",[37,540,542],{"id":541},"_83-文档测试","8.3 文档测试",[24,544,545,546,549,550,552],{},"Rust 的文档注释 ",[28,547,548],{},"\u002F\u002F\u002F"," 不仅能生成 HTML，其中的代码块还会被 ",[28,551,30],{}," 当作测试执行，确保示例代码长期有效、准确。",[45,554,555],{"id":555},"基本用法",[24,557,558],{},"在文档注释中写入 ``` 代码块，它们默认会被编译并运行：",[66,560,562],{"className":68,"code":561,"language":12,"meta":70,"style":70},"\u002F\u002F\u002F 将两个数相加。\n\u002F\u002F\u002F\n\u002F\u002F\u002F ```\n\u002F\u002F\u002F let result = my_crate::add(2, 3);\n\u002F\u002F\u002F assert_eq!(result, 5);\n\u002F\u002F\u002F ```\npub fn add(a: i32, b: i32) -> i32 {\n    a + b\n}\n",[28,563,564,569,574,579,584,589,593,598,602],{"__ignoreMap":70},[74,565,566],{"class":76,"line":77},[74,567,568],{},"\u002F\u002F\u002F 将两个数相加。\n",[74,570,571],{"class":76,"line":83},[74,572,573],{},"\u002F\u002F\u002F\n",[74,575,576],{"class":76,"line":89},[74,577,578],{},"\u002F\u002F\u002F ```\n",[74,580,581],{"class":76,"line":95},[74,582,583],{},"\u002F\u002F\u002F let result = my_crate::add(2, 3);\n",[74,585,586],{"class":76,"line":101},[74,587,588],{},"\u002F\u002F\u002F assert_eq!(result, 5);\n",[74,590,591],{"class":76,"line":107},[74,592,578],{},[74,594,595],{"class":76,"line":113},[74,596,597],{},"pub fn add(a: i32, b: i32) -> i32 {\n",[74,599,600],{"class":76,"line":308},[74,601,282],{},[74,603,604],{"class":76,"line":313},[74,605,116],{},[24,607,608,609,611],{},"运行 ",[28,610,30],{}," 时，会提取这些代码编译成独立测试并执行，断言失败则测试失败。",[45,613,614],{"id":614},"隐藏代码行",[24,616,617,618,621],{},"有时需要展示部分前置代码，但不希望它出现在文档中，可在行首添加 ",[28,619,620],{},"# ","：",[66,623,625],{"className":68,"code":624,"language":12,"meta":70,"style":70},"\u002F\u002F\u002F ```\n\u002F\u002F\u002F # use my_crate::prelude::*;\n\u002F\u002F\u002F # let conn = establish_connection();\n\u002F\u002F\u002F let users = conn.query(\"SELECT * FROM users\")?;\n\u002F\u002F\u002F ```\n",[28,626,627,631,636,641,646],{"__ignoreMap":70},[74,628,629],{"class":76,"line":77},[74,630,578],{},[74,632,633],{"class":76,"line":83},[74,634,635],{},"\u002F\u002F\u002F # use my_crate::prelude::*;\n",[74,637,638],{"class":76,"line":89},[74,639,640],{},"\u002F\u002F\u002F # let conn = establish_connection();\n",[74,642,643],{"class":76,"line":95},[74,644,645],{},"\u002F\u002F\u002F let users = conn.query(\"SELECT * FROM users\")?;\n",[74,647,648],{"class":76,"line":101},[74,649,578],{},[24,651,652,653,656],{},"前置的 ",[28,654,655],{},"#"," 行在文档渲染时被隐藏，但测试时仍会执行，保证代码完整性。",[45,658,659],{"id":659},"控制代码块行为",[24,661,662],{},"你可以通过属性控制某个代码块是否被编译或运行：",[129,664,665,671,677,686],{},[132,666,667,670],{},[135,668,669],{},"```ignore","：不编译该代码块（适用于无法通过编译的示例，但不推荐滥用）。",[132,672,673,676],{},[135,674,675],{},"```no_run","：编译但不运行（示例需要外部环境或会耗时）。",[132,678,679,682,683,685],{},[135,680,681],{},"```should_panic","：预期运行时 panic，与 ",[28,684,211],{}," 类似。",[132,687,688,691],{},[135,689,690],{},"```compile_fail","：预期编译失败（用于演示类型错误等）。",[66,693,695],{"className":68,"code":694,"language":12,"meta":70,"style":70},"\u002F\u002F\u002F ```compile_fail\n\u002F\u002F\u002F let x: i32 = \"hello\"; \u002F\u002F 编译错误演示\n\u002F\u002F\u002F ```\n",[28,696,697,702,710],{"__ignoreMap":70},[74,698,699],{"class":76,"line":77},[74,700,701],{},"\u002F\u002F\u002F ```compile_fail\n",[74,703,704,707],{"class":76,"line":83},[74,705,706],{},"\u002F\u002F\u002F let x: i32 = \"hello\";",[74,708,709],{}," \u002F\u002F 编译错误演示\n",[74,711,712],{"class":76,"line":89},[74,713,578],{},[24,715,716],{},"这些标记让文档示例能够灵活演示正确与错误用法。",[37,718,720],{"id":719},"_84-文档生成","8.4 文档生成",[24,722,723,724,727,728,730,731,734],{},"Rust 使用 ",[28,725,726],{},"rustdoc"," 工具从文档注释生成 HTML 网页。运行 ",[28,729,34],{}," 会为当前 crate 及所有依赖生成离线文档，放置在 ",[28,732,733],{},"target\u002Fdoc"," 目录。",[45,736,737],{"id":737},"文档注释语法",[129,739,740,747],{},[132,741,742,746],{},[135,743,744],{},[28,745,548],{},"：条目级注释，用于函数、结构体、模块等（Markdown 格式）。",[132,748,749,754],{},[135,750,751],{},[28,752,753],{},"\u002F\u002F!","：模块级注释，用于文件或模块的整体说明，写在模块最顶部。",[66,756,758],{"className":68,"code":757,"language":12,"meta":70,"style":70},"\u002F\u002F! # My Crate\n\u002F\u002F!\n\u002F\u002F! 提供高性能数学计算功能。\n\n\u002F\u002F\u002F 计算阶乘。\n\u002F\u002F\u002F\n\u002F\u002F\u002F # Examples\n\u002F\u002F\u002F\n\u002F\u002F\u002F ```\n\u002F\u002F\u002F let n = my_crate::factorial(5);\n\u002F\u002F\u002F assert_eq!(n, 120);\n\u002F\u002F\u002F ```\npub fn factorial(n: u32) -> u32 {\n    (2..=n).product()\n}\n",[28,759,760,765,770,775,779,784,788,793,797,801,806,811,815,820,826],{"__ignoreMap":70},[74,761,762],{"class":76,"line":77},[74,763,764],{},"\u002F\u002F! # My Crate\n",[74,766,767],{"class":76,"line":83},[74,768,769],{},"\u002F\u002F!\n",[74,771,772],{"class":76,"line":89},[74,773,774],{},"\u002F\u002F! 提供高性能数学计算功能。\n",[74,776,777],{"class":76,"line":95},[74,778,292],{"emptyLinePlaceholder":291},[74,780,781],{"class":76,"line":101},[74,782,783],{},"\u002F\u002F\u002F 计算阶乘。\n",[74,785,786],{"class":76,"line":107},[74,787,573],{},[74,789,790],{"class":76,"line":113},[74,791,792],{},"\u002F\u002F\u002F # Examples\n",[74,794,795],{"class":76,"line":308},[74,796,573],{},[74,798,799],{"class":76,"line":313},[74,800,578],{},[74,802,803],{"class":76,"line":318},[74,804,805],{},"\u002F\u002F\u002F let n = my_crate::factorial(5);\n",[74,807,808],{"class":76,"line":324},[74,809,810],{},"\u002F\u002F\u002F assert_eq!(n, 120);\n",[74,812,813],{"class":76,"line":330},[74,814,578],{},[74,816,817],{"class":76,"line":335},[74,818,819],{},"pub fn factorial(n: u32) -> u32 {\n",[74,821,823],{"class":76,"line":822},14,[74,824,825],{},"    (2..=n).product()\n",[74,827,829],{"class":76,"line":828},15,[74,830,116],{},[45,832,833],{"id":833},"常用文档章节",[24,835,836],{},"Rust 社区约定了一些标准章节，有助于文档的一致性：",[129,838,839,847,855,867],{},[132,840,841,846],{},[135,842,843],{},[28,844,845],{},"# Examples","：展示用法示例。",[132,848,849,854],{},[135,850,851],{},[28,852,853],{},"# Panics","：描述函数可能 panic 的条件。",[132,856,857,862,863,866],{},[135,858,859],{},[28,860,861],{},"# Errors","：如果返回 ",[28,864,865],{},"Result","，说明可能返回的错误种类。",[132,868,869,874,875,878],{},[135,870,871],{},[28,872,873],{},"# Safety","：对于 ",[28,876,877],{},"unsafe"," 函数，阐明调用者必须遵守的约束。",[66,880,882],{"className":68,"code":881,"language":12,"meta":70,"style":70},"\u002F\u002F\u002F 除以两个数。\n\u002F\u002F\u002F\n\u002F\u002F\u002F # Panics\n\u002F\u002F\u002F\n\u002F\u002F\u002F 如果除数为零，会 panic。\n\u002F\u002F\u002F\n\u002F\u002F\u002F # Examples\n\u002F\u002F\u002F\n\u002F\u002F\u002F ```\n\u002F\u002F\u002F let result = my_crate::div(10, 2);\n\u002F\u002F\u002F assert_eq!(result, 5);\n\u002F\u002F\u002F ```\npub fn div(a: i32, b: i32) -> i32 {\n    if b == 0 {\n        panic!(\"除数不能为零\");\n    }\n    a \u002F b\n}\n",[28,883,884,889,893,898,902,907,911,915,919,923,928,932,936,941,946,951,956,962],{"__ignoreMap":70},[74,885,886],{"class":76,"line":77},[74,887,888],{},"\u002F\u002F\u002F 除以两个数。\n",[74,890,891],{"class":76,"line":83},[74,892,573],{},[74,894,895],{"class":76,"line":89},[74,896,897],{},"\u002F\u002F\u002F # Panics\n",[74,899,900],{"class":76,"line":95},[74,901,573],{},[74,903,904],{"class":76,"line":101},[74,905,906],{},"\u002F\u002F\u002F 如果除数为零，会 panic。\n",[74,908,909],{"class":76,"line":107},[74,910,573],{},[74,912,913],{"class":76,"line":113},[74,914,792],{},[74,916,917],{"class":76,"line":308},[74,918,573],{},[74,920,921],{"class":76,"line":313},[74,922,578],{},[74,924,925],{"class":76,"line":318},[74,926,927],{},"\u002F\u002F\u002F let result = my_crate::div(10, 2);\n",[74,929,930],{"class":76,"line":324},[74,931,588],{},[74,933,934],{"class":76,"line":330},[74,935,578],{},[74,937,938],{"class":76,"line":335},[74,939,940],{},"pub fn div(a: i32, b: i32) -> i32 {\n",[74,942,943],{"class":76,"line":822},[74,944,945],{},"    if b == 0 {\n",[74,947,948],{"class":76,"line":828},[74,949,950],{},"        panic!(\"除数不能为零\");\n",[74,952,954],{"class":76,"line":953},16,[74,955,110],{},[74,957,959],{"class":76,"line":958},17,[74,960,961],{},"    a \u002F b\n",[74,963,965],{"class":76,"line":964},18,[74,966,116],{},[24,968,969],{},"使用这些章节可帮助读者快速查找所需信息。",[45,971,972],{"id":972},"隐藏条目与链接",[24,974,975,976,979],{},"有时你希望某个条目在文档中被隐藏，不暴露给用户，可使用 ",[28,977,978],{},"#[doc(hidden)]"," 属性：",[66,981,983],{"className":68,"code":982,"language":12,"meta":70,"style":70},"#[doc(hidden)]\npub fn internal_api() { }\n",[28,984,985,990],{"__ignoreMap":70},[74,986,987],{"class":76,"line":77},[74,988,989],{},"#[doc(hidden)]\n",[74,991,992],{"class":76,"line":83},[74,993,994],{},"pub fn internal_api() { }\n",[24,996,997,998,1001,1002,1005,1006,410,1008,1011,1012,1014],{},"文档注释中还支持 Markdown 链接语法，可以链接到其他类型或模块，如 ",[28,999,1000],{},"[","MyStruct",[28,1003,1004],{},"]"," 自动解析为本 crate 中的类型，或使用 ",[28,1007,1000],{},[28,1009,1010],{},"][","path::to::item",[28,1013,1004],{}," 精确跳转。",[45,1016,1017],{"id":1017},"浏览生成的文档",[24,1019,1020,1021,1024],{},"执行 ",[28,1022,1023],{},"cargo doc --open"," 会生成文档并直接在浏览器中打开首页。所有依赖的文档也会被生成，形成一个完整的可搜索知识库。",[24,1026,1027,1028,1030,1031,1036,1037,1041],{},"通过单元测试保证内部逻辑正确，集成测试验证公开 API 的可用性，文档测试让代码示例永久保鲜，再配合 ",[28,1029,34],{}," 自动生成的精美文档，Rust 的质量保障体系在每个环节都提供坚实支持。接下来请阅读 ",[1032,1033,1035],"a",{"href":1034},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fasync","并发与异步"," 与 ",[1032,1038,1040],{"href":1039},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fother","进阶特性","。",[37,1043,1044],{"id":1044},"参考文献",[1046,1047,1048,1061],"table",{},[1049,1050,1051],"thead",{},[1052,1053,1054,1058],"tr",{},[1055,1056,1057],"th",{},"资料",[1055,1059,1060],{},"说明",[1062,1063,1064,1078,1091],"tbody",{},[1052,1065,1066,1075],{},[1067,1068,1069],"td",{},[1032,1070,1074],{"href":1071,"rel":1072},"https:\u002F\u002Fdoc.rust-lang.org\u002Fbook\u002Fch11-00-testing.html",[1073],"nofollow","Testing",[1067,1076,1077],{},"官方书第 11 章",[1052,1079,1080,1087],{},[1067,1081,1082],{},[1032,1083,1086],{"href":1084,"rel":1085},"https:\u002F\u002Fdoc.rust-lang.org\u002Fbook\u002Fch14-00-more-about-cargo.html",[1073],"Documentation",[1067,1088,1089],{},[28,1090,34],{},[1052,1092,1093,1099],{},[1067,1094,1095],{},[1032,1096,726],{"href":1097,"rel":1098},"https:\u002F\u002Fdoc.rust-lang.org\u002Frustdoc\u002F",[1073],[1067,1100,1101],{},"文档生成工具",[1103,1104,1105],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":70,"searchDepth":83,"depth":83,"links":1107},[1108,1117,1122,1127,1133],{"id":39,"depth":83,"text":40,"children":1109},[1110,1112,1113,1115,1116],{"id":47,"depth":89,"text":1111},"#[cfg(test)] 模块与 #[test] 属性",{"id":124,"depth":89,"text":124},{"id":207,"depth":89,"text":1114},"期望 panic：#[should_panic]",{"id":257,"depth":89,"text":257},{"id":343,"depth":89,"text":343},{"id":389,"depth":83,"text":390,"children":1118},[1119,1120,1121],{"id":404,"depth":89,"text":404},{"id":460,"depth":89,"text":461},{"id":467,"depth":89,"text":467},{"id":541,"depth":83,"text":542,"children":1123},[1124,1125,1126],{"id":555,"depth":89,"text":555},{"id":614,"depth":89,"text":614},{"id":659,"depth":89,"text":659},{"id":719,"depth":83,"text":720,"children":1128},[1129,1130,1131,1132],{"id":737,"depth":89,"text":737},{"id":833,"depth":89,"text":833},{"id":972,"depth":89,"text":972},{"id":1017,"depth":89,"text":1017},{"id":1044,"depth":83,"text":1044},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fend\u002FRust\u002Fdocs","knowledge\u002Fknowledge\u002Fbooklet\u002Fend\u002FRust\u002Fdocs.md","md",{"items":1139},[1140,1144,1148,1152,1155,1159],{"path":1141,"title":1142,"description":1143,"category":10,"score":107},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Ft","泛型与 Trait","泛型和 trait 是 Rust 实现代码复用与多态的两大支柱。前置：Rust 基础。泛型让代码可以工作在多种类型上而不牺牲性能，trait 定义了类型间的共享行为，二者结合形成了零成本抽象的强大表达能力。本章将深入泛型定义、trai…",{"path":1145,"title":1146,"description":1147,"category":10,"score":107},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Ftype","第二章：基础语法与类型","Rust 的类型系统和语法设计处处体现着“安全”与“显式”的理念。这一章你将掌握变量绑定、基本类型、复合类型、函数定义以及所有基础控制流结构，它们是你写出任何 Rust 程序的基石。",{"path":1149,"title":1150,"description":1151,"category":10,"score":107},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fpackage","第七章：模块系统与包管理","Rust 的模块系统为代码组织、封装和复用提供了一套严谨但灵活的机制。包、crate、模块以及 use 路径相互配合，让你能够把项目拆解成清晰的功能单元，同时精确控制哪些对外可见。本章将带你系统掌握这些构建大型 Rust 项目所必需的…",{"path":1039,"title":1153,"description":1154,"category":10,"score":107},"第十章：进阶特性与模式","Rust 的核心安全保证覆盖了绝大多数日常编程场景。但当你需要打破常规——无论是编写极致通用的抽象、与 C 库交互，还是内联优化——本章将带你进入 Rust 的深层能力：声明宏与过程宏、unsafe 的超能力与封装、高级类型系统技巧…",{"path":1156,"title":1157,"description":1158,"category":10,"score":107},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Ferror","第五章：错误处理","Rust 将错误明确分为两类：不可恢复的错误与可恢复的错误。通过 panic! 处理前一种，Result 处理后一种，这让程序的错误路径不再是隐式的控制流，而是强类型、必须处理的代码分支。配合 Option 对缺失值的处理以及丰富的组…",{"path":1160,"title":1161,"description":1162,"category":10,"score":107},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fcore","第三章：所有权、借用与生命周期（核心）","所有权系统是 Rust 最独特、最核心的语言特性。它让 Rust 无需垃圾回收器就能保证内存安全，并在编译期消除数据竞争。本章你将深入理解所有权如何运转、引用和借用如何被检查、生命周期如何标注，以及常见智能指针如何扩展所有权模型。",{"series":1164,"title":12,"items":1165,"index":95,"prev":1190,"next":1191},"booklet\u002Fend\u002Frust",[1166,1169,1173,1175,1179,1180,1182,1184,1186,1188],{"path":1034,"title":1167,"date":1168,"pinned":15},"第九章：并发与异步","2020-05-22",{"path":1170,"title":1171,"date":1172,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fbase","Rust 基础","2020-07-21",{"path":1160,"title":1161,"date":1174,"pinned":15},"2023-05-09",{"path":1176,"title":1177,"date":1178,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fdata-type","第四章：复合数据类型","2021-02-24",{"path":7,"title":8,"date":14,"pinned":15},{"path":1156,"title":1157,"date":1181,"pinned":15},"2023-11-03",{"path":1039,"title":1153,"date":1183,"pinned":15},"2023-12-29",{"path":1149,"title":1150,"date":1185,"pinned":15},"2024-05-26",{"path":1141,"title":1142,"date":1187,"pinned":15},"2024-10-31",{"path":1145,"title":1146,"date":1189,"pinned":15},"2024-08-31",{"path":1176,"title":1177,"date":1178,"pinned":15},{"path":1156,"title":1157,"date":1181,"pinned":15}]