[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fasync":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fasync":1726,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fasync":1752},{"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":1722,"stem":1723,"id":1724,"extension":1725},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fasync","第九章：并发与异步","Rust 的并发编程建立在所有权和类型系统之上，许多并发错误会在编译期被拦截。本章从传统的线程、通道和共享状态开始，逐步深入到 Send\u002FSync 安全抽象，最后介绍现代异步编程模型 async\u002Fawait，理解 Rust 如何实现无…","技能小册",[12,13],"rust","async","2020-05-22",false,{"type":17,"value":18,"toc":1672},"minimark",[19,23,42,47,50,54,64,158,165,172,182,191,198,204,228,231,237,275,278,282,285,288,307,341,374,377,387,434,441,445,448,455,480,524,536,543,553,652,658,665,670,725,736,739,745,813,836,839,861,864,874,877,882,893,916,921,941,963,978,985,998,1002,1021,1026,1032,1056,1070,1076,1085,1118,1125,1143,1184,1192,1199,1208,1233,1240,1252,1276,1282,1286,1299,1346,1353,1360,1379,1414,1428,1459,1466,1498,1532,1535,1588,1591,1604,1607,1668],[20,21,8],"h1",{"id":22},"第九章并发与异步",[24,25,26,27,31,32,35,36,31,38,41],"p",{},"Rust 的并发编程建立在所有权和类型系统之上，许多并发错误会在编译期被拦截。本章从传统的线程、通道和共享状态开始，逐步深入到 ",[28,29,30],"code",{},"Send","\u002F",[28,33,34],{},"Sync"," 安全抽象，最后介绍现代异步编程模型 ",[28,37,13],{},[28,39,40],{},"await","，理解 Rust 如何实现无畏并发。",[43,44,46],"h2",{"id":45},"_91-线程基础","9.1 线程基础",[24,48,49],{},"Rust 标准库提供了 1:1 原生线程支持，每个 Rust 线程对应一个操作系统线程。",[51,52,53],"h3",{"id":53},"创建线程",[24,55,56,59,60,63],{},[28,57,58],{},"std::thread::spawn"," 接收一个闭包，在新线程中执行并返回 ",[28,61,62],{},"JoinHandle","：",[65,66,70],"pre",{"className":67,"code":68,"language":12,"meta":69,"style":69},"language-rust shiki shiki-themes material-theme-lighter github-light github-dark","use std::thread;\nuse std::time::Duration;\n\nlet handle = thread::spawn(|| {\n    for i in 1..10 {\n        println!(\"子线程: {i}\");\n        thread::sleep(Duration::from_millis(1));\n    }\n});\n\nfor i in 1..5 {\n    println!(\"主线程: {i}\");\n    thread::sleep(Duration::from_millis(1));\n}\n","",[28,71,72,80,86,93,99,105,111,117,123,129,134,140,146,152],{"__ignoreMap":69},[73,74,77],"span",{"class":75,"line":76},"line",1,[73,78,79],{},"use std::thread;\n",[73,81,83],{"class":75,"line":82},2,[73,84,85],{},"use std::time::Duration;\n",[73,87,89],{"class":75,"line":88},3,[73,90,92],{"emptyLinePlaceholder":91},true,"\n",[73,94,96],{"class":75,"line":95},4,[73,97,98],{},"let handle = thread::spawn(|| {\n",[73,100,102],{"class":75,"line":101},5,[73,103,104],{},"    for i in 1..10 {\n",[73,106,108],{"class":75,"line":107},6,[73,109,110],{},"        println!(\"子线程: {i}\");\n",[73,112,114],{"class":75,"line":113},7,[73,115,116],{},"        thread::sleep(Duration::from_millis(1));\n",[73,118,120],{"class":75,"line":119},8,[73,121,122],{},"    }\n",[73,124,126],{"class":75,"line":125},9,[73,127,128],{},"});\n",[73,130,132],{"class":75,"line":131},10,[73,133,92],{"emptyLinePlaceholder":91},[73,135,137],{"class":75,"line":136},11,[73,138,139],{},"for i in 1..5 {\n",[73,141,143],{"class":75,"line":142},12,[73,144,145],{},"    println!(\"主线程: {i}\");\n",[73,147,149],{"class":75,"line":148},13,[73,150,151],{},"    thread::sleep(Duration::from_millis(1));\n",[73,153,155],{"class":75,"line":154},14,[73,156,157],{},"}\n",[24,159,160,161,164],{},"当主线程结束时，整个程序退出，无论子线程是否完成。因此通常需要用 ",[28,162,163],{},"handle.join()"," 等待子线程结束。",[51,166,168,171],{"id":167},"join-等待线程",[28,169,170],{},"join"," 等待线程",[24,173,174,177,178,181],{},[28,175,176],{},"join()"," 会阻塞当前线程，直到被等待的线程完成，返回该线程的 ",[28,179,180],{},"Result","（用于处理 panic）：",[65,183,185],{"className":67,"code":184,"language":12,"meta":69,"style":69},"handle.join().unwrap();\n",[28,186,187],{"__ignoreMap":69},[73,188,189],{"class":75,"line":76},[73,190,184],{},[51,192,194,197],{"id":193},"move-闭包",[28,195,196],{},"move"," 闭包",[24,199,200,201,203],{},"闭包默认会从环境中借用值，但在跨线程场景下，必须强制闭包获得所有权，以避免悬垂引用。",[28,202,196],{}," 关键字会强制闭包将所用到的环境变量移入其中：",[65,205,207],{"className":67,"code":206,"language":12,"meta":69,"style":69},"let v = vec![1, 2, 3];\nlet handle = thread::spawn(move || {\n    println!(\"{:?}\", v); \u002F\u002F v 所有权转移到闭包\n});\n",[28,208,209,214,219,224],{"__ignoreMap":69},[73,210,211],{"class":75,"line":76},[73,212,213],{},"let v = vec![1, 2, 3];\n",[73,215,216],{"class":75,"line":82},[73,217,218],{},"let handle = thread::spawn(move || {\n",[73,220,221],{"class":75,"line":88},[73,222,223],{},"    println!(\"{:?}\", v); \u002F\u002F v 所有权转移到闭包\n",[73,225,226],{"class":75,"line":95},[73,227,128],{},[51,229,230],{"id":230},"线程局部存储",[24,232,233,236],{},[28,234,235],{},"thread_local!"," 宏可以定义线程局部的静态变量，每个线程拥有独立的副本：",[65,238,240],{"className":67,"code":239,"language":12,"meta":69,"style":69},"use std::cell::RefCell;\nthread_local! {\n    static FOO: RefCell\u003Cu32> = RefCell::new(0);\n}\nFOO.with(|f| {\n    *f.borrow_mut() = 42;\n});\n",[28,241,242,247,252,257,261,266,271],{"__ignoreMap":69},[73,243,244],{"class":75,"line":76},[73,245,246],{},"use std::cell::RefCell;\n",[73,248,249],{"class":75,"line":82},[73,250,251],{},"thread_local! {\n",[73,253,254],{"class":75,"line":88},[73,255,256],{},"    static FOO: RefCell\u003Cu32> = RefCell::new(0);\n",[73,258,259],{"class":75,"line":95},[73,260,157],{},[73,262,263],{"class":75,"line":101},[73,264,265],{},"FOO.with(|f| {\n",[73,267,268],{"class":75,"line":107},[73,269,270],{},"    *f.borrow_mut() = 42;\n",[73,272,273],{"class":75,"line":113},[73,274,128],{},[24,276,277],{},"这类变量特别适合存储线程专属的上下文或缓存。",[43,279,281],{"id":280},"_92-消息传递channel","9.2 消息传递（Channel）",[24,283,284],{},"Rust 标准库提供了多生产者单消费者（mpsc）通道，通过消息传递在线程间通信，符合“不要通过共享内存来通信，而要通过通信来共享内存”的理念。",[51,286,287],{"id":287},"创建通道",[65,289,291],{"className":67,"code":290,"language":12,"meta":69,"style":69},"use std::sync::mpsc;\n\nlet (tx, rx) = mpsc::channel(); \u002F\u002F tx: 发送端, rx: 接收端\n",[28,292,293,298,302],{"__ignoreMap":69},[73,294,295],{"class":75,"line":76},[73,296,297],{},"use std::sync::mpsc;\n",[73,299,300],{"class":75,"line":82},[73,301,92],{"emptyLinePlaceholder":91},[73,303,304],{"class":75,"line":88},[73,305,306],{},"let (tx, rx) = mpsc::channel(); \u002F\u002F tx: 发送端, rx: 接收端\n",[308,309,310,321,329],"ul",{},[311,312,313,316,317,320],"li",{},[28,314,315],{},"tx.send(value)","：发送值，若接收端已抛弃则返回 ",[28,318,319],{},"Err","。",[311,322,323,326,327,320],{},[28,324,325],{},"rx.recv()","：阻塞直到收到值，通道关闭时返回 ",[28,328,319],{},[311,330,331,334,335,338,339,320],{},[28,332,333],{},"rx.try_recv()","：非阻塞，有值时返回 ",[28,336,337],{},"Ok","，否则返回 ",[28,340,319],{},[65,342,344],{"className":67,"code":343,"language":12,"meta":69,"style":69},"thread::spawn(move || {\n    tx.send(\"hello from thread\").unwrap();\n});\n\nlet msg = rx.recv().unwrap();\nprintln!(\"收到: {msg}\");\n",[28,345,346,351,356,360,364,369],{"__ignoreMap":69},[73,347,348],{"class":75,"line":76},[73,349,350],{},"thread::spawn(move || {\n",[73,352,353],{"class":75,"line":82},[73,354,355],{},"    tx.send(\"hello from thread\").unwrap();\n",[73,357,358],{"class":75,"line":88},[73,359,128],{},[73,361,362],{"class":75,"line":95},[73,363,92],{"emptyLinePlaceholder":91},[73,365,366],{"class":75,"line":101},[73,367,368],{},"let msg = rx.recv().unwrap();\n",[73,370,371],{"class":75,"line":107},[73,372,373],{},"println!(\"收到: {msg}\");\n",[51,375,376],{"id":376},"多生产者",[24,378,379,382,383,386],{},[28,380,381],{},"mpsc"," 的 ",[28,384,385],{},"tx"," 可以克隆，产生多个发送端共享同一接收端：",[65,388,390],{"className":67,"code":389,"language":12,"meta":69,"style":69},"let (tx, rx) = mpsc::channel();\nlet tx1 = tx.clone();\n\nthread::spawn(move || { tx.send(\"线程1\").unwrap(); });\nthread::spawn(move || { tx1.send(\"线程2\").unwrap(); });\n\nfor received in rx {\n    println!(\"{received}\");\n}\n",[28,391,392,397,402,406,411,416,420,425,430],{"__ignoreMap":69},[73,393,394],{"class":75,"line":76},[73,395,396],{},"let (tx, rx) = mpsc::channel();\n",[73,398,399],{"class":75,"line":82},[73,400,401],{},"let tx1 = tx.clone();\n",[73,403,404],{"class":75,"line":88},[73,405,92],{"emptyLinePlaceholder":91},[73,407,408],{"class":75,"line":95},[73,409,410],{},"thread::spawn(move || { tx.send(\"线程1\").unwrap(); });\n",[73,412,413],{"class":75,"line":101},[73,414,415],{},"thread::spawn(move || { tx1.send(\"线程2\").unwrap(); });\n",[73,417,418],{"class":75,"line":107},[73,419,92],{"emptyLinePlaceholder":91},[73,421,422],{"class":75,"line":113},[73,423,424],{},"for received in rx {\n",[73,426,427],{"class":75,"line":119},[73,428,429],{},"    println!(\"{received}\");\n",[73,431,432],{"class":75,"line":125},[73,433,157],{},[24,435,436,437,440],{},"接收端 ",[28,438,439],{},"rx"," 可作为迭代器使用，阻塞地获取每条消息，直到所有发送端都被丢弃且通道为空时迭代结束。",[43,442,444],{"id":443},"_93-共享状态并发","9.3 共享状态并发",[24,446,447],{},"消息传递并非万能，有时需要多个线程同时读写同一数据。Rust 的类型系统让共享内存也安全。",[51,449,451,454],{"id":450},"mutext互斥锁",[28,452,453],{},"Mutex\u003CT>","：互斥锁",[24,456,457,459,460,463,464,467,468,471,472,475,476,479],{},[28,458,453],{}," 提供内部数据的互斥访问。",[28,461,462],{},"lock()"," 方法返回 ",[28,465,466],{},"LockResult\u003CMutexGuard\u003CT>>","，",[28,469,470],{},"MutexGuard"," 实现 ",[28,473,474],{},"Deref"," 和 ",[28,477,478],{},"DerefMut","，可以透明地访问内部值，离开作用域时自动释放锁：",[65,481,483],{"className":67,"code":482,"language":12,"meta":69,"style":69},"use std::sync::Mutex;\n\nlet m = Mutex::new(5);\n{\n    let mut num = m.lock().unwrap();\n    *num = 6;\n} \u002F\u002F 锁在此处自动释放\nprintln!(\"{:?}\", m);\n",[28,484,485,490,494,499,504,509,514,519],{"__ignoreMap":69},[73,486,487],{"class":75,"line":76},[73,488,489],{},"use std::sync::Mutex;\n",[73,491,492],{"class":75,"line":82},[73,493,92],{"emptyLinePlaceholder":91},[73,495,496],{"class":75,"line":88},[73,497,498],{},"let m = Mutex::new(5);\n",[73,500,501],{"class":75,"line":95},[73,502,503],{},"{\n",[73,505,506],{"class":75,"line":101},[73,507,508],{},"    let mut num = m.lock().unwrap();\n",[73,510,511],{"class":75,"line":107},[73,512,513],{},"    *num = 6;\n",[73,515,516],{"class":75,"line":113},[73,517,518],{},"} \u002F\u002F 锁在此处自动释放\n",[73,520,521],{"class":75,"line":119},[73,522,523],{},"println!(\"{:?}\", m);\n",[24,525,526,528,529,531,532,535],{},[28,527,462],{}," 在获得锁的线程 panic 时会返回 ",[28,530,319],{},"，用 ",[28,533,534],{},"unwrap()"," 处理是常见做法。",[51,537,539,542],{"id":538},"arct-多线程所有权共享",[28,540,541],{},"Arc\u003CT>"," 多线程所有权共享",[24,544,545,546,548,549,552],{},"由于线程之间可能没有明确的所有权层次，需要引用计数来共享所有权。",[28,547,541],{},"（原子引用计数）功能与 ",[28,550,551],{},"Rc\u003CT>"," 相同，但通过原子操作保证线程安全：",[65,554,556],{"className":67,"code":555,"language":12,"meta":69,"style":69},"use std::sync::{Arc, Mutex};\nuse std::thread;\n\nlet counter = Arc::new(Mutex::new(0));\nlet mut handles = vec![];\n\nfor _ in 0..10 {\n    let counter = Arc::clone(&counter);\n    let handle = thread::spawn(move || {\n        let mut num = counter.lock().unwrap();\n        *num += 1;\n    });\n    handles.push(handle);\n}\n\nfor handle in handles {\n    handle.join().unwrap();\n}\nprintln!(\"结果: {}\", *counter.lock().unwrap()); \u002F\u002F 10\n",[28,557,558,563,567,571,576,581,585,590,595,600,605,610,615,620,624,629,635,641,646],{"__ignoreMap":69},[73,559,560],{"class":75,"line":76},[73,561,562],{},"use std::sync::{Arc, Mutex};\n",[73,564,565],{"class":75,"line":82},[73,566,79],{},[73,568,569],{"class":75,"line":88},[73,570,92],{"emptyLinePlaceholder":91},[73,572,573],{"class":75,"line":95},[73,574,575],{},"let counter = Arc::new(Mutex::new(0));\n",[73,577,578],{"class":75,"line":101},[73,579,580],{},"let mut handles = vec![];\n",[73,582,583],{"class":75,"line":107},[73,584,92],{"emptyLinePlaceholder":91},[73,586,587],{"class":75,"line":113},[73,588,589],{},"for _ in 0..10 {\n",[73,591,592],{"class":75,"line":119},[73,593,594],{},"    let counter = Arc::clone(&counter);\n",[73,596,597],{"class":75,"line":125},[73,598,599],{},"    let handle = thread::spawn(move || {\n",[73,601,602],{"class":75,"line":131},[73,603,604],{},"        let mut num = counter.lock().unwrap();\n",[73,606,607],{"class":75,"line":136},[73,608,609],{},"        *num += 1;\n",[73,611,612],{"class":75,"line":142},[73,613,614],{},"    });\n",[73,616,617],{"class":75,"line":148},[73,618,619],{},"    handles.push(handle);\n",[73,621,622],{"class":75,"line":154},[73,623,157],{},[73,625,627],{"class":75,"line":626},15,[73,628,92],{"emptyLinePlaceholder":91},[73,630,632],{"class":75,"line":631},16,[73,633,634],{},"for handle in handles {\n",[73,636,638],{"class":75,"line":637},17,[73,639,640],{},"    handle.join().unwrap();\n",[73,642,644],{"class":75,"line":643},18,[73,645,157],{},[73,647,649],{"class":75,"line":648},19,[73,650,651],{},"println!(\"结果: {}\", *counter.lock().unwrap()); \u002F\u002F 10\n",[24,653,654,657],{},[28,655,656],{},"Arc\u003CMutex\u003CT>>"," 是多线程共享可变状态最经典的模式，但要注意死锁风险和锁的开销。",[51,659,661,664],{"id":660},"rwlockt读写锁",[28,662,663],{},"RwLock\u003CT>","：读写锁",[24,666,667,669],{},[28,668,663],{}," 允许多个读或一个写，适合读多写少场景：",[65,671,673],{"className":67,"code":672,"language":12,"meta":69,"style":69},"use std::sync::RwLock;\n\nlet lock = RwLock::new(5);\n{\n    let r1 = lock.read().unwrap();\n    let r2 = lock.read().unwrap(); \u002F\u002F 多个读可以共存\n}\n{\n    let mut w = lock.write().unwrap();\n    *w += 1;\n}\n",[28,674,675,680,684,689,693,698,703,707,711,716,721],{"__ignoreMap":69},[73,676,677],{"class":75,"line":76},[73,678,679],{},"use std::sync::RwLock;\n",[73,681,682],{"class":75,"line":82},[73,683,92],{"emptyLinePlaceholder":91},[73,685,686],{"class":75,"line":88},[73,687,688],{},"let lock = RwLock::new(5);\n",[73,690,691],{"class":75,"line":95},[73,692,503],{},[73,694,695],{"class":75,"line":101},[73,696,697],{},"    let r1 = lock.read().unwrap();\n",[73,699,700],{"class":75,"line":107},[73,701,702],{},"    let r2 = lock.read().unwrap(); \u002F\u002F 多个读可以共存\n",[73,704,705],{"class":75,"line":113},[73,706,157],{},[73,708,709],{"class":75,"line":119},[73,710,503],{},[73,712,713],{"class":75,"line":125},[73,714,715],{},"    let mut w = lock.write().unwrap();\n",[73,717,718],{"class":75,"line":131},[73,719,720],{},"    *w += 1;\n",[73,722,723],{"class":75,"line":136},[73,724,157],{},[24,726,727,728,731,732,735],{},"内部原理上，",[28,729,730],{},"RwLock"," 在读多时优于 ",[28,733,734],{},"Mutex","，但可能增加锁竞争开销。",[51,737,738],{"id":738},"原子类型",[24,740,741,744],{},[28,742,743],{},"std::sync::atomic"," 模块提供无需锁的原子操作，适用于简单的共享标志或计数器：",[65,746,748],{"className":67,"code":747,"language":12,"meta":69,"style":69},"use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};\nuse std::sync::Arc;\nuse std::thread;\n\nlet running = Arc::new(AtomicBool::new(true));\nlet r = running.clone();\n\nthread::spawn(move || {\n    while r.load(Ordering::SeqCst) {\n        \u002F\u002F 执行工作\n    }\n});\n\nrunning.store(false, Ordering::SeqCst);\n",[28,749,750,755,760,764,768,773,778,782,786,791,796,800,804,808],{"__ignoreMap":69},[73,751,752],{"class":75,"line":76},[73,753,754],{},"use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};\n",[73,756,757],{"class":75,"line":82},[73,758,759],{},"use std::sync::Arc;\n",[73,761,762],{"class":75,"line":88},[73,763,79],{},[73,765,766],{"class":75,"line":95},[73,767,92],{"emptyLinePlaceholder":91},[73,769,770],{"class":75,"line":101},[73,771,772],{},"let running = Arc::new(AtomicBool::new(true));\n",[73,774,775],{"class":75,"line":107},[73,776,777],{},"let r = running.clone();\n",[73,779,780],{"class":75,"line":113},[73,781,92],{"emptyLinePlaceholder":91},[73,783,784],{"class":75,"line":119},[73,785,350],{},[73,787,788],{"class":75,"line":125},[73,789,790],{},"    while r.load(Ordering::SeqCst) {\n",[73,792,793],{"class":75,"line":131},[73,794,795],{},"        \u002F\u002F 执行工作\n",[73,797,798],{"class":75,"line":136},[73,799,122],{},[73,801,802],{"class":75,"line":142},[73,803,128],{},[73,805,806],{"class":75,"line":148},[73,807,92],{"emptyLinePlaceholder":91},[73,809,810],{"class":75,"line":154},[73,811,812],{},"running.store(false, Ordering::SeqCst);\n",[24,814,815,818,819,822,823,822,826,822,829,832,833,835],{},[28,816,817],{},"Ordering","（",[28,820,821],{},"Relaxed","、",[28,824,825],{},"Acquire",[28,827,828],{},"Release",[28,830,831],{},"SeqCst","）控制内存顺序保证，",[28,834,831],{}," 是最严格、最容易理解的，但在性能敏感场景下可选用较宽松的顺序。",[51,837,838],{"id":838},"其他同步原语",[308,840,841,850],{},[311,842,843,849],{},[844,845,846],"strong",{},[28,847,848],{},"Barrier","：让所有线程在某点同步，直到达到指定数量后一起继续。",[311,851,852,857,858,860],{},[844,853,854],{},[28,855,856],{},"Condvar","：条件变量，配合 ",[28,859,734],{}," 实现线程通知等待。",[24,862,863],{},"这些原语为更复杂的同步模式提供了底层支持。",[43,865,867,868,870,871,873],{"id":866},"_94-send-与-sync-trait","9.4 ",[28,869,30],{}," 与 ",[28,872,34],{}," trait",[24,875,876],{},"这两个标记 trait 是 Rust 并发安全的基石，编译器会自动为符合规则的类型实现它们。",[51,878,880],{"id":879},"send",[28,881,30],{},[24,883,884,886,887,889,890,892],{},[28,885,30],{}," 标记表示该类型的所有权可以安全地在线程间转移。几乎所有 Rust 类型都是 ",[28,888,30],{},"，但 ",[28,891,551],{}," 例外，因为它的引用计数不是原子操作。",[65,894,896],{"className":67,"code":895,"language":12,"meta":69,"style":69},"fn is_send\u003CT: Send>() {}\nis_send::\u003Ci32>();      \u002F\u002F 通过\n\u002F\u002F is_send::\u003CRc\u003Ci32>>(); \u002F\u002F 编译错误\n",[28,897,898,903,908],{"__ignoreMap":69},[73,899,900],{"class":75,"line":76},[73,901,902],{},"fn is_send\u003CT: Send>() {}\n",[73,904,905],{"class":75,"line":82},[73,906,907],{},"is_send::\u003Ci32>();      \u002F\u002F 通过\n",[73,909,910,913],{"class":75,"line":88},[73,911,912],{},"\u002F\u002F is_send::\u003CRc\u003Ci32>>();",[73,914,915],{}," \u002F\u002F 编译错误\n",[51,917,919],{"id":918},"sync",[28,920,34],{},[24,922,923,925,926,929,930,932,933,935,936,932,939,320],{},[28,924,34],{}," 标记表示该类型的共享引用 ",[28,927,928],{},"&T"," 可以安全地在多个线程间访问。即如果 ",[28,931,928],{}," 是 ",[28,934,30],{},"，则 ",[28,937,938],{},"T",[28,940,34],{},[65,942,944],{"className":67,"code":943,"language":12,"meta":69,"style":69},"fn is_sync\u003CT: Sync>() {}\nis_sync::\u003Ci32>();         \u002F\u002F 通过\n\u002F\u002F is_sync::\u003CRefCell\u003Ci32>>(); \u002F\u002F 编译错误\n",[28,945,946,951,956],{"__ignoreMap":69},[73,947,948],{"class":75,"line":76},[73,949,950],{},"fn is_sync\u003CT: Sync>() {}\n",[73,952,953],{"class":75,"line":82},[73,954,955],{},"is_sync::\u003Ci32>();         \u002F\u002F 通过\n",[73,957,958,961],{"class":75,"line":88},[73,959,960],{},"\u002F\u002F is_sync::\u003CRefCell\u003Ci32>>();",[73,962,915],{},[24,964,965,932,967,969,970,973,974,977],{},[28,966,453],{},[28,968,34],{},"，而 ",[28,971,972],{},"RefCell\u003CT>"," 不是，因为 ",[28,975,976],{},"RefCell"," 的借用检查是运行时的且非线程安全。",[51,979,981,982],{"id":980},"自动实现与手动-unsafe","自动实现与手动 ",[28,983,984],{},"unsafe",[24,986,987,988,990,991,993,994,997],{},"这两个 trait 是自动推导的：如果一个类型的所有成员都是 ",[28,989,30],{}," \u002F ",[28,992,34],{},"，那该类型也自动是。如果某个类型内部使用了原始指针等需要手动保证线程安全的场景，就需要 ",[28,995,996],{},"unsafe impl Send"," 等方式来自行承诺，这必须极其谨慎。",[43,999,1001],{"id":1000},"_95-异步基础asyncawait","9.5 异步基础（async\u002Fawait）",[24,1003,1004,1005,31,1007,1009,1010,1013,1014,822,1017,1020],{},"Rust 的异步编程通过 ",[28,1006,13],{},[28,1008,40],{}," 语法和 ",[28,1011,1012],{},"Future"," trait 实现，没有内置运行时——你需要选择外部执行器（如 ",[28,1015,1016],{},"tokio",[28,1018,1019],{},"async-std","）来驱动任务。",[51,1022,1024,873],{"id":1023},"future-trait",[28,1025,1012],{},[24,1027,1028,1029,1031],{},"异步操作的核心抽象是 ",[28,1030,1012],{},"，它代表一个尚未完成的计算。简化定义如下：",[65,1033,1035],{"className":67,"code":1034,"language":12,"meta":69,"style":69},"pub trait Future {\n    type Output;\n    fn poll(self: Pin\u003C&mut Self>, cx: &mut Context\u003C'_>) -> Poll\u003CSelf::Output>;\n}\n",[28,1036,1037,1042,1047,1052],{"__ignoreMap":69},[73,1038,1039],{"class":75,"line":76},[73,1040,1041],{},"pub trait Future {\n",[73,1043,1044],{"class":75,"line":82},[73,1045,1046],{},"    type Output;\n",[73,1048,1049],{"class":75,"line":88},[73,1050,1051],{},"    fn poll(self: Pin\u003C&mut Self>, cx: &mut Context\u003C'_>) -> Poll\u003CSelf::Output>;\n",[73,1053,1054],{"class":75,"line":95},[73,1055,157],{},[24,1057,1058,1061,1062,1065,1066,1069],{},[28,1059,1060],{},"Poll::Pending"," 表示未就绪，执行器会在就绪时再次调用 ",[28,1063,1064],{},"poll","；",[28,1067,1068],{},"Poll::Ready(value)"," 则返回最终值。",[51,1071,1073,1075],{"id":1072},"async-块与函数",[28,1074,13],{}," 块与函数",[24,1077,1078,1079,1081,1082,1084],{},"用 ",[28,1080,13],{}," 关键字标记函数或块，编译器会将其转换为实现了 ",[28,1083,1012],{}," 的状态机：",[65,1086,1088],{"className":67,"code":1087,"language":12,"meta":69,"style":69},"async fn fetch_data() -> String {\n    \u002F\u002F 异步操作\n    \"data\".to_string()\n}\n\nlet future = fetch_data(); \u002F\u002F 返回 Future，尚未执行\n",[28,1089,1090,1095,1100,1105,1109,1113],{"__ignoreMap":69},[73,1091,1092],{"class":75,"line":76},[73,1093,1094],{},"async fn fetch_data() -> String {\n",[73,1096,1097],{"class":75,"line":82},[73,1098,1099],{},"    \u002F\u002F 异步操作\n",[73,1101,1102],{"class":75,"line":88},[73,1103,1104],{},"    \"data\".to_string()\n",[73,1106,1107],{"class":75,"line":95},[73,1108,157],{},[73,1110,1111],{"class":75,"line":101},[73,1112,92],{"emptyLinePlaceholder":91},[73,1114,1115],{"class":75,"line":107},[73,1116,1117],{},"let future = fetch_data(); \u002F\u002F 返回 Future，尚未执行\n",[51,1119,1121,1122],{"id":1120},"执行器与-await","执行器与 ",[28,1123,1124],{},".await",[24,1126,1127,1128,1130,1131,1133,1134,1136,1137,1139,1140,1142],{},"执行器（如 ",[28,1129,1016],{},"）负责调度和推进 ",[28,1132,1012],{},"。在 ",[28,1135,13],{}," 函数中使用 ",[28,1138,1124],{}," 等待某个 ",[28,1141,1012],{}," 完成并获取结果：",[65,1144,1146],{"className":67,"code":1145,"language":12,"meta":69,"style":69},"use tokio;\n\n#[tokio::main] \u002F\u002F 使用 tokio 执行器的宏，隐式启动运行时\nasync fn main() {\n    let data = fetch_data().await;\n    println!(\"{data}\");\n}\n",[28,1147,1148,1153,1157,1165,1170,1175,1180],{"__ignoreMap":69},[73,1149,1150],{"class":75,"line":76},[73,1151,1152],{},"use tokio;\n",[73,1154,1155],{"class":75,"line":82},[73,1156,92],{"emptyLinePlaceholder":91},[73,1158,1159,1162],{"class":75,"line":88},[73,1160,1161],{},"#[tokio::main]",[73,1163,1164],{}," \u002F\u002F 使用 tokio 执行器的宏，隐式启动运行时\n",[73,1166,1167],{"class":75,"line":95},[73,1168,1169],{},"async fn main() {\n",[73,1171,1172],{"class":75,"line":101},[73,1173,1174],{},"    let data = fetch_data().await;\n",[73,1176,1177],{"class":75,"line":107},[73,1178,1179],{},"    println!(\"{data}\");\n",[73,1181,1182],{"class":75,"line":113},[73,1183,157],{},[24,1185,1186,1188,1189,1191],{},[28,1187,1124],{}," 会在该点让出执行权，直到 ",[28,1190,1012],{}," 就绪。",[51,1193,1195,1198],{"id":1194},"async-move-块",[28,1196,1197],{},"async move"," 块",[24,1200,1201,1202,1204,1205,1207],{},"与普通闭包一样，",[28,1203,13],{}," 块默认会从环境中借用；使用 ",[28,1206,1197],{}," 让块获得所用变量的所有权，常用于生成不同生命周期的任务：",[65,1209,1211],{"className":67,"code":1210,"language":12,"meta":69,"style":69},"let s = String::from(\"hello\");\nlet task = async move {\n    println!(\"{s}\");\n};\n",[28,1212,1213,1218,1223,1228],{"__ignoreMap":69},[73,1214,1215],{"class":75,"line":76},[73,1216,1217],{},"let s = String::from(\"hello\");\n",[73,1219,1220],{"class":75,"line":82},[73,1221,1222],{},"let task = async move {\n",[73,1224,1225],{"class":75,"line":88},[73,1226,1227],{},"    println!(\"{s}\");\n",[73,1229,1230],{"class":75,"line":95},[73,1231,1232],{},"};\n",[51,1234,1236,1237],{"id":1235},"异步任务tokiospawn","异步任务：",[28,1238,1239],{},"tokio::spawn",[24,1241,1242,1244,1245,1247,1248,1251],{},[28,1243,1239],{}," 将一个 ",[28,1246,1012],{}," 提交为独立任务并立即在后台运行（需满足 ",[28,1249,1250],{},"'static"," 生命周期）：",[65,1253,1255],{"className":67,"code":1254,"language":12,"meta":69,"style":69},"let handle = tokio::spawn(async {\n    \"return value\"\n});\nlet result = handle.await.unwrap();\n",[28,1256,1257,1262,1267,1271],{"__ignoreMap":69},[73,1258,1259],{"class":75,"line":76},[73,1260,1261],{},"let handle = tokio::spawn(async {\n",[73,1263,1264],{"class":75,"line":82},[73,1265,1266],{},"    \"return value\"\n",[73,1268,1269],{"class":75,"line":88},[73,1270,128],{},[73,1272,1273],{"class":75,"line":95},[73,1274,1275],{},"let result = handle.await.unwrap();\n",[24,1277,1278,1279,1281],{},"任务失败或 panic 时可以通过 ",[28,1280,62],{}," 捕获。",[51,1283,1285],{"id":1284},"异步-io","异步 I\u002FO",[24,1287,1288,1289,822,1292,1295,1296,1298],{},"标准库的同步 I\u002FO 会阻塞线程，异步版本（如 ",[28,1290,1291],{},"tokio::net",[28,1293,1294],{},"tokio::fs","）则配合 ",[28,1297,1124],{}," 实现非阻塞操作：",[65,1300,1302],{"className":67,"code":1301,"language":12,"meta":69,"style":69},"use tokio::net::TcpListener;\n\nlet listener = TcpListener::bind(\"127.0.0.1:8080\").await.unwrap();\nloop {\n    let (socket, _) = listener.accept().await.unwrap();\n    tokio::spawn(async move {\n        \u002F\u002F 处理 socket\n    });\n}\n",[28,1303,1304,1309,1313,1318,1323,1328,1333,1338,1342],{"__ignoreMap":69},[73,1305,1306],{"class":75,"line":76},[73,1307,1308],{},"use tokio::net::TcpListener;\n",[73,1310,1311],{"class":75,"line":82},[73,1312,92],{"emptyLinePlaceholder":91},[73,1314,1315],{"class":75,"line":88},[73,1316,1317],{},"let listener = TcpListener::bind(\"127.0.0.1:8080\").await.unwrap();\n",[73,1319,1320],{"class":75,"line":95},[73,1321,1322],{},"loop {\n",[73,1324,1325],{"class":75,"line":101},[73,1326,1327],{},"    let (socket, _) = listener.accept().await.unwrap();\n",[73,1329,1330],{"class":75,"line":107},[73,1331,1332],{},"    tokio::spawn(async move {\n",[73,1334,1335],{"class":75,"line":113},[73,1336,1337],{},"        \u002F\u002F 处理 socket\n",[73,1339,1340],{"class":75,"line":119},[73,1341,614],{},[73,1343,1344],{"class":75,"line":125},[73,1345,157],{},[51,1347,1349,1350],{"id":1348},"异步-trait-与-async_trait","异步 trait 与 ",[28,1351,1352],{},"async_trait",[24,1354,1355,1356,1359],{},"自 Rust 1.75（2023 年底）起，稳定版已支持在 trait 中直接定义 ",[28,1357,1358],{},"async fn","（静态分发）：",[65,1361,1363],{"className":67,"code":1362,"language":12,"meta":69,"style":69},"trait Fetcher {\n    async fn fetch(&self) -> String;\n}\n",[28,1364,1365,1370,1375],{"__ignoreMap":69},[73,1366,1367],{"class":75,"line":76},[73,1368,1369],{},"trait Fetcher {\n",[73,1371,1372],{"class":75,"line":82},[73,1373,1374],{},"    async fn fetch(&self) -> String;\n",[73,1376,1377],{"class":75,"line":88},[73,1378,157],{},[24,1380,1381,1382,1389,1390,1393,1394,1396,1397,1399,1400,1402,1403,1406,1407,1410,1411,1413],{},"但该特性目前仍有限制：这类 trait ",[844,1383,1384,1385,1388],{},"不是 ",[28,1386,1387],{},"dyn"," 安全的","（无法用于 ",[28,1391,1392],{},"Box\u003Cdyn Fetcher>"," 等动态分发场景），且公共 trait 中的 ",[28,1395,1358],{}," 默认无法显式声明返回的 ",[28,1398,1012],{}," 是否 ",[28,1401,30],{},"（可配合 ",[28,1404,1405],{},"trait-variant"," crate 的 ",[28,1408,1409],{},"#[trait_variant::make]"," 生成 ",[28,1412,30],{}," 版本）。",[24,1415,1416,1417,1420,1421,1423,1424,1427],{},"若需要动态分发（",[28,1418,1419],{},"dyn Trait","），仍需使用 ",[28,1422,1352],{}," 宏，它将异步方法转换为返回 ",[28,1425,1426],{},"Pin\u003CBox\u003Cdyn Future\u003COutput = ...> + Send>>"," 的形式：",[65,1429,1431],{"className":67,"code":1430,"language":12,"meta":69,"style":69},"use async_trait::async_trait;\n\n#[async_trait]\ntrait Fetcher {\n    async fn fetch(&self) -> String;\n}\n",[28,1432,1433,1438,1442,1447,1451,1455],{"__ignoreMap":69},[73,1434,1435],{"class":75,"line":76},[73,1436,1437],{},"use async_trait::async_trait;\n",[73,1439,1440],{"class":75,"line":82},[73,1441,92],{"emptyLinePlaceholder":91},[73,1443,1444],{"class":75,"line":88},[73,1445,1446],{},"#[async_trait]\n",[73,1448,1449],{"class":75,"line":95},[73,1450,1369],{},[73,1452,1453],{"class":75,"line":101},[73,1454,1374],{},[73,1456,1457],{"class":75,"line":107},[73,1458,157],{},[51,1460,1462,1465],{"id":1461},"stream异步迭代器",[28,1463,1464],{},"Stream","：异步迭代器",[24,1467,1468,1470,1471,889,1474,463,1477,320,1480,1483,1484,1487,1488,822,1491,822,1494,1497],{},[28,1469,1464],{}," 类似于 ",[28,1472,1473],{},"Iterator",[28,1475,1476],{},"next",[28,1478,1479],{},"Poll\u003COption\u003CItem>>",[28,1481,1482],{},"futures"," crate 提供了 ",[28,1485,1486],{},"StreamExt"," 扩展，可在流上使用 ",[28,1489,1490],{},"map",[28,1492,1493],{},"filter",[28,1495,1496],{},"for_each"," 等组合子：",[65,1499,1501],{"className":67,"code":1500,"language":12,"meta":69,"style":69},"use futures::stream::{self, StreamExt};\n\nlet stream = stream::iter(vec![1, 2, 3]);\nstream.for_each(|x| async move {\n    println!(\"{x}\");\n}).await;\n",[28,1502,1503,1508,1512,1517,1522,1527],{"__ignoreMap":69},[73,1504,1505],{"class":75,"line":76},[73,1506,1507],{},"use futures::stream::{self, StreamExt};\n",[73,1509,1510],{"class":75,"line":82},[73,1511,92],{"emptyLinePlaceholder":91},[73,1513,1514],{"class":75,"line":88},[73,1515,1516],{},"let stream = stream::iter(vec![1, 2, 3]);\n",[73,1518,1519],{"class":75,"line":95},[73,1520,1521],{},"stream.for_each(|x| async move {\n",[73,1523,1524],{"class":75,"line":101},[73,1525,1526],{},"    println!(\"{x}\");\n",[73,1528,1529],{"class":75,"line":107},[73,1530,1531],{},"}).await;\n",[51,1533,1534],{"id":1534},"常见异步模式",[308,1536,1537,1551,1568],{},[311,1538,1539,818,1544,990,1547,1550],{},[844,1540,1541],{},[28,1542,1543],{},"select!",[28,1545,1546],{},"tokio::select!",[28,1548,1549],{},"futures::select!","）：同时等待多个异步操作，任一完成即返回，可用于超时等。",[311,1552,1553,818,1558,990,1561,1564,1565,1567],{},[844,1554,1555],{},[28,1556,1557],{},"join!",[28,1559,1560],{},"tokio::join!",[28,1562,1563],{},"futures::join!","）：并行等待多个 ",[28,1566,1012],{}," 全部完成。",[311,1569,1570,1573,1574,1576,1577,1579,1580,1583,1584,1587],{},[844,1571,1572],{},"并发请求","：将多个 ",[28,1575,1012],{}," 提交到 ",[28,1578,1239],{}," 或收集为 ",[28,1581,1582],{},"Vec"," 后用 ",[28,1585,1586],{},"join_all"," 并发执行。",[24,1589,1590],{},"这些模式使异步代码能以接近同步代码的简洁性实现高并发。",[24,1592,1593,1594,31,1596,1598,1599,31,1601,1603],{},"传统并发模型通过线程、通道、互斥锁和原子类型提供了可靠的基础，而 ",[28,1595,13],{},[28,1597,40],{}," 则让高并发 I\u002FO 密集任务变得轻盈直观。Rust 将安全性从单线程延续到并发世界，",[28,1600,30],{},[28,1602,34],{}," 是这一承诺的守护者。掌握这些工具后，你就可以构建既安全又高性能的并发程序了。",[43,1605,1606],{"id":1606},"参考文献",[1608,1609,1610,1623],"table",{},[1611,1612,1613],"thead",{},[1614,1615,1616,1620],"tr",{},[1617,1618,1619],"th",{},"资料",[1617,1621,1622],{},"说明",[1624,1625,1626,1641,1656],"tbody",{},[1614,1627,1628,1638],{},[1629,1630,1631],"td",{},[1632,1633,1637],"a",{"href":1634,"rel":1635},"https:\u002F\u002Fdoc.rust-lang.org\u002Fbook\u002Fch16-00-concurrency.html",[1636],"nofollow","Concurrency",[1629,1639,1640],{},"官方书第 16 章",[1614,1642,1643,1650],{},[1629,1644,1645],{},[1632,1646,1649],{"href":1647,"rel":1648},"https:\u002F\u002Fdoc.rust-lang.org\u002Fbook\u002Fch17-00-async-await.html",[1636],"Async",[1629,1651,1652,31,1654],{},[28,1653,13],{},[28,1655,40],{},[1614,1657,1658,1665],{},[1629,1659,1660],{},[1632,1661,1664],{"href":1662,"rel":1663},"https:\u002F\u002Ftokio.rs\u002F",[1636],"Tokio",[1629,1666,1667],{},"常用异步运行时（第三方 crate）",[1669,1670,1671],"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":69,"searchDepth":82,"depth":82,"links":1673},[1674,1682,1686,1696,1703,1721],{"id":45,"depth":82,"text":46,"children":1675},[1676,1677,1679,1681],{"id":53,"depth":88,"text":53},{"id":167,"depth":88,"text":1678},"join 等待线程",{"id":193,"depth":88,"text":1680},"move 闭包",{"id":230,"depth":88,"text":230},{"id":280,"depth":82,"text":281,"children":1683},[1684,1685],{"id":287,"depth":88,"text":287},{"id":376,"depth":88,"text":376},{"id":443,"depth":82,"text":444,"children":1687},[1688,1690,1692,1694,1695],{"id":450,"depth":88,"text":1689},"Mutex\u003CT>：互斥锁",{"id":538,"depth":88,"text":1691},"Arc\u003CT> 多线程所有权共享",{"id":660,"depth":88,"text":1693},"RwLock\u003CT>：读写锁",{"id":738,"depth":88,"text":738},{"id":838,"depth":88,"text":838},{"id":866,"depth":82,"text":1697,"children":1698},"9.4 Send 与 Sync trait",[1699,1700,1701],{"id":879,"depth":88,"text":30},{"id":918,"depth":88,"text":34},{"id":980,"depth":88,"text":1702},"自动实现与手动 unsafe",{"id":1000,"depth":82,"text":1001,"children":1704},[1705,1707,1709,1711,1713,1715,1716,1718,1720],{"id":1023,"depth":88,"text":1706},"Future trait",{"id":1072,"depth":88,"text":1708},"async 块与函数",{"id":1120,"depth":88,"text":1710},"执行器与 .await",{"id":1194,"depth":88,"text":1712},"async move 块",{"id":1235,"depth":88,"text":1714},"异步任务：tokio::spawn",{"id":1284,"depth":88,"text":1285},{"id":1348,"depth":88,"text":1717},"异步 trait 与 async_trait",{"id":1461,"depth":88,"text":1719},"Stream：异步迭代器",{"id":1534,"depth":88,"text":1534},{"id":1606,"depth":82,"text":1606},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fend\u002FRust\u002Fasync","knowledge\u002Fknowledge\u002Fbooklet\u002Fend\u002FRust\u002Fasync.md","md",{"items":1727},[1728,1732,1736,1740,1744,1748],{"path":1729,"title":1730,"description":1731,"category":10,"score":107},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fdocs","第八章：测试、文档与质量","Rust 将测试和文档视为语言的一等公民。通过内置的测试框架，你可以在项目里编写单元测试、集成测试以及随文档一起运行的示例测试，三者共用 cargo test 命令。配合 cargo doc 生成文档，形成了一套确保代码质量与可维护性…",{"path":1733,"title":1734,"description":1735,"category":10,"score":107},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Ft","泛型与 Trait","泛型和 trait 是 Rust 实现代码复用与多态的两大支柱。前置：Rust 基础。泛型让代码可以工作在多种类型上而不牺牲性能，trait 定义了类型间的共享行为，二者结合形成了零成本抽象的强大表达能力。本章将深入泛型定义、trai…",{"path":1737,"title":1738,"description":1739,"category":10,"score":107},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Ftype","第二章：基础语法与类型","Rust 的类型系统和语法设计处处体现着“安全”与“显式”的理念。这一章你将掌握变量绑定、基本类型、复合类型、函数定义以及所有基础控制流结构，它们是你写出任何 Rust 程序的基石。",{"path":1741,"title":1742,"description":1743,"category":10,"score":107},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fpackage","第七章：模块系统与包管理","Rust 的模块系统为代码组织、封装和复用提供了一套严谨但灵活的机制。包、crate、模块以及 use 路径相互配合，让你能够把项目拆解成清晰的功能单元，同时精确控制哪些对外可见。本章将带你系统掌握这些构建大型 Rust 项目所必需的…",{"path":1745,"title":1746,"description":1747,"category":10,"score":107},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fother","第十章：进阶特性与模式","Rust 的核心安全保证覆盖了绝大多数日常编程场景。但当你需要打破常规——无论是编写极致通用的抽象、与 C 库交互，还是内联优化——本章将带你进入 Rust 的深层能力：声明宏与过程宏、unsafe 的超能力与封装、高级类型系统技巧…",{"path":1749,"title":1750,"description":1751,"category":10,"score":107},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Ferror","第五章：错误处理","Rust 将错误明确分为两类：不可恢复的错误与可恢复的错误。通过 panic! 处理前一种，Result 处理后一种，这让程序的错误路径不再是隐式的控制流，而是强类型、必须处理的代码分支。配合 Option 对缺失值的处理以及丰富的组…",{"series":1753,"title":12,"items":1754,"index":1780,"prev":1781,"next":1782},"booklet\u002Fend\u002Frust",[1755,1756,1760,1764,1768,1770,1772,1774,1776,1778],{"path":7,"title":8,"date":14,"pinned":15},{"path":1757,"title":1758,"date":1759,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fbase","Rust 基础","2020-07-21",{"path":1761,"title":1762,"date":1763,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fcore","第三章：所有权、借用与生命周期（核心）","2023-05-09",{"path":1765,"title":1766,"date":1767,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Frust\u002Fdata-type","第四章：复合数据类型","2021-02-24",{"path":1729,"title":1730,"date":1769,"pinned":15},"2026-01-11",{"path":1749,"title":1750,"date":1771,"pinned":15},"2023-11-03",{"path":1745,"title":1746,"date":1773,"pinned":15},"2023-12-29",{"path":1741,"title":1742,"date":1775,"pinned":15},"2024-05-26",{"path":1733,"title":1734,"date":1777,"pinned":15},"2024-10-31",{"path":1737,"title":1738,"date":1779,"pinned":15},"2024-08-31",0,null,{"path":1757,"title":1758,"date":1759,"pinned":15}]