[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fcore":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fcore":1216,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fcore":1242},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":13,"pinned":14,"draft":14,"body":15,"seo":1212,"stem":1213,"id":1214,"extension":1215},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fcore","第三章：所有权、借用与生命周期（核心）","所有权系统是 Rust 最独特、最核心的语言特性。它让 Rust 无需垃圾回收器就能保证内存安全，并在编译期消除数据竞争。本章你将深入理解所有权如何运转、引用和借用如何被检查、生命周期如何标注，以及常见智能指针如何扩展所有权模型。","技能小册",[12],"rust","2023-05-09",false,{"type":16,"value":17,"toc":1169},"minimark",[18,22,25,30,34,37,60,64,71,102,105,134,137,141,157,177,185,200,214,218,224,248,251,254,257,301,304,308,318,325,332,357,364,371,398,401,409,413,420,456,459,462,465,469,472,475,489,504,507,510,513,532,549,552,555,585,588,591,594,613,624,631,639,648,654,661,677,696,700,703,722,728,732,735,742,747,758,761,795,806,813,826,856,862,869,877,917,924,943,968,975,984,1028,1035,1046,1088,1098,1106,1109,1165],[19,20,8],"h1",{"id":21},"第三章所有权借用与生命周期核心",[23,24,9],"p",{},[26,27,29],"h2",{"id":28},"_31-所有权ownership","3.1 所有权（Ownership）",[31,32,33],"h3",{"id":33},"所有权规则",[23,35,36],{},"Rust 的所有权系统遵循三条铁律：",[38,39,40,49,57],"ol",{},[41,42,43,44,48],"li",{},"Rust 中每一个值都有且仅有一个",[45,46,47],"strong",{},"所有者","。",[41,50,51,52,56],{},"当所有者离开作用域，值会被自动释放（调用 ",[53,54,55],"code",{},"drop","）。",[41,58,59],{},"所有权可以在变量之间转移（移动），转移后原变量失效。",[31,61,63],{"id":62},"移动move","移动（move）",[23,65,66,67,70],{},"在 Rust 中，赋值、传参、返回值默认都是",[45,68,69],{},"移动","语义：所有权从一个绑定转移到另一个绑定。原变量不能再被使用。",[72,73,77],"pre",{"className":74,"code":75,"language":12,"meta":76,"style":76},"language-rust shiki shiki-themes material-theme-lighter github-light github-dark","let s1 = String::from(\"hello\");\nlet s2 = s1;             \u002F\u002F s1 的所有权移动到 s2\n\u002F\u002F println!(\"{s1}\");     \u002F\u002F 编译错误：s1 已失效\n","",[53,78,79,87,93],{"__ignoreMap":76},[80,81,84],"span",{"class":82,"line":83},"line",1,[80,85,86],{},"let s1 = String::from(\"hello\");\n",[80,88,90],{"class":82,"line":89},2,[80,91,92],{},"let s2 = s1;             \u002F\u002F s1 的所有权移动到 s2\n",[80,94,96,99],{"class":82,"line":95},3,[80,97,98],{},"\u002F\u002F println!(\"{s1}\");",[80,100,101],{},"     \u002F\u002F 编译错误：s1 已失效\n",[23,103,104],{},"传参与返回也会发生移动：",[72,106,108],{"className":74,"code":107,"language":12,"meta":76,"style":76},"fn take(s: String) { }   \u002F\u002F 接收所有权\nlet s = String::from(\"hi\");\ntake(s);                 \u002F\u002F s 被移动\n\u002F\u002F println!(\"{s}\");      \u002F\u002F 错误\n",[53,109,110,115,120,125],{"__ignoreMap":76},[80,111,112],{"class":82,"line":83},[80,113,114],{},"fn take(s: String) { }   \u002F\u002F 接收所有权\n",[80,116,117],{"class":82,"line":89},[80,118,119],{},"let s = String::from(\"hi\");\n",[80,121,122],{"class":82,"line":95},[80,123,124],{},"take(s);                 \u002F\u002F s 被移动\n",[80,126,128,131],{"class":82,"line":127},4,[80,129,130],{},"\u002F\u002F println!(\"{s}\");",[80,132,133],{},"      \u002F\u002F 错误\n",[23,135,136],{},"函数返回一个值时，所有权也会移交给调用方。",[31,138,140],{"id":139},"copy-与-clone","Copy 与 Clone",[23,142,143,144,147,148,151,152,154,155,48],{},"有些类型在赋值时不会移动，而是执行",[45,145,146],{},"按位复制","。这个行为由 ",[53,149,150],{},"Copy"," trait 标记。实现了 ",[53,153,150],{}," 的类型在重新赋值后，原变量仍然可用。标量类型（整数、浮点、布尔、字符）以及由 Copy 类型组成的元组和数组都实现了 ",[53,156,150],{},[72,158,160],{"className":74,"code":159,"language":12,"meta":76,"style":76},"let x = 5;\nlet y = x;        \u002F\u002F x 被复制，依然有效\nprintln!(\"{x}\");  \u002F\u002F 正常\n",[53,161,162,167,172],{"__ignoreMap":76},[80,163,164],{"class":82,"line":83},[80,165,166],{},"let x = 5;\n",[80,168,169],{"class":82,"line":89},[80,170,171],{},"let y = x;        \u002F\u002F x 被复制，依然有效\n",[80,173,174],{"class":82,"line":95},[80,175,176],{},"println!(\"{x}\");  \u002F\u002F 正常\n",[23,178,179,181,182,184],{},[53,180,150],{}," 是一个隐式的、栈上的按位复制，不能重写，且要求类型中所有成员都是 ",[53,183,150],{}," 的。",[23,186,187,188,191,192,195,196,199],{},"与之相对的，",[53,189,190],{},"Clone"," 是一个显式调用的方法，用于深拷贝堆数据等。对于 ",[53,193,194],{},"String"," 这类拥有堆数据的类型，必须显式调用 ",[53,197,198],{},".clone()"," 来创建副本，而不是隐式复制。",[72,201,203],{"className":74,"code":202,"language":12,"meta":76,"style":76},"let s1 = String::from(\"hello\");\nlet s2 = s1.clone();   \u002F\u002F 深拷贝，s1 仍有效\n",[53,204,205,209],{"__ignoreMap":76},[80,206,207],{"class":82,"line":83},[80,208,86],{},[80,210,211],{"class":82,"line":89},[80,212,213],{},"let s2 = s1.clone();   \u002F\u002F 深拷贝，s1 仍有效\n",[31,215,217],{"id":216},"栈数据-vs-堆数据","栈数据 vs 堆数据",[23,219,220,221,223],{},"为什么 ",[53,222,194],{}," 会移动而整数会复制？根本原因在于它们在内存中的存储方式：",[225,226,227,230],"ul",{},[41,228,229],{},"整数等数据完全存储在栈上，按位复制成本极低。",[41,231,232,234,235,237,238,241,242,244,245,247],{},[53,233,194],{}," 内部由指针、长度和容量组成，但实际字符串内容在堆上。如果按位复制，会出现两个 ",[53,236,194],{}," 指向同一块堆内存，离开作用域时会引发",[45,239,240],{},"二次释放","。因此 ",[53,243,194],{}," 不实现 ",[53,246,150],{},"，赋值就是移动。",[23,249,250],{},"Rust 通过所有权和移动语义从根本上杜绝了这种问题。",[31,252,253],{"id":253},"常见所有权转移场景",[23,255,256],{},"所有权转移不仅发生在显式赋值中，也会隐含在各种流程里：",[72,258,260],{"className":74,"code":259,"language":12,"meta":76,"style":76},"let s = String::from(\"text\");\nlet v = vec![s];           \u002F\u002F s 移动到 v 中\n\nfor item in v {            \u002F\u002F 遍历会消耗 v 本身（非引用迭代）\n    println!(\"{item}\");\n}\n\u002F\u002F 此处 v 已不可用\n",[53,261,262,267,272,278,283,289,295],{"__ignoreMap":76},[80,263,264],{"class":82,"line":83},[80,265,266],{},"let s = String::from(\"text\");\n",[80,268,269],{"class":82,"line":89},[80,270,271],{},"let v = vec![s];           \u002F\u002F s 移动到 v 中\n",[80,273,274],{"class":82,"line":95},[80,275,277],{"emptyLinePlaceholder":276},true,"\n",[80,279,280],{"class":82,"line":127},[80,281,282],{},"for item in v {            \u002F\u002F 遍历会消耗 v 本身（非引用迭代）\n",[80,284,286],{"class":82,"line":285},5,[80,287,288],{},"    println!(\"{item}\");\n",[80,290,292],{"class":82,"line":291},6,[80,293,294],{},"}\n",[80,296,298],{"class":82,"line":297},7,[80,299,300],{},"\u002F\u002F 此处 v 已不可用\n",[23,302,303],{},"理解所有权的流动是阅读和编写 Rust 代码的基础。",[26,305,307],{"id":306},"_32-引用与借用","3.2 引用与借用",[23,309,310,311,314,315,48],{},"如果每次使用一个值都要转移所有权，程序会变得极其繁琐。Rust 提供了",[45,312,313],{},"引用","（reference），允许在不获取所有权的情况下使用数据，这就是",[45,316,317],{},"借用",[31,319,321,322],{"id":320},"共享引用-t","共享引用 ",[53,323,324],{},"&T",[23,326,327,328,331],{},"共享引用允许多个变量同时借用同一个值，但只能读取，不能修改。用 ",[53,329,330],{},"&"," 创建。",[72,333,335],{"className":74,"code":334,"language":12,"meta":76,"style":76},"let s = String::from(\"hello\");\nlet r1 = &s;\nlet r2 = &s;\nprintln!(\"{r1} and {r2}\");  \u002F\u002F 多个共享引用可以共存\n",[53,336,337,342,347,352],{"__ignoreMap":76},[80,338,339],{"class":82,"line":83},[80,340,341],{},"let s = String::from(\"hello\");\n",[80,343,344],{"class":82,"line":89},[80,345,346],{},"let r1 = &s;\n",[80,348,349],{"class":82,"line":95},[80,350,351],{},"let r2 = &s;\n",[80,353,354],{"class":82,"line":127},[80,355,356],{},"println!(\"{r1} and {r2}\");  \u002F\u002F 多个共享引用可以共存\n",[31,358,360,361],{"id":359},"可变引用-mut-t","可变引用 ",[53,362,363],{},"&mut T",[23,365,366,367,370],{},"可变引用允许修改被借用的数据，但只能存在一个可变引用，且在它的作用域内",[45,368,369],{},"不能有任何其他引用","（无论共享还是可变）。这是为了在编译期消除数据竞争。",[72,372,374],{"className":74,"code":373,"language":12,"meta":76,"style":76},"let mut s = String::from(\"hello\");\nlet r = &mut s;\nr.push_str(\" world\");\n\u002F\u002F println!(\"{s}\");       \u002F\u002F 错误，r 借用期间不可用 s\n",[53,375,376,381,386,391],{"__ignoreMap":76},[80,377,378],{"class":82,"line":83},[80,379,380],{},"let mut s = String::from(\"hello\");\n",[80,382,383],{"class":82,"line":89},[80,384,385],{},"let r = &mut s;\n",[80,387,388],{"class":82,"line":95},[80,389,390],{},"r.push_str(\" world\");\n",[80,392,393,395],{"class":82,"line":127},[80,394,130],{},[80,396,397],{},"       \u002F\u002F 错误，r 借用期间不可用 s\n",[23,399,400],{},"规则：在任意给定时间，你只能拥有以下两种引用之一，但不能同时拥有：",[225,402,403,406],{},[41,404,405],{},"任意数量的不可变引用",[41,407,408],{},"恰好一个可变引用",[31,410,412],{"id":411},"借用检查器与-nll","借用检查器与 NLL",[23,414,415,416,419],{},"Rust 的借用检查器在编译期严格检查这些规则，确保引用永远不会悬垂（指向已被释放的内存）。同时，得益于",[45,417,418],{},"非词法作用域生命周期（NLL）","，引用的有效期并不是简单地到所在代码块末尾，而是到它最后一次被使用的位置。这使得很多以往无法编译的代码变得合法：",[72,421,423],{"className":74,"code":422,"language":12,"meta":76,"style":76},"let mut s = String::from(\"hello\");\nlet r1 = &s;\nlet r2 = &s;\nprintln!(\"{r1} {r2}\");  \u002F\u002F 共享引用最后一次使用\n\nlet r3 = &mut s;        \u002F\u002F r1,r2 已不再使用，此处可变引用合法\nr3.push_str(\" world\");\n",[53,424,425,429,433,437,442,446,451],{"__ignoreMap":76},[80,426,427],{"class":82,"line":83},[80,428,380],{},[80,430,431],{"class":82,"line":89},[80,432,346],{},[80,434,435],{"class":82,"line":95},[80,436,351],{},[80,438,439],{"class":82,"line":127},[80,440,441],{},"println!(\"{r1} {r2}\");  \u002F\u002F 共享引用最后一次使用\n",[80,443,444],{"class":82,"line":285},[80,445,277],{"emptyLinePlaceholder":276},[80,447,448],{"class":82,"line":291},[80,449,450],{},"let r3 = &mut s;        \u002F\u002F r1,r2 已不再使用，此处可变引用合法\n",[80,452,453],{"class":82,"line":297},[80,454,455],{},"r3.push_str(\" world\");\n",[23,457,458],{},"NLL 让借用检查更聪明，减少了不必要的限制。",[31,460,461],{"id":461},"引用的作用域规则",[23,463,464],{},"引用的生命周期必须短于被引用值的生命周期。这自然导出下一节的生命周期概念。",[26,466,468],{"id":467},"_33-生命周期lifetime","3.3 生命周期（Lifetime）",[23,470,471],{},"生命周期是编译器用来确保所有引用都有效的泛型参数。大多数情况下，生命周期是隐式推导的，但编译器需要你显式标注引用之间的关系时，你就必须写出来。",[31,473,474],{"id":474},"生命周期标注语法",[23,476,477,478,481,482,485,486,488],{},"生命周期标注以单引号开头，通常使用 ",[53,479,480],{},"'a","、",[53,483,484],{},"'b"," 等小写字母。它们标注在引用的 ",[53,487,330],{}," 符号之后：",[72,490,492],{"className":74,"code":491,"language":12,"meta":76,"style":76},"&'a i32      \u002F\u002F 拥有生命周期 'a 的 i32 引用\n&'a mut i32  \u002F\u002F 拥有生命周期 'a 的可变 i32 引用\n",[53,493,494,499],{"__ignoreMap":76},[80,495,496],{"class":82,"line":83},[80,497,498],{},"&'a i32      \u002F\u002F 拥有生命周期 'a 的 i32 引用\n",[80,500,501],{"class":82,"line":89},[80,502,503],{},"&'a mut i32  \u002F\u002F 拥有生命周期 'a 的可变 i32 引用\n",[23,505,506],{},"标注本身并不改变引用的实际存活时间，而是告诉编译器多个引用之间的存活关系。",[31,508,509],{"id":509},"函数中的生命周期标注",[23,511,512],{},"当函数接收多个引用作为参数并返回一个引用时，编译器必须知道返回的引用与哪个参数的生命周期相关联。此时就需要显式标注：",[72,514,516],{"className":74,"code":515,"language":12,"meta":76,"style":76},"fn longest\u003C'a>(x: &'a str, y: &'a str) -> &'a str {\n    if x.len() > y.len() { x } else { y }\n}\n",[53,517,518,523,528],{"__ignoreMap":76},[80,519,520],{"class":82,"line":83},[80,521,522],{},"fn longest\u003C'a>(x: &'a str, y: &'a str) -> &'a str {\n",[80,524,525],{"class":82,"line":89},[80,526,527],{},"    if x.len() > y.len() { x } else { y }\n",[80,529,530],{"class":82,"line":95},[80,531,294],{},[23,533,534,535,538,539,481,542,545,546,548],{},"这里 ",[53,536,537],{},"\u003C'a>"," 声明了一个生命周期泛型参数，并约束了参数 ",[53,540,541],{},"x",[53,543,544],{},"y"," 和返回值的生命周期都是 ",[53,547,480],{},"，即：返回值至少与两个参数中较短的那一个活得一样长。",[31,550,551],{"id":551},"生命周期省略规则",[23,553,554],{},"Rust 编译器在函数签名中可以自动推导生命周期，遵循三条规则：",[38,556,557,567,570],{},[41,558,559,560,563,564,56],{},"每个引用参数都有各自的生命周期（例如 ",[53,561,562],{},"fn foo(x: &i32)"," 展开为 ",[53,565,566],{},"fn foo\u003C'a>(x: &'a i32)",[41,568,569],{},"如果只有一个输入生命周期参数，那么输出生命周期被赋予该参数。",[41,571,572,573,576,577,580,581,584],{},"如果有多个输入生命周期参数，但其中一个是 ",[53,574,575],{},"&self"," 或 ",[53,578,579],{},"&mut self","（方法），则输出的生命周期被赋予 ",[53,582,583],{},"self"," 的生命周期。",[23,586,587],{},"如果这三条规则无法推导出所有引用类型的生命周期，编译器就会报错，要求你手动标注。",[31,589,590],{"id":590},"结构体中的生命周期",[23,592,593],{},"当结构体持有引用时，必须标注生命周期参数，以保证该引用在结构体有效期间始终有效：",[72,595,597],{"className":74,"code":596,"language":12,"meta":76,"style":76},"struct Excerpt\u003C'a> {\n    part: &'a str,\n}\n",[53,598,599,604,609],{"__ignoreMap":76},[80,600,601],{"class":82,"line":83},[80,602,603],{},"struct Excerpt\u003C'a> {\n",[80,605,606],{"class":82,"line":89},[80,607,608],{},"    part: &'a str,\n",[80,610,611],{"class":82,"line":95},[80,612,294],{},[23,614,615,616,619,620,623],{},"这表示 ",[53,617,618],{},"Excerpt"," 实例不能比它持有的 ",[53,621,622],{},"part"," 引用活得更久。",[31,625,627,628],{"id":626},"静态生命周期-static","静态生命周期 ",[53,629,630],{},"'static",[23,632,633,635,636,638],{},[53,634,630],{}," 是一个特殊的生命周期，表示这个引用在整个程序运行期间都有效。所有字符串字面量都拥有 ",[53,637,630],{}," 生命周期：",[72,640,642],{"className":74,"code":641,"language":12,"meta":76,"style":76},"let s: &'static str = \"I am static\";\n",[53,643,644],{"__ignoreMap":76},[80,645,646],{"class":82,"line":83},[80,647,641],{},[23,649,650,651,653],{},"但需要警惕：不要轻易对普通数据标注 ",[53,652,630],{},"，大多数情况下应该由编译器推断或限制为较短的生命周期。",[31,655,657,658],{"id":656},"生命周期界限-t-a","生命周期界限 ",[53,659,660],{},"T: 'a",[23,662,663,664,667,668,670,671,673,674,676],{},"当泛型类型 ",[53,665,666],{},"T"," 包含引用时，我们可以用生命周期界限约束它。",[53,669,660],{}," 表示 ",[53,672,666],{}," 类型中的所有引用都必须活得至少和 ",[53,675,480],{}," 一样长。这通常用于结构体同时持有引用和泛型数据：",[72,678,680],{"className":74,"code":679,"language":12,"meta":76,"style":76},"struct RefHolder\u003C'a, T: 'a> {\n    data: &'a T,\n}\n",[53,681,682,687,692],{"__ignoreMap":76},[80,683,684],{"class":82,"line":83},[80,685,686],{},"struct RefHolder\u003C'a, T: 'a> {\n",[80,688,689],{"class":82,"line":89},[80,690,691],{},"    data: &'a T,\n",[80,693,694],{"class":82,"line":95},[80,695,294],{},[31,697,699],{"id":698},"实际应用多引用关系的标注","实际应用：多引用关系的标注",[23,701,702],{},"实际中，你可能需要标注更复杂的关系，例如：",[72,704,706],{"className":74,"code":705,"language":12,"meta":76,"style":76},"fn select\u003C'a, 'b>(first: &'a str, second: &'b str, flag: bool) -> &'a str {\n    if flag { first } else { first } \u002F\u002F 只返回 first\n}\n",[53,707,708,713,718],{"__ignoreMap":76},[80,709,710],{"class":82,"line":83},[80,711,712],{},"fn select\u003C'a, 'b>(first: &'a str, second: &'b str, flag: bool) -> &'a str {\n",[80,714,715],{"class":82,"line":89},[80,716,717],{},"    if flag { first } else { first } \u002F\u002F 只返回 first\n",[80,719,720],{"class":82,"line":95},[80,721,294],{},[23,723,724,725,727],{},"这里返回值只依赖于 ",[53,726,480],{},"，所以不需要将两个参数绑定到同一生命周期。理解这种关系能让你写出更精确的 API。",[26,729,731],{"id":730},"_34-智能指针初步","3.4 智能指针初步",[23,733,734],{},"智能指针是行为类似指针，但拥有额外元数据和功能的结构体。Rust 标准库提供了多个重要的智能指针，它们扩展了所有权模型，让你能在安全的边界内完成更复杂的内存管理。",[31,736,738,741],{"id":737},"boxt堆分配单一所有权",[53,739,740],{},"Box\u003CT>","：堆分配，单一所有权",[23,743,744,746],{},[53,745,740],{}," 让你将值分配在堆上，自身保留了唯一的所有权。它常用于以下场景：",[225,748,749,752,755],{},[41,750,751],{},"类型大小在编译期无法确定，如递归类型",[41,753,754],{},"传输大量数据时希望避免拷贝",[41,756,757],{},"拥有一个实现了 trait 的对象",[23,759,760],{},"经典例子是递归定义的链表节点：",[72,762,764],{"className":74,"code":763,"language":12,"meta":76,"style":76},"enum List {\n    Cons(i32, Box\u003CList>),\n    Nil,\n}\nuse List::{Cons, Nil};\nlet list = Cons(1, Box::new(Cons(2, Box::new(Nil))));\n",[53,765,766,771,776,781,785,790],{"__ignoreMap":76},[80,767,768],{"class":82,"line":83},[80,769,770],{},"enum List {\n",[80,772,773],{"class":82,"line":89},[80,774,775],{},"    Cons(i32, Box\u003CList>),\n",[80,777,778],{"class":82,"line":95},[80,779,780],{},"    Nil,\n",[80,782,783],{"class":82,"line":127},[80,784,294],{},[80,786,787],{"class":82,"line":285},[80,788,789],{},"use List::{Cons, Nil};\n",[80,791,792],{"class":82,"line":291},[80,793,794],{},"let list = Cons(1, Box::new(Cons(2, Box::new(Nil))));\n",[23,796,797,798,801,802,805],{},"没有 ",[53,799,800],{},"Box","，",[53,803,804],{},"List"," 类型的大小将是无穷大，编译器无法确定。",[31,807,809,812],{"id":808},"rct引用计数单线程共享所有权",[53,810,811],{},"Rc\u003CT>","：引用计数，单线程共享所有权",[23,814,815,817,818,821,822,825],{},[53,816,811],{},"（Reference Counted）允许一个值拥有多个所有者，在单线程环境下通过不可变引用共享数据。每次调用 ",[53,819,820],{},"Rc::clone"," 都会增加引用计数，当最后一个 ",[53,823,824],{},"Rc"," 离开作用域时，数据被释放。",[72,827,829],{"className":74,"code":828,"language":12,"meta":76,"style":76},"use std::rc::Rc;\nlet a = Rc::new(String::from(\"shared\"));\nlet b = Rc::clone(&a);\nlet c = Rc::clone(&a);\nprintln!(\"count: {}\", Rc::strong_count(&a)); \u002F\u002F 3\n",[53,830,831,836,841,846,851],{"__ignoreMap":76},[80,832,833],{"class":82,"line":83},[80,834,835],{},"use std::rc::Rc;\n",[80,837,838],{"class":82,"line":89},[80,839,840],{},"let a = Rc::new(String::from(\"shared\"));\n",[80,842,843],{"class":82,"line":95},[80,844,845],{},"let b = Rc::clone(&a);\n",[80,847,848],{"class":82,"line":127},[80,849,850],{},"let c = Rc::clone(&a);\n",[80,852,853],{"class":82,"line":285},[80,854,855],{},"println!(\"count: {}\", Rc::strong_count(&a)); \u002F\u002F 3\n",[23,857,858,859,861],{},"但 ",[53,860,811],{}," 提供的共享引用是不可变的；如果需要在多个所有者间修改数据，就需要内部可变性。",[31,863,865,868],{"id":864},"arct原子引用计数多线程安全",[53,866,867],{},"Arc\u003CT>","：原子引用计数，多线程安全",[23,870,871,873,874,876],{},[53,872,867],{}," 与 ",[53,875,811],{}," 功能相同，但使用原子操作进行计数，可安全用于多线程环境。在线程间共享所有权时使用。",[72,878,880],{"className":74,"code":879,"language":12,"meta":76,"style":76},"use std::sync::Arc;\nuse std::thread;\nlet a = Arc::new(10);\nlet a_clone = Arc::clone(&a);\nthread::spawn(move || {\n    println!(\"{a_clone}\");\n}).join().unwrap();\n",[53,881,882,887,892,897,902,907,912],{"__ignoreMap":76},[80,883,884],{"class":82,"line":83},[80,885,886],{},"use std::sync::Arc;\n",[80,888,889],{"class":82,"line":89},[80,890,891],{},"use std::thread;\n",[80,893,894],{"class":82,"line":95},[80,895,896],{},"let a = Arc::new(10);\n",[80,898,899],{"class":82,"line":127},[80,900,901],{},"let a_clone = Arc::clone(&a);\n",[80,903,904],{"class":82,"line":285},[80,905,906],{},"thread::spawn(move || {\n",[80,908,909],{"class":82,"line":291},[80,910,911],{},"    println!(\"{a_clone}\");\n",[80,913,914],{"class":82,"line":297},[80,915,916],{},"}).join().unwrap();\n",[31,918,920,923],{"id":919},"refcellt内部可变性运行时借用检查",[53,921,922],{},"RefCell\u003CT>","：内部可变性，运行时借用检查",[23,925,926,928,929,932,933,936,937,48,940,942],{},[53,927,922],{}," 允许你在拥有不可变引用的同时修改内部值，它通过运行时的借用规则来保证安全：",[53,930,931],{},"borrow()"," 和 ",[53,934,935],{},"borrow_mut()"," 会动态地检查同一时间只有一个可变借用或多个不可变借用。违反规则会导致 ",[53,938,939],{},"panic",[53,941,922],{}," 只能用于单线程。",[72,944,946],{"className":74,"code":945,"language":12,"meta":76,"style":76},"use std::cell::RefCell;\nlet data = RefCell::new(42);\n*data.borrow_mut() += 1;\nprintln!(\"{}\", data.borrow()); \u002F\u002F 43\n",[53,947,948,953,958,963],{"__ignoreMap":76},[80,949,950],{"class":82,"line":83},[80,951,952],{},"use std::cell::RefCell;\n",[80,954,955],{"class":82,"line":89},[80,956,957],{},"let data = RefCell::new(42);\n",[80,959,960],{"class":82,"line":95},[80,961,962],{},"*data.borrow_mut() += 1;\n",[80,964,965],{"class":82,"line":127},[80,966,967],{},"println!(\"{}\", data.borrow()); \u002F\u002F 43\n",[31,969,971,972],{"id":970},"组合模式rcrefcellt","组合模式：",[53,973,974],{},"Rc\u003CRefCell\u003CT>>",[23,976,977,978,873,980,983],{},"将 ",[53,979,824],{},[53,981,982],{},"RefCell"," 结合在一起，就能在单线程环境下实现多个所有者同时拥有可变数据的能力。这是 Rust 实现共享可变状态的一种常见模式：",[72,985,987],{"className":74,"code":986,"language":12,"meta":76,"style":76},"use std::rc::Rc;\nuse std::cell::RefCell;\nlet value = Rc::new(RefCell::new(5));\nlet a = Rc::clone(&value);\nlet b = Rc::clone(&value);\n*a.borrow_mut() += 1;\n*b.borrow_mut() += 2;\nprintln!(\"{}\", value.borrow()); \u002F\u002F 8\n",[53,988,989,993,997,1002,1007,1012,1017,1022],{"__ignoreMap":76},[80,990,991],{"class":82,"line":83},[80,992,835],{},[80,994,995],{"class":82,"line":89},[80,996,952],{},[80,998,999],{"class":82,"line":95},[80,1000,1001],{},"let value = Rc::new(RefCell::new(5));\n",[80,1003,1004],{"class":82,"line":127},[80,1005,1006],{},"let a = Rc::clone(&value);\n",[80,1008,1009],{"class":82,"line":285},[80,1010,1011],{},"let b = Rc::clone(&value);\n",[80,1013,1014],{"class":82,"line":291},[80,1015,1016],{},"*a.borrow_mut() += 1;\n",[80,1018,1019],{"class":82,"line":297},[80,1020,1021],{},"*b.borrow_mut() += 2;\n",[80,1023,1025],{"class":82,"line":1024},8,[80,1026,1027],{},"println!(\"{}\", value.borrow()); \u002F\u002F 8\n",[31,1029,1031,1034],{"id":1030},"weakt弱引用避免循环引用",[53,1032,1033],{},"Weak\u003CT>","：弱引用，避免循环引用",[23,1036,1037,932,1039,1042,1043,1045],{},[53,1038,824],{},[53,1040,1041],{},"Arc"," 还可以产生弱引用 ",[53,1044,1033],{},"。弱引用不增加引用计数，不能直接访问数据（需要先升级为强引用），主要用于打破循环引用，防止内存泄漏。",[72,1047,1049],{"className":74,"code":1048,"language":12,"meta":76,"style":76},"use std::rc::{Rc, Weak};\nuse std::cell::RefCell;\n\nstruct Node {\n    value: i32,\n    parent: RefCell\u003CWeak\u003CNode>>,  \u002F\u002F 弱引用指向父节点\n    children: RefCell\u003CVec\u003CRc\u003CNode>>>,\n}\n",[53,1050,1051,1056,1060,1064,1069,1074,1079,1084],{"__ignoreMap":76},[80,1052,1053],{"class":82,"line":83},[80,1054,1055],{},"use std::rc::{Rc, Weak};\n",[80,1057,1058],{"class":82,"line":89},[80,1059,952],{},[80,1061,1062],{"class":82,"line":95},[80,1063,277],{"emptyLinePlaceholder":276},[80,1065,1066],{"class":82,"line":127},[80,1067,1068],{},"struct Node {\n",[80,1070,1071],{"class":82,"line":285},[80,1072,1073],{},"    value: i32,\n",[80,1075,1076],{"class":82,"line":291},[80,1077,1078],{},"    parent: RefCell\u003CWeak\u003CNode>>,  \u002F\u002F 弱引用指向父节点\n",[80,1080,1081],{"class":82,"line":297},[80,1082,1083],{},"    children: RefCell\u003CVec\u003CRc\u003CNode>>>,\n",[80,1085,1086],{"class":82,"line":1024},[80,1087,294],{},[23,1089,1090,1091,1093,1094,1097],{},"父节点持有子节点的 ",[53,1092,824],{},"，子节点通过 ",[53,1095,1096],{},"Weak"," 指向父节点，形成父强子弱的关系，避免了双向强引用导致的内存泄漏。",[23,1099,1100,1101,48],{},"所有权、借用和生命周期构成了 Rust 内存安全的基石。理解这套规则后，你不仅能编写安全且高效的代码，更会发现大部分内存问题在编译时就被拦下。接下来请阅读 ",[1102,1103,1105],"a",{"href":1104},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fdata-type","结构体与集合",[26,1107,1108],{"id":1108},"参考文献",[1110,1111,1112,1125],"table",{},[1113,1114,1115],"thead",{},[1116,1117,1118,1122],"tr",{},[1119,1120,1121],"th",{},"资料",[1119,1123,1124],{},"说明",[1126,1127,1128,1142,1153],"tbody",{},[1116,1129,1130,1139],{},[1131,1132,1133],"td",{},[1102,1134,1138],{"href":1135,"rel":1136},"https:\u002F\u002Fdoc.rust-lang.org\u002Fbook\u002Fch04-00-understanding-ownership.html",[1137],"nofollow","Ownership",[1131,1140,1141],{},"官方书第 4 章",[1116,1143,1144,1151],{},[1131,1145,1146],{},[1102,1147,1150],{"href":1148,"rel":1149},"https:\u002F\u002Fdoc.rust-lang.org\u002Fbook\u002Fch04-02-references-and-borrowing.html",[1137],"References",[1131,1152,317],{},[1116,1154,1155,1162],{},[1131,1156,1157],{},[1102,1158,1161],{"href":1159,"rel":1160},"https:\u002F\u002Fdoc.rust-lang.org\u002Fbook\u002Fch10-03-lifetime-syntax.html",[1137],"Lifetimes",[1131,1163,1164],{},"生命周期",[1166,1167,1168],"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":76,"searchDepth":89,"depth":89,"links":1170},[1171,1178,1186,1197,1211],{"id":28,"depth":89,"text":29,"children":1172},[1173,1174,1175,1176,1177],{"id":33,"depth":95,"text":33},{"id":62,"depth":95,"text":63},{"id":139,"depth":95,"text":140},{"id":216,"depth":95,"text":217},{"id":253,"depth":95,"text":253},{"id":306,"depth":89,"text":307,"children":1179},[1180,1182,1184,1185],{"id":320,"depth":95,"text":1181},"共享引用 &T",{"id":359,"depth":95,"text":1183},"可变引用 &mut T",{"id":411,"depth":95,"text":412},{"id":461,"depth":95,"text":461},{"id":467,"depth":89,"text":468,"children":1187},[1188,1189,1190,1191,1192,1194,1196],{"id":474,"depth":95,"text":474},{"id":509,"depth":95,"text":509},{"id":551,"depth":95,"text":551},{"id":590,"depth":95,"text":590},{"id":626,"depth":95,"text":1193},"静态生命周期 'static",{"id":656,"depth":95,"text":1195},"生命周期界限 T: 'a",{"id":698,"depth":95,"text":699},{"id":730,"depth":89,"text":731,"children":1198},[1199,1201,1203,1205,1207,1209],{"id":737,"depth":95,"text":1200},"Box\u003CT>：堆分配，单一所有权",{"id":808,"depth":95,"text":1202},"Rc\u003CT>：引用计数，单线程共享所有权",{"id":864,"depth":95,"text":1204},"Arc\u003CT>：原子引用计数，多线程安全",{"id":919,"depth":95,"text":1206},"RefCell\u003CT>：内部可变性，运行时借用检查",{"id":970,"depth":95,"text":1208},"组合模式：Rc\u003CRefCell\u003CT>>",{"id":1030,"depth":95,"text":1210},"Weak\u003CT>：弱引用，避免循环引用",{"id":1108,"depth":89,"text":1108},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fend\u002FRust\u002Fcore","knowledge\u002Fknowledge\u002Fbooklet\u002Fend\u002FRust\u002Fcore.md","md",{"items":1217},[1218,1222,1226,1230,1234,1238],{"path":1219,"title":1220,"description":1221,"category":10,"score":291},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fdocs","第八章：测试、文档与质量","Rust 将测试和文档视为语言的一等公民。通过内置的测试框架，你可以在项目里编写单元测试、集成测试以及随文档一起运行的示例测试，三者共用 cargo test 命令。配合 cargo doc 生成文档，形成了一套确保代码质量与可维护性…",{"path":1223,"title":1224,"description":1225,"category":10,"score":291},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Ft","泛型与 Trait","泛型和 trait 是 Rust 实现代码复用与多态的两大支柱。前置：Rust 基础。泛型让代码可以工作在多种类型上而不牺牲性能，trait 定义了类型间的共享行为，二者结合形成了零成本抽象的强大表达能力。本章将深入泛型定义、trai…",{"path":1227,"title":1228,"description":1229,"category":10,"score":291},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Ftype","第二章：基础语法与类型","Rust 的类型系统和语法设计处处体现着“安全”与“显式”的理念。这一章你将掌握变量绑定、基本类型、复合类型、函数定义以及所有基础控制流结构，它们是你写出任何 Rust 程序的基石。",{"path":1231,"title":1232,"description":1233,"category":10,"score":291},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fpackage","第七章：模块系统与包管理","Rust 的模块系统为代码组织、封装和复用提供了一套严谨但灵活的机制。包、crate、模块以及 use 路径相互配合，让你能够把项目拆解成清晰的功能单元，同时精确控制哪些对外可见。本章将带你系统掌握这些构建大型 Rust 项目所必需的…",{"path":1235,"title":1236,"description":1237,"category":10,"score":291},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fother","第十章：进阶特性与模式","Rust 的核心安全保证覆盖了绝大多数日常编程场景。但当你需要打破常规——无论是编写极致通用的抽象、与 C 库交互，还是内联优化——本章将带你进入 Rust 的深层能力：声明宏与过程宏、unsafe 的超能力与封装、高级类型系统技巧…",{"path":1239,"title":1240,"description":1241,"category":10,"score":291},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Ferror","第五章：错误处理","Rust 将错误明确分为两类：不可恢复的错误与可恢复的错误。通过 panic! 处理前一种，Result 处理后一种，这让程序的错误路径不再是隐式的控制流，而是强类型、必须处理的代码分支。配合 Option 对缺失值的处理以及丰富的组…",{"series":1243,"title":12,"items":1244,"index":89,"prev":1269,"next":1270},"booklet\u002Fend\u002Frust",[1245,1249,1253,1254,1257,1259,1261,1263,1265,1267],{"path":1246,"title":1247,"date":1248,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fasync","第九章：并发与异步","2020-05-22",{"path":1250,"title":1251,"date":1252,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fbase","Rust 基础","2020-07-21",{"path":7,"title":8,"date":13,"pinned":14},{"path":1104,"title":1255,"date":1256,"pinned":14},"第四章：复合数据类型","2021-02-24",{"path":1219,"title":1220,"date":1258,"pinned":14},"2026-01-11",{"path":1239,"title":1240,"date":1260,"pinned":14},"2023-11-03",{"path":1235,"title":1236,"date":1262,"pinned":14},"2023-12-29",{"path":1231,"title":1232,"date":1264,"pinned":14},"2024-05-26",{"path":1223,"title":1224,"date":1266,"pinned":14},"2024-10-31",{"path":1227,"title":1228,"date":1268,"pinned":14},"2024-08-31",{"path":1250,"title":1251,"date":1252,"pinned":14},{"path":1104,"title":1255,"date":1256,"pinned":14}]