[{"data":1,"prerenderedAt":3012},["ShallowReactive",2],{"page-\u002Frust\u002F19-smart-pointers":3},{"id":4,"title":5,"body":6,"description":35,"extension":3006,"meta":3007,"navigation":110,"path":3008,"seo":3009,"stem":3010,"__hash__":3011},"content\u002Frust\u002F19-smart-pointers.md","19 — Smart Pointers",{"type":7,"value":8,"toc":2969},"minimark",[9,13,196,282,376,445,522,799,872,1099,1251,1351,1443,1567,1917,2006,2091,2190,2263,2380,2604,2965],[10,11,5],"h1",{"id":12},"_19-smart-pointers",[14,15,17,27,97,146],"question-wrapper",{"language":16},"rust",[18,19,21,22,26],"h3",{"id":20},"q1-what-problem-does-boxt-primarily-solve-for-a-type-like-this","Q1. What problem does ",[23,24,25],"code",{},"Box\u003CT>"," primarily solve for a type like this?",[28,29,30],"code-wrapper",{"language":16},[31,32,36],"pre",{"className":33,"code":34,"language":16,"meta":35,"style":35},"language-rust shiki shiki-themes github-light github-dark","enum List {\n    Cons(i32, Box\u003CList>),\n    Nil,\n}\n","",[23,37,38,55,82,91],{"__ignoreMap":35},[39,40,43,47,51],"span",{"class":41,"line":42},"line",1,[39,44,46],{"class":45},"svdQ7","enum",[39,48,50],{"class":49},"sIsaT"," List",[39,52,54],{"class":53},"ssxIu"," {\n",[39,56,58,61,64,67,70,73,76,79],{"class":41,"line":57},2,[39,59,60],{"class":49},"    Cons",[39,62,63],{"class":53},"(",[39,65,66],{"class":49},"i32",[39,68,69],{"class":53},", ",[39,71,72],{"class":49},"Box",[39,74,75],{"class":53},"\u003C",[39,77,78],{"class":49},"List",[39,80,81],{"class":53},">),\n",[39,83,85,88],{"class":41,"line":84},3,[39,86,87],{"class":49},"    Nil",[39,89,90],{"class":53},",\n",[39,92,94],{"class":41,"line":93},4,[39,95,96],{"class":53},"}\n",[98,99,102,119,128,134],"ul",{"className":100},[101],"contains-task-list",[103,104,107,112,113,115,116],"li",{"className":105},[106],"task-list-item",[108,109],"input",{"disabled":110,"type":111},true,"checkbox"," It makes ",[23,114,78],{}," implement ",[23,117,118],{},"Copy",[103,120,122,124,125,127],{"className":121},[106],[108,123],{"disabled":110,"type":111}," It gives ",[23,126,78],{}," a known, fixed size at compile time by putting the recursive part on the heap",[103,129,131,133],{"className":130},[106],[108,132],{"disabled":110,"type":111}," It makes the enum thread-safe",[103,135,137,139,140,143,144],{"className":136},[106],[108,138],{"disabled":110,"type":111}," It automatically derives ",[23,141,142],{},"Clone"," for ",[23,145,78],{},[147,148,149,153,163],"details",{},[150,151,152],"summary",{},"Show Answer",[154,155,156,160,161,127],"p",{},[157,158,159],"strong",{},"Answer:"," B — It gives ",[23,162,78],{},[154,164,165,168,169,171,172,174,175,178,179,182,183,186,187,189,190,192,193,195],{},[157,166,167],{},"Explanation:"," Without indirection, ",[23,170,78],{}," would need to contain a ",[23,173,78],{}," inline, giving it infinite size — the compiler cannot compute ",[23,176,177],{},"size_of::\u003CList>()",". ",[23,180,181],{},"Box\u003CList>"," stores a single pointer-sized value (the heap address) inline instead, so the enum's size is fixed regardless of how deep the list grows. ",[157,184,185],{},"Safety",": this is a compile-time size problem, not a runtime one — code with an unboxed recursive variant is rejected before it ever runs. It has nothing to do with ",[23,188,118],{},", thread safety, or ",[23,191,142],{},", none of which ",[23,194,72],{}," grants automatically.",[14,197,198,206,238],{},[18,199,201,202,205],{"id":200},"q2-what-is-rct-used-for","Q2. What is ",[23,203,204],{},"Rc\u003CT>"," used for?",[98,207,209,215,221,227],{"className":208},[101],[103,210,212,214],{"className":211},[106],[108,213],{"disabled":110,"type":111}," Enabling shared ownership of heap data within a single thread via reference counting",[103,216,218,220],{"className":217},[106],[108,219],{"disabled":110,"type":111}," Enabling shared mutable access across threads",[103,222,224,226],{"className":223},[106],[108,225],{"disabled":110,"type":111}," Automatic garbage collection of cyclic data structures",[103,228,230,232,233,235,236],{"className":229},[106],[108,231],{"disabled":110,"type":111}," Making a type ",[23,234,118],{}," instead of ",[23,237,142],{},[147,239,240,242,247],{},[150,241,152],{},[154,243,244,246],{},[157,245,159],{}," A — Enabling shared ownership of heap data within a single thread via reference counting",[154,248,249,251,252,254,255,258,259,261,262,264,265,268,269,272,273,275,276,278,279,281],{},[157,250,167],{}," ",[23,253,204],{}," (\"reference counted\") lets multiple owners share the same heap allocation; each ",[23,256,257],{},"clone()"," bumps a counter, and the value is dropped once the count reaches zero. ",[157,260,185],{},": ",[23,263,204],{},"'s counter increments are not atomic, so it is neither ",[23,266,267],{},"Send"," nor ",[23,270,271],{},"Sync"," — sharing one across threads is a compile error, which rules out B. It does not collect cycles (rules out C, see the leak question later in this file), and it does not affect ",[23,274,118],{},"\u002F",[23,277,142],{}," derivation semantics beyond providing its own cheap ",[23,280,142],{}," impl.",[14,283,284,296,336],{},[18,285,287,288,291,292,295],{"id":286},"q3-given-let-b-rcclonea-what-is-idiomatic-about-writing-it-this-way-instead-of-let-b-aclone","Q3. Given ",[23,289,290],{},"let b = Rc::clone(&a);",", what is idiomatic about writing it this way instead of ",[23,293,294],{},"let b = a.clone();","?",[98,297,299,308,314,323],{"className":298},[101],[103,300,302,251,304,307],{"className":301},[106],[108,303],{"disabled":110,"type":111},[23,305,306],{},"Rc::clone"," is faster because it skips the reference count",[103,309,311,313],{"className":310},[106],[108,312],{"disabled":110,"type":111}," Nothing — they are different operations with different results",[103,315,317,251,319,322],{"className":316},[106],[108,318],{"disabled":110,"type":111},[23,320,321],{},"Rc::clone(&a)"," makes it visually clear at the call site that this is a cheap pointer\u002Frefcount clone, not a deep data clone",[103,324,326,251,328,331,332,335],{"className":325},[106],[108,327],{"disabled":110,"type":111},[23,329,330],{},"a.clone()"," would move ",[23,333,334],{},"a"," instead of borrowing it",[147,337,338,340,347],{},[150,339,152],{},[154,341,342,344,345,322],{},[157,343,159],{}," C — ",[23,346,321],{},[154,348,349,351,352,354,355,358,359,361,362,365,366,368,369,372,373,375],{},[157,350,167],{}," Both calls do exactly the same thing — increment the strong count and return a new ",[23,353,204],{}," pointing at the same allocation. ",[157,356,357],{},"Idiom",": Rust style favors ",[23,360,321],{}," as documentation-by-convention, distinguishing \"cheap, shared-ownership clone\" from a ",[23,363,364],{},"T::clone()"," that might be an expensive deep copy. It's purely a readability convention, not a performance difference (rules out A), the operations are identical (rules out B), and ",[23,367,330],{}," takes ",[23,370,371],{},"&self"," so it borrows, it never moves ",[23,374,334],{}," (rules out D).",[14,377,378,385,422],{},[18,379,381,382,384],{"id":380},"q4-when-does-the-value-inside-an-rct-actually-get-dropped","Q4. When does the value inside an ",[23,383,204],{}," actually get dropped?",[98,386,388,398,404,413],{"className":387},[101],[103,389,391,393,394,397],{"className":390},[106],[108,392],{"disabled":110,"type":111}," As soon as any single ",[23,395,396],{},"Rc"," handle to it goes out of scope",[103,399,401,403],{"className":400},[106],[108,402],{"disabled":110,"type":111}," Only when the strong count drops to zero",[103,405,407,409,410,412],{"className":406},[106],[108,408],{"disabled":110,"type":111}," Immediately when ",[23,411,306],{}," is called",[103,414,416,418,419,421],{"className":415},[106],[108,417],{"disabled":110,"type":111}," Never — ",[23,420,396],{}," values are leaked by design",[147,423,424,426,431],{},[150,425,152],{},[154,427,428,430],{},[157,429,159],{}," B — Only when the strong count drops to zero",[154,432,433,435,436,438,439,441,442,444],{},[157,434,167],{}," Every ",[23,437,396],{}," clone increments a shared strong count; dropping any one handle decrements it, and the inner value's destructor only runs when that count hits zero. A is the tempting-but-wrong beginner assumption — it confuses \"one handle drops\" with \"the value drops,\" which only coincide when there was exactly one owner left. ",[23,440,306],{}," increments, it never triggers a drop (rules out C), and ",[23,443,396],{}," values are reclaimed normally (rules out D) — unless a reference cycle prevents the count from ever reaching zero, which is a separate leak scenario covered later.",[14,446,447,459,490],{},[18,448,450,451,454,455,458],{"id":449},"q5-what-does-refcellt-provide-that-a-plain-t-behind-a-shared-reference-does-not","Q5. What does ",[23,452,453],{},"RefCell\u003CT>"," provide that a plain ",[23,456,457],{},"T"," behind a shared reference does not?",[98,460,462,468,478,484],{"className":461},[101],[103,463,465,467],{"className":464},[106],[108,466],{"disabled":110,"type":111}," Compile-time enforcement of Rust's borrow rules, just faster",[103,469,471,473,474,477],{"className":470},[106],[108,472],{"disabled":110,"type":111}," Interior mutability — the ability to mutate data through a shared (",[23,475,476],{},"&",") reference, with borrow rules checked at runtime instead of compile time",[103,479,481,483],{"className":480},[106],[108,482],{"disabled":110,"type":111}," Thread-safe mutability across multiple threads",[103,485,487,489],{"className":486},[106],[108,488],{"disabled":110,"type":111}," Automatic synchronization equivalent to a mutex",[147,491,492,494,501],{},[150,493,152],{},[154,495,496,498,499,477],{},[157,497,159],{}," B — Interior mutability — the ability to mutate data through a shared (",[23,500,476],{},[154,502,503,251,505,507,508,511,512,515,516,518,519,521],{},[157,504,167],{},[23,506,453],{}," moves Rust's \"one mutable borrow XOR many shared borrows\" rule from compile time to runtime: ",[23,509,510],{},"borrow()"," and ",[23,513,514],{},"borrow_mut()"," track active borrows and panic if violated. ",[157,517,185],{},": this trades a compile error for a runtime panic — it does not weaken the rule, it just enforces it later. It is single-threaded only (no ",[23,520,271],{}," for its guards in the way a mutex provides), so it is not a threading primitive (rules out C and D), and it is strictly runtime checking, not a faster compile-time check (rules out A).",[14,523,524,528,705,750],{"language":16},[18,525,527],{"id":526},"q6-why-does-this-code-fail-to-compile","Q6. Why does this code fail to compile?",[28,529,530],{"language":16},[31,531,533],{"className":33,"code":532,"language":16,"meta":35,"style":35},"use std::rc::Rc;\nuse std::thread;\n\nfn main() {\n    let data = Rc::new(vec![1, 2, 3]);\n    let handle = thread::spawn(move || {\n        println!(\"{:?}\", data);\n    });\n    handle.join().unwrap();\n}\n",[23,534,535,556,567,572,583,628,656,671,677,700],{"__ignoreMap":35},[39,536,537,540,543,546,549,551,553],{"class":41,"line":42},[39,538,539],{"class":45},"use",[39,541,542],{"class":49}," std",[39,544,545],{"class":45},"::",[39,547,548],{"class":49},"rc",[39,550,545],{"class":45},[39,552,396],{"class":49},[39,554,555],{"class":53},";\n",[39,557,558,560,562,564],{"class":41,"line":57},[39,559,539],{"class":45},[39,561,542],{"class":49},[39,563,545],{"class":45},[39,565,566],{"class":53},"thread;\n",[39,568,569],{"class":41,"line":84},[39,570,571],{"emptyLinePlaceholder":110},"\n",[39,573,574,577,580],{"class":41,"line":93},[39,575,576],{"class":45},"fn",[39,578,579],{"class":49}," main",[39,581,582],{"class":53},"() {\n",[39,584,586,589,592,595,598,600,603,605,608,611,615,617,620,622,625],{"class":41,"line":585},5,[39,587,588],{"class":45},"    let",[39,590,591],{"class":53}," data ",[39,593,594],{"class":45},"=",[39,596,597],{"class":49}," Rc",[39,599,545],{"class":45},[39,601,602],{"class":49},"new",[39,604,63],{"class":53},[39,606,607],{"class":49},"vec!",[39,609,610],{"class":53},"[",[39,612,614],{"class":613},"snvgF","1",[39,616,69],{"class":53},[39,618,619],{"class":613},"2",[39,621,69],{"class":53},[39,623,624],{"class":613},"3",[39,626,627],{"class":53},"]);\n",[39,629,631,633,636,638,641,643,646,648,651,654],{"class":41,"line":630},6,[39,632,588],{"class":45},[39,634,635],{"class":53}," handle ",[39,637,594],{"class":45},[39,639,640],{"class":49}," thread",[39,642,545],{"class":45},[39,644,645],{"class":49},"spawn",[39,647,63],{"class":53},[39,649,650],{"class":45},"move",[39,652,653],{"class":45}," ||",[39,655,54],{"class":53},[39,657,659,662,664,668],{"class":41,"line":658},7,[39,660,661],{"class":49},"        println!",[39,663,63],{"class":53},[39,665,667],{"class":666},"sJ6F3","\"{:?}\"",[39,669,670],{"class":53},", data);\n",[39,672,674],{"class":41,"line":673},8,[39,675,676],{"class":53},"    });\n",[39,678,680,683,686,689,692,694,697],{"class":41,"line":679},9,[39,681,682],{"class":53},"    handle",[39,684,685],{"class":45},".",[39,687,688],{"class":49},"join",[39,690,691],{"class":53},"()",[39,693,685],{"class":45},[39,695,696],{"class":49},"unwrap",[39,698,699],{"class":53},"();\n",[39,701,703],{"class":41,"line":702},10,[39,704,96],{"class":53},[98,706,708,717,728,741],{"className":707},[101],[103,709,711,251,713,716],{"className":710},[106],[108,712],{"disabled":110,"type":111},[23,714,715],{},"Vec\u003Ci32>"," cannot be sent between threads",[103,718,720,251,722,724,725,727],{"className":719},[106],[108,721],{"disabled":110,"type":111},[23,723,204],{}," does not implement ",[23,726,267],{},", because its non-atomic refcount would cause a data race if incremented from multiple threads",[103,729,731,251,733,736,737,740],{"className":730},[106],[108,732],{"disabled":110,"type":111},[23,734,735],{},"thread::spawn"," requires a ",[23,738,739],{},"'static"," closure and this one isn't",[103,742,744,251,746,749],{"className":743},[106],[108,745],{"disabled":110,"type":111},[23,747,748],{},"println!"," cannot be used inside a spawned thread",[147,751,752,754,763],{},[150,753,152],{},[154,755,756,758,759,724,761,727],{},[157,757,159],{}," B — ",[23,760,204],{},[23,762,267],{},[154,764,765,251,767,769,770,275,772,143,774,776,777,780,781,783,784,786,787,789,790,793,794,796,797,685],{},[157,766,167],{},[23,768,204],{},"'s clone\u002Fdrop increments and decrements a plain (non-atomic) counter; if two threads did that concurrently it would be a data race, so the standard library simply withholds ",[23,771,267],{},[23,773,271],{},[23,775,204],{}," and the compiler rejects moving it into another thread. The fix is ",[23,778,779],{},"Arc\u003CT>",", which uses atomic operations for its counters. ",[23,782,715],{}," itself is perfectly ",[23,785,267],{}," (rules out A), the closure is ",[23,788,739],{}," here since ",[23,791,792],{},"data"," is moved in and owns its data (rules out C), and ",[23,795,748],{}," is fine inside threads (rules out D) — the error is specifically about ",[23,798,396],{},[14,800,801,809,838],{},[18,802,804,805,808],{"id":803},"q7-what-is-boxdyn-trait-primarily-used-for","Q7. What is ",[23,806,807],{},"Box\u003Cdyn Trait>"," primarily used for?",[98,810,812,818,824,832],{"className":811},[101],[103,813,815,817],{"className":814},[106],[108,816],{"disabled":110,"type":111}," Storing a trait object with a size known only at runtime, enabling dynamic dispatch through a heap-allocated pointer",[103,819,821,823],{"className":820},[106],[108,822],{"disabled":110,"type":111}," Making a trait's methods run faster via static dispatch",[103,825,827,829,830],{"className":826},[106],[108,828],{"disabled":110,"type":111}," Automatically implementing the trait for ",[23,831,72],{},[103,833,835,837],{"className":834},[106],[108,836],{"disabled":110,"type":111}," Sharing ownership of a trait object across threads",[147,839,840,842,847],{},[150,841,152],{},[154,843,844,846],{},[157,845,159],{}," A — Storing a trait object with a size known only at runtime, enabling dynamic dispatch through a heap-allocated pointer",[154,848,849,251,851,854,855,857,858,861,862,864,865,868,869,871],{},[157,850,167],{},[23,852,853],{},"dyn Trait"," is unsized (different implementors have different sizes), so it can't be stored by value; ",[23,856,807],{}," gives it a fixed-size, heap-allocated home and dispatches method calls through a vtable at runtime. That's the opposite of static dispatch — ",[23,859,860],{},"dyn"," implies dynamic dispatch, which is typically slightly slower than monomorphized generics, not faster (rules out B). ",[23,863,72],{}," doesn't implement the trait itself, it just stores something that does (rules out C), and ownership sharing across threads is ",[23,866,867],{},"Arc\u003Cdyn Trait + Send + Sync>","'s job, not plain ",[23,870,72],{},"'s (rules out D).",[14,873,874,878,997,1042],{"language":16},[18,875,877],{"id":876},"q8-what-happens-when-this-code-runs","Q8. What happens when this code runs?",[28,879,880],{"language":16},[31,881,883],{"className":33,"code":882,"language":16,"meta":35,"style":35},"use std::cell::RefCell;\n\nfn main() {\n    let cell = RefCell::new(5);\n    let _b1 = cell.borrow_mut();\n    let _b2 = cell.borrow_mut();\n    println!(\"{}\", *_b1);\n}\n",[23,884,885,903,907,915,939,958,975,993],{"__ignoreMap":35},[39,886,887,889,891,893,896,898,901],{"class":41,"line":42},[39,888,539],{"class":45},[39,890,542],{"class":49},[39,892,545],{"class":45},[39,894,895],{"class":49},"cell",[39,897,545],{"class":45},[39,899,900],{"class":49},"RefCell",[39,902,555],{"class":53},[39,904,905],{"class":41,"line":57},[39,906,571],{"emptyLinePlaceholder":110},[39,908,909,911,913],{"class":41,"line":84},[39,910,576],{"class":45},[39,912,579],{"class":49},[39,914,582],{"class":53},[39,916,917,919,922,924,927,929,931,933,936],{"class":41,"line":93},[39,918,588],{"class":45},[39,920,921],{"class":53}," cell ",[39,923,594],{"class":45},[39,925,926],{"class":49}," RefCell",[39,928,545],{"class":45},[39,930,602],{"class":49},[39,932,63],{"class":53},[39,934,935],{"class":613},"5",[39,937,938],{"class":53},");\n",[39,940,941,943,946,948,951,953,956],{"class":41,"line":585},[39,942,588],{"class":45},[39,944,945],{"class":53}," _b1 ",[39,947,594],{"class":45},[39,949,950],{"class":53}," cell",[39,952,685],{"class":45},[39,954,955],{"class":49},"borrow_mut",[39,957,699],{"class":53},[39,959,960,962,965,967,969,971,973],{"class":41,"line":630},[39,961,588],{"class":45},[39,963,964],{"class":53}," _b2 ",[39,966,594],{"class":45},[39,968,950],{"class":53},[39,970,685],{"class":45},[39,972,955],{"class":49},[39,974,699],{"class":53},[39,976,977,980,982,985,987,990],{"class":41,"line":658},[39,978,979],{"class":49},"    println!",[39,981,63],{"class":53},[39,983,984],{"class":666},"\"{}\"",[39,986,69],{"class":53},[39,988,989],{"class":45},"*",[39,991,992],{"class":53},"_b1);\n",[39,994,995],{"class":41,"line":673},[39,996,96],{"class":53},[98,998,1000,1012,1021,1033],{"className":999},[101],[103,1001,1003,1005,1006,1008,1009,1011],{"className":1002},[106],[108,1004],{"disabled":110,"type":111}," It prints ",[23,1007,935],{}," — ",[23,1010,900],{}," allows nested mutable borrows within the same scope",[103,1013,1015,1017,1018,1020],{"className":1014},[106],[108,1016],{"disabled":110,"type":111}," It panics at the second ",[23,1019,514],{}," call with \"already borrowed: BorrowMutError\"",[103,1022,1024,1026,1027,1029,1030],{"className":1023},[106],[108,1025],{"disabled":110,"type":111}," It fails to compile because ",[23,1028,900],{}," requires ",[23,1031,1032],{},"unsafe",[103,1034,1036,1038,1039],{"className":1035},[106],[108,1037],{"disabled":110,"type":111}," It silently returns a stale value for ",[23,1040,1041],{},"_b2",[147,1043,1044,1046,1053],{},[150,1045,152],{},[154,1047,1048,1050,1051,1020],{},[157,1049,159],{}," B — It panics at the second ",[23,1052,514],{},[154,1054,1055,251,1057,1060,1061,1064,1065,1067,1068,1070,1071,1073,1074,1076,1077,1080,1081,1083,1084,1087,1088,1091,1092,1095,1096,1098],{},[157,1056,167],{},[23,1058,1059],{},"_b1"," is a live ",[23,1062,1063],{},"RefMut"," guard that isn't dropped before ",[23,1066,1041],{}," is requested, so ",[23,1069,895],{}," already has one active mutable borrow when the second ",[23,1072,514],{}," runs; ",[23,1075,900],{}," enforces exclusivity at runtime and panics rather than allowing the second borrow. ",[157,1078,1079],{},"Debug",": the correct fix is to drop ",[23,1082,1059],{}," (e.g., wrap it in its own block, or call ",[23,1085,1086],{},"drop(_b1)",") before taking the next borrow, or to use ",[23,1089,1090],{},"try_borrow_mut()"," and handle the ",[23,1093,1094],{},"Err"," case instead of unwrapping blindly. This compiles fine (rules out C) — the whole point of ",[23,1097,900],{}," is that these checks happen at runtime, not compile time — and there is no silent stale-data behavior (rules out D); the panic is loud and immediate.",[14,1100,1101,1115,1186,1217],{"language":16},[18,1102,1104,1105,1108,1109,1111,1112,1114],{"id":1103},"q9-this-code-builds-a-parent-child-tree-using-rcrefcellnode-where-each-parent-also-stores-an-rc-back-to-its-child-and-each-child-stores-an-rc-back-to-its-parent-what-is-the-consequence","Q9. This code builds a parent-child tree using ",[23,1106,1107],{},"Rc\u003CRefCell\u003CNode>>"," where each parent also stores an ",[23,1110,396],{}," back to its child, and each child stores an ",[23,1113,396],{}," back to its parent. What is the consequence?",[28,1116,1117],{"language":16},[31,1118,1120],{"className":33,"code":1119,"language":16,"meta":35,"style":35},"struct Node {\n    parent: RefCell\u003COption\u003CRc\u003CNode>>>,\n    child: RefCell\u003COption\u003CRc\u003CNode>>>,\n}\n",[23,1121,1122,1132,1159,1182],{"__ignoreMap":35},[39,1123,1124,1127,1130],{"class":41,"line":42},[39,1125,1126],{"class":45},"struct",[39,1128,1129],{"class":49}," Node",[39,1131,54],{"class":53},[39,1133,1134,1137,1140,1142,1144,1147,1149,1151,1153,1156],{"class":41,"line":57},[39,1135,1136],{"class":53},"    parent",[39,1138,1139],{"class":45},":",[39,1141,926],{"class":49},[39,1143,75],{"class":53},[39,1145,1146],{"class":49},"Option",[39,1148,75],{"class":53},[39,1150,396],{"class":49},[39,1152,75],{"class":53},[39,1154,1155],{"class":49},"Node",[39,1157,1158],{"class":53},">>>,\n",[39,1160,1161,1164,1166,1168,1170,1172,1174,1176,1178,1180],{"class":41,"line":84},[39,1162,1163],{"class":53},"    child",[39,1165,1139],{"class":45},[39,1167,926],{"class":49},[39,1169,75],{"class":53},[39,1171,1146],{"class":49},[39,1173,75],{"class":53},[39,1175,396],{"class":49},[39,1177,75],{"class":53},[39,1179,1155],{"class":49},[39,1181,1158],{"class":53},[39,1183,1184],{"class":41,"line":93},[39,1185,96],{"class":53},[98,1187,1189,1195,1201,1211],{"className":1188},[101],[103,1190,1192,1194],{"className":1191},[106],[108,1193],{"disabled":110,"type":111}," The program fails to compile because Rust detects the cycle",[103,1196,1198,1200],{"className":1197},[106],[108,1199],{"disabled":110,"type":111}," The program panics at runtime with a stack overflow when dropped",[103,1202,1204,1206,1207,1210],{"className":1203},[106],[108,1205],{"disabled":110,"type":111}," Both nodes leak memory — their strong counts never reach zero, so ",[23,1208,1209],{},"Drop"," never runs, even though nothing is UB",[103,1212,1214,1216],{"className":1213},[106],[108,1215],{"disabled":110,"type":111}," Rust's garbage collector silently reclaims the cycle at the next allocation",[147,1218,1219,1221,1228],{},[150,1220,152],{},[154,1222,1223,1225,1226,1210],{},[157,1224,159],{}," C — Both nodes leak memory — their strong counts never reach zero, so ",[23,1227,1209],{},[154,1229,1230,1232,1233,1235,1236,1238,1239,1241,1242,1244,1245,1248,1249,685],{},[157,1231,167],{}," Parent holds a strong ",[23,1234,396],{}," to child and child holds a strong ",[23,1237,396],{}," back to parent, so each keeps the other's strong count above zero forever; once external references go out of scope, both nodes become unreachable garbage that will never be freed. ",[157,1240,185],{},": this is a memory leak, not undefined behavior — Rust's ownership model guarantees memory safety (no dangling pointers, no double frees) but does not guarantee the absence of leaks, and reference cycles are the classic way to produce one. The compiler has no cycle detector for ",[23,1243,396],{}," graphs (rules out A), there's no stack overflow or panic involved in the leak itself (rules out B), and Rust has no garbage collector to sweep up cycles (rules out D). The idiomatic fix is to make the parent link a ",[23,1246,1247],{},"Weak\u003CNode>"," instead of a strong ",[23,1250,396],{},[14,1252,1253,1275,1309],{},[18,1254,1256,1257,1260,1261,1264,1265,1268,1269,1271,1272,1274],{"id":1255},"q10-weakt-is-obtained-via-rcdowngraderc-what-does-calling-upgrade-on-a-weakt-return-once-every-strong-rc-to-the-value-has-been-dropped","Q10. ",[23,1258,1259],{},"Weak\u003CT>"," is obtained via ",[23,1262,1263],{},"Rc::downgrade(&rc)",". What does calling ",[23,1266,1267],{},".upgrade()"," on a ",[23,1270,1259],{}," return once every strong ",[23,1273,396],{}," to the value has been dropped?",[98,1276,1278,1286,1295,1301],{"className":1277},[101],[103,1279,1281,251,1283,1285],{"className":1280},[106],[108,1282],{"disabled":110,"type":111},[23,1284,204],{}," pointing to freed memory (undefined behavior)",[103,1287,1289,251,1291,1294],{"className":1288},[106],[108,1290],{"disabled":110,"type":111},[23,1292,1293],{},"None",", safely indicating the value no longer exists",[103,1296,1298,1300],{"className":1297},[106],[108,1299],{"disabled":110,"type":111}," A panic",[103,1302,1304,1306,1307],{"className":1303},[106],[108,1305],{"disabled":110,"type":111}," A default-constructed ",[23,1308,457],{},[147,1310,1311,1313,1319],{},[150,1312,152],{},[154,1314,1315,758,1317,1294],{},[157,1316,159],{},[23,1318,1293],{},[154,1320,1321,251,1323,1326,1327,1330,1331,1334,1335,1008,1337,1340,1341,1343,1344,1347,1348,1350],{},[157,1322,167],{},[23,1324,1325],{},"Weak\u003CT>::upgrade()"," returns ",[23,1328,1329],{},"Option\u003CRc\u003CT>>",": if the strong count is still above zero it bumps it and returns ",[23,1332,1333],{},"Some(rc)",", and if the value has already been dropped it returns ",[23,1336,1293],{},[23,1338,1339],{},"Weak"," never lets you touch freed memory. This is exactly why ",[23,1342,1339],{}," is the standard tool for breaking parent\u002Fback-references in tree and graph structures without risking a dangling pointer (rules out A, which describes what would be UB in a language like C). There's no panic on upgrade (rules out C) and no requirement that ",[23,1345,1346],{},"T: Default"," (rules out D) — the ",[23,1349,1146],{}," return is the whole safety mechanism.",[14,1352,1353,1360,1395],{},[18,1354,1356,1357,295],{"id":1355},"q11-on-a-typical-64-bit-target-what-is-stdmemsize_ofrci32","Q11. On a typical 64-bit target, what is ",[23,1358,1359],{},"std::mem::size_of::\u003CRc\u003Ci32>>()",[98,1361,1363,1372,1381,1389],{"className":1362},[101],[103,1364,1366,1368,1369,1371],{"className":1365},[106],[108,1367],{"disabled":110,"type":111}," 8 bytes — ",[23,1370,204],{}," is just a pointer to a heap block that also holds the strong\u002Fweak counts",[103,1373,1375,1377,1378,1380],{"className":1374},[106],[108,1376],{"disabled":110,"type":111}," 24 bytes — the strong count, weak count, and value are all stored inline in the ",[23,1379,396],{}," handle",[103,1382,1384,1386,1387],{"className":1383},[106],[108,1385],{"disabled":110,"type":111}," 4 bytes — same as ",[23,1388,66],{},[103,1390,1392,1394],{"className":1391},[106],[108,1393],{"disabled":110,"type":111}," 16 bytes — one pointer plus one inline count",[147,1396,1397,1399,1406],{},[150,1398,152],{},[154,1400,1401,1403,1404,1371],{},[157,1402,159],{}," A — 8 bytes — ",[23,1405,204],{},[154,1407,1408,251,1410,1413,1414,1417,1418,1421,1422,1424,1425,178,1427,1430,1431,1433,1434,1436,1437,1439,1440,1442],{},[157,1409,167],{},[23,1411,1412],{},"Rc::new(v)"," allocates a single heap block containing an ",[23,1415,1416],{},"RcBox"," (strong count, weak count, and the value ",[23,1419,1420],{},"v"," together); the ",[23,1423,204],{}," handle you hold is just one pointer to that block, so it's a single pointer-sized value like ",[23,1426,25],{},[157,1428,1429],{},"Performance",": this is a common gotcha — people assume the counts live \"in the ",[23,1432,396],{},"\" and inflate its size, but they live on the heap alongside the data, which is also why cloning an ",[23,1435,396],{}," is cheap (copy one pointer, bump one heap-resident counter) rather than copying counts by value. B describes a design ",[23,1438,396],{}," doesn't use; C ignores that ",[23,1441,396],{}," is a pointer, not the value itself; D is a plausible-sounding but incorrect split.",[14,1444,1445,1455,1503],{},[18,1446,1448,1449,511,1452,295],{"id":1447},"q12-whats-the-difference-between-let-b2-boxnew42-let-b3-b2clone-and-let-r2-rcnew42-let-r3-rccloner2","Q12. What's the difference between ",[23,1450,1451],{},"let b2 = Box::new(42); let b3 = b2.clone();",[23,1453,1454],{},"let r2 = Rc::new(42); let r3 = Rc::clone(&r2);",[98,1456,1458,1464,1484,1492],{"className":1457},[101],[103,1459,1461,1463],{"className":1460},[106],[108,1462],{"disabled":110,"type":111}," No difference — both share the same heap allocation afterward",[103,1465,1467,251,1469,1472,1473,1476,1477,1479,1480,1483],{"className":1466},[106],[108,1468],{"disabled":110,"type":111},[23,1470,1471],{},"Box::clone"," performs a deep clone into a ",[1474,1475,602],"em",{}," heap allocation, while ",[23,1478,306],{}," shares the ",[1474,1481,1482],{},"same"," allocation and just bumps a refcount",[103,1485,1487,251,1489,1491],{"className":1486},[106],[108,1488],{"disabled":110,"type":111},[23,1490,72],{}," cannot be cloned at all",[103,1493,1495,251,1497,1499,1500,1502],{"className":1494},[106],[108,1496],{"disabled":110,"type":111},[23,1498,306],{}," performs a deep clone while ",[23,1501,1471],{}," shares the allocation",[147,1504,1505,1507,1519],{},[150,1506,152],{},[154,1508,1509,758,1511,1472,1513,1476,1515,1479,1517,1483],{},[157,1510,159],{},[23,1512,1471],{},[1474,1514,602],{},[23,1516,306],{},[1474,1518,1482],{},[154,1520,1521,251,1523,1525,1526,1528,1529,1532,1533,511,1536,1539,1540,1542,1543,1545,1546,1548,1549,1551,1552,1554,1555,1557,1558,1560,1561,1563,1564,1566],{},[157,1522,167],{},[23,1524,25],{}," implements single ownership, so its ",[23,1527,142],{}," impl (when ",[23,1530,1531],{},"T: Clone",") allocates a fresh block and copies the value into it — ",[23,1534,1535],{},"b2",[23,1537,1538],{},"b3"," end up as two independent ",[23,1541,66],{},"s on the heap. ",[23,1544,204],{},"'s ",[23,1547,142],{}," impl is the opposite: it does not touch the underlying ",[23,1550,457],{}," at all, it just increments the shared strong count and returns a handle to the ",[1474,1553,1482],{}," block. Assuming both behave like ",[23,1556,396],{}," (A) is the classic trap; ",[23,1559,25],{}," is ",[23,1562,142],{}," whenever ",[23,1565,1531],{}," (rules out C); D has the two exactly backwards.",[14,1568,1569,1573,1770,1831],{"language":16},[18,1570,1572],{"id":1571},"q13-what-causes-this-to-panic","Q13. What causes this to panic?",[28,1574,1575],{"language":16},[31,1576,1578],{"className":33,"code":1577,"language":16,"meta":35,"style":35},"use std::cell::RefCell;\n\nfn total(counts: &RefCell\u003CVec\u003Ci32>>) -> i32 {\n    let data = counts.borrow();\n    data.iter().sum()\n}\n\nfn add(counts: &RefCell\u003CVec\u003Ci32>>, n: i32) {\n    let mut data = counts.borrow_mut();\n    data.push(n);\n    println!(\"running total: {}\", total(counts));\n}\n",[23,1579,1580,1596,1600,1637,1655,1675,1679,1683,1716,1735,1747,1765],{"__ignoreMap":35},[39,1581,1582,1584,1586,1588,1590,1592,1594],{"class":41,"line":42},[39,1583,539],{"class":45},[39,1585,542],{"class":49},[39,1587,545],{"class":45},[39,1589,895],{"class":49},[39,1591,545],{"class":45},[39,1593,900],{"class":49},[39,1595,555],{"class":53},[39,1597,1598],{"class":41,"line":57},[39,1599,571],{"emptyLinePlaceholder":110},[39,1601,1602,1604,1607,1610,1612,1615,1617,1619,1622,1624,1626,1629,1632,1635],{"class":41,"line":84},[39,1603,576],{"class":45},[39,1605,1606],{"class":49}," total",[39,1608,1609],{"class":53},"(counts",[39,1611,1139],{"class":45},[39,1613,1614],{"class":45}," &",[39,1616,900],{"class":49},[39,1618,75],{"class":53},[39,1620,1621],{"class":49},"Vec",[39,1623,75],{"class":53},[39,1625,66],{"class":49},[39,1627,1628],{"class":53},">>) ",[39,1630,1631],{"class":45},"->",[39,1633,1634],{"class":49}," i32",[39,1636,54],{"class":53},[39,1638,1639,1641,1643,1645,1648,1650,1653],{"class":41,"line":93},[39,1640,588],{"class":45},[39,1642,591],{"class":53},[39,1644,594],{"class":45},[39,1646,1647],{"class":53}," counts",[39,1649,685],{"class":45},[39,1651,1652],{"class":49},"borrow",[39,1654,699],{"class":53},[39,1656,1657,1660,1662,1665,1667,1669,1672],{"class":41,"line":585},[39,1658,1659],{"class":53},"    data",[39,1661,685],{"class":45},[39,1663,1664],{"class":49},"iter",[39,1666,691],{"class":53},[39,1668,685],{"class":45},[39,1670,1671],{"class":49},"sum",[39,1673,1674],{"class":53},"()\n",[39,1676,1677],{"class":41,"line":630},[39,1678,96],{"class":53},[39,1680,1681],{"class":41,"line":658},[39,1682,571],{"emptyLinePlaceholder":110},[39,1684,1685,1687,1690,1692,1694,1696,1698,1700,1702,1704,1706,1709,1711,1713],{"class":41,"line":673},[39,1686,576],{"class":45},[39,1688,1689],{"class":49}," add",[39,1691,1609],{"class":53},[39,1693,1139],{"class":45},[39,1695,1614],{"class":45},[39,1697,900],{"class":49},[39,1699,75],{"class":53},[39,1701,1621],{"class":49},[39,1703,75],{"class":53},[39,1705,66],{"class":49},[39,1707,1708],{"class":53},">>, n",[39,1710,1139],{"class":45},[39,1712,1634],{"class":49},[39,1714,1715],{"class":53},") {\n",[39,1717,1718,1720,1723,1725,1727,1729,1731,1733],{"class":41,"line":679},[39,1719,588],{"class":45},[39,1721,1722],{"class":45}," mut",[39,1724,591],{"class":53},[39,1726,594],{"class":45},[39,1728,1647],{"class":53},[39,1730,685],{"class":45},[39,1732,955],{"class":49},[39,1734,699],{"class":53},[39,1736,1737,1739,1741,1744],{"class":41,"line":702},[39,1738,1659],{"class":53},[39,1740,685],{"class":45},[39,1742,1743],{"class":49},"push",[39,1745,1746],{"class":53},"(n);\n",[39,1748,1750,1752,1754,1757,1759,1762],{"class":41,"line":1749},11,[39,1751,979],{"class":49},[39,1753,63],{"class":53},[39,1755,1756],{"class":666},"\"running total: {}\"",[39,1758,69],{"class":53},[39,1760,1761],{"class":49},"total",[39,1763,1764],{"class":53},"(counts));\n",[39,1766,1768],{"class":41,"line":1767},12,[39,1769,96],{"class":53},[98,1771,1773,1785,1808,1819],{"className":1772},[101],[103,1774,1776,1778,1779,511,1781,1784],{"className":1775},[106],[108,1777],{"disabled":110,"type":111}," It never panics — ",[23,1780,1761],{},[23,1782,1783],{},"add"," are unrelated functions",[103,1786,1788,251,1790,1792,1793,1795,1796,1798,1799,1801,1802,1804,1805,1807],{"className":1787},[106],[108,1789],{"disabled":110,"type":111},[23,1791,1783],{}," holds a ",[23,1794,514],{}," guard (",[23,1797,792],{},") alive while calling ",[23,1800,1761],{},", which tries ",[23,1803,510],{}," on the same still-mutably-borrowed ",[23,1806,900],{},", panicking with \"already borrowed\"",[103,1809,1811,251,1813,1815,1816,1818],{"className":1810},[106],[108,1812],{"disabled":110,"type":111},[23,1814,1743],{}," inside a ",[23,1817,900],{}," is not allowed under any circumstances",[103,1820,1822,1026,1824,1827,1828],{"className":1821},[106],[108,1823],{"disabled":110,"type":111},[23,1825,1826],{},"RefCell\u003CVec\u003Ci32>>"," doesn't implement ",[23,1829,1830],{},"Iterator",[147,1832,1833,1835,1851],{},[150,1834,152],{},[154,1836,1837,758,1839,1792,1841,1795,1843,1798,1845,1801,1847,1804,1849,1807],{},[157,1838,159],{},[23,1840,1783],{},[23,1842,514],{},[23,1844,792],{},[23,1846,1761],{},[23,1848,510],{},[23,1850,900],{},[154,1852,1853,251,1855,1857,1858,1860,1861,1863,1864,1867,1868,1545,1870,1873,1874,178,1877,1879,1880,1882,1883,1886,1887,1890,1891,1893,1894,1896,1897,1899,1900,1902,1903,1906,1907,1909,1910,1913,1914,1916],{},[157,1854,167],{},[23,1856,792],{}," in ",[23,1859,1783],{}," is a ",[23,1862,1063],{}," that stays alive across the ",[23,1865,1866],{},"total(counts)"," call (it's used again afterward implicitly by scope, and even if it weren't, it hasn't been dropped yet), so ",[23,1869,1761],{},[23,1871,1872],{},"counts.borrow()"," runs while a mutable borrow is still outstanding — a runtime ",[23,1875,1876],{},"BorrowError",[157,1878,1079],{},": the fix is to drop or scope ",[23,1881,792],{}," before calling anything that might re-borrow ",[23,1884,1885],{},"counts",", e.g. ",[23,1888,1889],{},"{ let mut data = counts.borrow_mut(); data.push(n); }"," in its own block, then call ",[23,1892,1866],{}," afterward. This absolutely can panic despite the functions looking unrelated (rules out A) — that's exactly the gotcha; nothing bans ",[23,1895,1743],{}," through a ",[23,1898,900],{}," in general (rules out C); and the code compiles fine since ",[23,1901,1761],{}," only calls ",[23,1904,1905],{},".iter().sum()"," on the ",[23,1908,1621],{}," obtained via ",[23,1911,1912],{},"Deref",", not on the ",[23,1915,900],{}," itself (rules out D).",[14,1918,1919,1930,1965],{},[18,1920,1922,1923,1926,1927,1929],{"id":1921},"q14-what-is-the-effect-of-calling-droprc_handle-on-one-clone-of-an-rct-that-has-two-other-clones-still-alive-elsewhere","Q14. What is the effect of calling ",[23,1924,1925],{},"drop(rc_handle)"," on one clone of an ",[23,1928,204],{}," that has two other clones still alive elsewhere?",[98,1931,1933,1939,1948,1957],{"className":1932},[101],[103,1934,1936,1938],{"className":1935},[106],[108,1937],{"disabled":110,"type":111}," It immediately frees the underlying value and invalidates the other clones",[103,1940,1942,1944,1945,1947],{"className":1941},[106],[108,1943],{"disabled":110,"type":111}," It only decrements the strong count by one; the value stays alive because other ",[23,1946,396],{}," handles still reference it",[103,1949,1951,1953,1954,1956],{"className":1950},[106],[108,1952],{"disabled":110,"type":111}," It's a compile error — ",[23,1955,204],{}," cannot be manually dropped",[103,1958,1960,1962,1963],{"className":1959},[106],[108,1961],{"disabled":110,"type":111}," It converts the remaining handles into ",[23,1964,1259],{},[147,1966,1967,1969,1976],{},[150,1968,152],{},[154,1970,1971,1973,1974,1947],{},[157,1972,159],{}," B — It only decrements the strong count by one; the value stays alive because other ",[23,1975,396],{},[154,1977,1978,251,1980,1983,1984,1986,1987,1545,1989,1991,1992,1994,1995,1997,1998,2000,2001,2003,2004,375],{},[157,1979,167],{},[23,1981,1982],{},"drop"," on an ",[23,1985,396],{}," handle runs ",[23,1988,396],{},[23,1990,1209],{}," impl, which decrements the strong count and only deallocates the inner value when that count reaches zero. With two other live clones, the count merely goes from 3 to 2 and the data is untouched. A is the tempting mistake of treating ",[23,1993,396],{}," like ",[23,1996,72],{}," (single owner); ",[23,1999,204],{}," is a completely ordinary value that can be dropped like anything else, no special restriction exists (rules out C); and dropping one strong handle has zero effect on the type of the others — they remain ",[23,2002,204],{},", not ",[23,2005,1259],{},[14,2007,2008,2012,2044],{},[18,2009,2011],{"id":2010},"q15-for-a-struct-field-that-needs-to-be-owned-by-exactly-one-place-but-whose-size-isnt-known-until-runtime-eg-a-boxed-trait-object-or-a-recursive-variant-which-is-the-idiomatic-choice","Q15. For a struct field that needs to be owned by exactly one place but whose size isn't known until runtime (e.g., a boxed trait object or a recursive variant), which is the idiomatic choice?",[98,2013,2015,2022,2029,2036],{"className":2014},[101],[103,2016,2018,251,2020],{"className":2017},[106],[108,2019],{"disabled":110,"type":111},[23,2021,204],{},[103,2023,2025,251,2027],{"className":2024},[106],[108,2026],{"disabled":110,"type":111},[23,2028,25],{},[103,2030,2032,251,2034],{"className":2031},[106],[108,2033],{"disabled":110,"type":111},[23,2035,453],{},[103,2037,2039,251,2041],{"className":2038},[106],[108,2040],{"disabled":110,"type":111},[23,2042,2043],{},"Arc\u003CMutex\u003CT>>",[147,2045,2046,2048,2054],{},[150,2047,152],{},[154,2049,2050,758,2052],{},[157,2051,159],{},[23,2053,25],{},[154,2055,2056,251,2058,261,2060,2062,2063,2065,2066,2068,2069,2071,2072,2075,2076,2078,2079,275,2081,2084,2085,275,2087,2090],{},[157,2057,167],{},[157,2059,357],{},[23,2061,25],{}," is the minimal-overhead choice for \"one owner, heap-allocated, unsized-at-compile-time\" — no refcounting overhead, no runtime borrow checks, no atomics. Reaching for ",[23,2064,204],{}," (A) or ",[23,2067,2043],{}," (D) when you don't actually need shared ownership adds needless refcount\u002Flocking overhead and complexity; reaching for ",[23,2070,453],{}," (C) solves a mutability problem you don't have here (single ownership already gives you ",[23,2073,2074],{},"&mut"," access). The rule of thumb: start with ",[23,2077,72],{},", add ",[23,2080,396],{},[23,2082,2083],{},"Arc"," only when multiple owners are genuinely required, and add ",[23,2086,900],{},[23,2088,2089],{},"Mutex"," only when mutation through a shared reference is genuinely required.",[14,2092,2093,2100,2144],{},[18,2094,2096,2097,2099],{"id":2095},"q16-in-a-single-threaded-tree-structure-using-rcrefcellnode-for-parentchild-links-what-is-the-idiomatic-way-to-prevent-the-reference-cycle-leak-described-earlier","Q16. In a single-threaded tree structure using ",[23,2098,1107],{}," for parent\u002Fchild links, what is the idiomatic way to prevent the reference-cycle leak described earlier?",[98,2101,2103,2115,2125,2135],{"className":2102},[101],[103,2104,2106,2108,2109,235,2112,2114],{"className":2105},[106],[108,2107],{"disabled":110,"type":111}," Wrap the parent link in ",[23,2110,2111],{},"Weak\u003CRefCell\u003CNode>>",[23,2113,1107],{},", since a child shouldn't keep its parent alive",[103,2116,2118,2120,2121,2124],{"className":2117},[106],[108,2119],{"disabled":110,"type":111}," Call ",[23,2122,2123],{},"std::mem::forget"," on the child before dropping the parent",[103,2126,2128,2130,2131,2134],{"className":2127},[106],[108,2129],{"disabled":110,"type":111}," Manually call ",[23,2132,2133],{},"Rc::strong_count"," and panic if it's above 1",[103,2136,2138,2140,2141],{"className":2137},[106],[108,2139],{"disabled":110,"type":111}," Switch every field to ",[23,2142,2143],{},"Cell\u003CT>",[147,2145,2146,2148,2157],{},[150,2147,152],{},[154,2149,2150,2152,2153,235,2155,2114],{},[157,2151,159],{}," A — Wrap the parent link in ",[23,2154,2111],{},[23,2156,1107],{},[154,2158,2159,251,2161,2163,2164,2166,2167,2169,2170,2172,2173,2175,2176,2179,2180,2183,2184,2186,2187,2189],{},[157,2160,167],{},[157,2162,357],{},": the ownership direction should mirror the logical lifetime relationship — a tree's parent owns its children (strong ",[23,2165,396],{},"), but a child referencing its parent should not keep the parent alive on its own, so that link should be ",[23,2168,1339],{},". This breaks the cycle: when external owners drop the parent, its strong count can reach zero and it's freed even though children still hold ",[23,2171,1339],{}," back-pointers (which safely resolve to ",[23,2174,1293],{}," via ",[23,2177,2178],{},"upgrade()"," afterward). ",[23,2181,2182],{},"mem::forget"," (B) leaks deliberately, the opposite of what's wanted; manually auditing strong counts (C) is fragile and not how idiomatic Rust manages this; ",[23,2185,2143],{}," (D) solves a different problem (cheap interior mutability for ",[23,2188,118],{}," types), not cycles.",[14,2191,2192,2200,2237],{},[18,2193,2195,2196,2199],{"id":2194},"q17-when-is-reaching-for-rcrefcellt-considered-good-practice-versus-a-design-smell","Q17. When is reaching for ",[23,2197,2198],{},"Rc\u003CRefCell\u003CT>>"," considered good practice versus a design smell?",[98,2201,2203,2209,2218,2227],{"className":2202},[101],[103,2204,2206,2208],{"className":2205},[106],[108,2207],{"disabled":110,"type":111}," It should be used everywhere shared state exists, as the default choice",[103,2210,2212,2214,2215,2217],{"className":2211},[106],[108,2213],{"disabled":110,"type":111}," It's appropriate when shared, mutable, single-threaded ownership is a genuine requirement of the domain (e.g., a GUI widget tree); it's a smell when it's used to route around the borrow checker in code that could instead pass ownership or ",[23,2216,2074],{}," explicitly",[103,2219,2221,2223,2224,2226],{"className":2220},[106],[108,2222],{"disabled":110,"type":111}," It should never be used because ",[23,2225,1032],{}," is always faster",[103,2228,2230,2232,2233,2236],{"className":2229},[106],[108,2231],{"disabled":110,"type":111}," It's only valid inside ",[23,2234,2235],{},"#[test]"," modules",[147,2238,2239,2241,2248],{},[150,2240,152],{},[154,2242,2243,2245,2246,2217],{},[157,2244,159],{}," B — It's appropriate when shared, mutable, single-threaded ownership is a genuine requirement of the domain (e.g., a GUI widget tree); it's a smell when it's used to route around the borrow checker in code that could instead pass ownership or ",[23,2247,2074],{},[154,2249,2250,251,2252,261,2254,2256,2257,2259,2260,2262],{},[157,2251,167],{},[157,2253,357],{},[23,2255,2198],{}," is a legitimate, commonly used pattern for graphs\u002Ftrees with genuinely shared mutable nodes, but it moves Rust's aliasing guarantees to runtime, so overusing it as a generic escape hatch from ownership\u002Fborrowing errors trades compile-time safety for panics later and is widely considered a code smell. Treating it as an unconditional default (A) throws away the compiler's static guarantees for no reason in code that doesn't need shared mutation. It isn't about ",[23,2258,1032],{}," being faster — ",[23,2261,1032],{}," isn't involved here at all (rules out C) — and it's a general-purpose pattern, not something scoped to tests (rules out D).",[14,2264,2265,2274,2323],{},[18,2266,2268,2269,511,2271,2273],{"id":2267},"q18-cellt-and-refcellt-both-provide-interior-mutability-whats-the-key-practical-difference","Q18. ",[23,2270,2143],{},[23,2272,453],{}," both provide interior mutability. What's the key practical difference?",[98,2275,2277,2298,2309,2315],{"className":2276},[101],[103,2278,2280,251,2282,1029,2284,2287,2288,275,2291,2294,2295,2297],{"className":2279},[106],[108,2281],{"disabled":110,"type":111},[23,2283,2143],{},[23,2285,2286],{},"T: Copy"," and only exposes ",[23,2289,2290],{},"get",[23,2292,2293],{},"set"," (no borrows, so it can never panic from a borrow conflict); ",[23,2296,453],{}," hands out borrow guards and can panic if borrow rules are violated",[103,2299,2301,251,2303,2305,2306,2308],{"className":2300},[106],[108,2302],{"disabled":110,"type":111},[23,2304,2143],{}," is thread-safe and ",[23,2307,453],{}," is not",[103,2310,2312,2314],{"className":2311},[106],[108,2313],{"disabled":110,"type":111}," They are interchangeable in every situation",[103,2316,2318,251,2320,2322],{"className":2317},[106],[108,2319],{"disabled":110,"type":111},[23,2321,453],{}," is faster because it avoids runtime checks entirely",[147,2324,2325,2327,2342],{},[150,2326,152],{},[154,2328,2329,2331,2332,1029,2334,2287,2336,275,2338,2294,2340,2297],{},[157,2330,159],{}," A — ",[23,2333,2143],{},[23,2335,2286],{},[23,2337,2290],{},[23,2339,2293],{},[23,2341,453],{},[154,2343,2344,251,2346,2348,2349,275,2351,2353,2354,2356,2357,2359,2360,275,2363,2365,2366,2368,2369,2372,2373,2375,2376,2379],{},[157,2345,167],{},[23,2347,2143],{}," sidesteps the borrow-checking problem entirely by never handing out references to its contents — you copy values in and out via ",[23,2350,2290],{},[23,2352,2293],{},", which is why it's restricted to (effectively) ",[23,2355,118],{}," types and can never panic at runtime. ",[23,2358,453],{}," instead hands out ",[23,2361,2362],{},"Ref",[23,2364,1063],{}," guards so it works for non-",[23,2367,118],{}," types too, but that flexibility is exactly what introduces the possibility of a runtime borrow-rule panic. Neither is thread-safe — both are ",[23,2370,2371],{},"!Sync"," (rules out B); they solve overlapping but distinct problems so they aren't interchangeable (rules out C); and ",[23,2374,900],{}," does more runtime bookkeeping than ",[23,2377,2378],{},"Cell",", not less (rules out D).",[14,2381,2382,2386,2505,2551],{"language":16},[18,2383,2385],{"id":2384},"q19-what-is-the-idiomatic-way-to-safely-attempt-a-borrow-that-might-conflict-without-risking-a-panic","Q19. What is the idiomatic way to safely attempt a borrow that might conflict, without risking a panic?",[28,2387,2388],{"language":16},[31,2389,2391],{"className":33,"code":2390,"language":16,"meta":35,"style":35},"use std::cell::RefCell;\n\nfn maybe_read(cell: &RefCell\u003Ci32>) {\n    match cell.try_borrow() {\n        Ok(guard) => println!(\"value: {}\", *guard),\n        Err(_) => println!(\"currently borrowed elsewhere, skipping\"),\n    }\n}\n",[23,2392,2393,2409,2413,2436,2450,2476,2496,2501],{"__ignoreMap":35},[39,2394,2395,2397,2399,2401,2403,2405,2407],{"class":41,"line":42},[39,2396,539],{"class":45},[39,2398,542],{"class":49},[39,2400,545],{"class":45},[39,2402,895],{"class":49},[39,2404,545],{"class":45},[39,2406,900],{"class":49},[39,2408,555],{"class":53},[39,2410,2411],{"class":41,"line":57},[39,2412,571],{"emptyLinePlaceholder":110},[39,2414,2415,2417,2420,2423,2425,2427,2429,2431,2433],{"class":41,"line":84},[39,2416,576],{"class":45},[39,2418,2419],{"class":49}," maybe_read",[39,2421,2422],{"class":53},"(cell",[39,2424,1139],{"class":45},[39,2426,1614],{"class":45},[39,2428,900],{"class":49},[39,2430,75],{"class":53},[39,2432,66],{"class":49},[39,2434,2435],{"class":53},">) {\n",[39,2437,2438,2441,2443,2445,2448],{"class":41,"line":93},[39,2439,2440],{"class":45},"    match",[39,2442,950],{"class":53},[39,2444,685],{"class":45},[39,2446,2447],{"class":49},"try_borrow",[39,2449,582],{"class":53},[39,2451,2452,2455,2458,2461,2464,2466,2469,2471,2473],{"class":41,"line":585},[39,2453,2454],{"class":49},"        Ok",[39,2456,2457],{"class":53},"(guard) ",[39,2459,2460],{"class":45},"=>",[39,2462,2463],{"class":49}," println!",[39,2465,63],{"class":53},[39,2467,2468],{"class":666},"\"value: {}\"",[39,2470,69],{"class":53},[39,2472,989],{"class":45},[39,2474,2475],{"class":53},"guard),\n",[39,2477,2478,2481,2484,2486,2488,2490,2493],{"class":41,"line":630},[39,2479,2480],{"class":49},"        Err",[39,2482,2483],{"class":53},"(_) ",[39,2485,2460],{"class":45},[39,2487,2463],{"class":49},[39,2489,63],{"class":53},[39,2491,2492],{"class":666},"\"currently borrowed elsewhere, skipping\"",[39,2494,2495],{"class":53},"),\n",[39,2497,2498],{"class":41,"line":658},[39,2499,2500],{"class":53},"    }\n",[39,2502,2503],{"class":41,"line":673},[39,2504,96],{"class":53},[98,2506,2508,2517,2533,2543],{"className":2507},[101],[103,2509,2511,2513,2514,2516],{"className":2510},[106],[108,2512],{"disabled":110,"type":111}," This is an anti-pattern — always use ",[23,2515,510],{}," and let it panic",[103,2518,2520,2522,2523,275,2525,2528,2529,2532],{"className":2519},[106],[108,2521],{"disabled":110,"type":111}," This is idiomatic — ",[23,2524,2447],{},[23,2526,2527],{},"try_borrow_mut"," return ",[23,2530,2531],{},"Result"," so conflicting borrows can be handled gracefully instead of panicking",[103,2534,2536,251,2538,2540,2541],{"className":2535},[106],[108,2537],{"disabled":110,"type":111},[23,2539,2447],{}," doesn't exist on ",[23,2542,900],{},[103,2544,2546,251,2548,2550],{"className":2545},[106],[108,2547],{"disabled":110,"type":111},[23,2549,2447],{}," still panics, it just delays the panic",[147,2552,2553,2555,2566],{},[150,2554,152],{},[154,2556,2557,2559,2560,275,2562,2528,2564,2532],{},[157,2558,159],{}," B — This is idiomatic — ",[23,2561,2447],{},[23,2563,2527],{},[23,2565,2531],{},[154,2567,2568,251,2570,2572,2573,275,2575,2577,2578,275,2581,2583,2584,275,2586,2588,2589,275,2591,2593,2594,2597,2598,2600,2601,2603],{},[157,2569,167],{},[157,2571,357],{},": when a borrow conflict is an expected, recoverable possibility (rather than a programming bug you want to fail loudly on), ",[23,2574,2447],{},[23,2576,2527],{}," let you branch on ",[23,2579,2580],{},"Ok",[23,2582,1094],{}," instead of letting ",[23,2585,1652],{},[23,2587,955],{}," panic. Reserving the panicking ",[23,2590,510],{},[23,2592,514],{}," for cases where a conflict would indicate a genuine logic error (and the fallible ",[23,2595,2596],{},"try_*"," variants for cases where it's a normal runtime condition) is the recommended split — always panicking (A) throws away that flexibility. The method exists and is stable (rules out C), and it returns a ",[23,2599,2531],{}," rather than panicking at all on the ",[23,2602,1094],{}," path (rules out D).",[14,2605,2606,2616,2844,2894],{"language":16},[18,2607,2609,2610,2612,2613,2615],{"id":2608},"q20-in-this-recursive-tree-printing-function-using-rcrefcellnode-why-is-the-explicit-block-around-borrow-necessary-to-avoid-a-panic","Q20. In this recursive tree-printing function using ",[23,2611,1107],{},", why is the explicit block around ",[23,2614,510],{}," necessary to avoid a panic?",[28,2617,2618],{"language":16},[31,2619,2621],{"className":33,"code":2620,"language":16,"meta":35,"style":35},"struct Node {\n    value: i32,\n    children: RefCell\u003CVec\u003CRc\u003CRefCell\u003CNode>>>>,\n}\n\nfn print_tree(node: &Rc\u003CRefCell\u003CNode>>, depth: usize) {\n    let children_snapshot = {\n        let n = node.borrow();\n        println!(\"{}{}\", \"  \".repeat(depth), n.value);\n        n.children.borrow().clone()\n    };\n    for child in children_snapshot.iter() {\n        print_tree(child, depth + 1);\n    }\n}\n",[23,2622,2623,2631,2642,2670,2674,2678,2712,2723,2742,2769,2792,2797,2817,2834,2839],{"__ignoreMap":35},[39,2624,2625,2627,2629],{"class":41,"line":42},[39,2626,1126],{"class":45},[39,2628,1129],{"class":49},[39,2630,54],{"class":53},[39,2632,2633,2636,2638,2640],{"class":41,"line":57},[39,2634,2635],{"class":53},"    value",[39,2637,1139],{"class":45},[39,2639,1634],{"class":49},[39,2641,90],{"class":53},[39,2643,2644,2647,2649,2651,2653,2655,2657,2659,2661,2663,2665,2667],{"class":41,"line":84},[39,2645,2646],{"class":53},"    children",[39,2648,1139],{"class":45},[39,2650,926],{"class":49},[39,2652,75],{"class":53},[39,2654,1621],{"class":49},[39,2656,75],{"class":53},[39,2658,396],{"class":49},[39,2660,75],{"class":53},[39,2662,900],{"class":49},[39,2664,75],{"class":53},[39,2666,1155],{"class":49},[39,2668,2669],{"class":53},">>>>,\n",[39,2671,2672],{"class":41,"line":93},[39,2673,96],{"class":53},[39,2675,2676],{"class":41,"line":585},[39,2677,571],{"emptyLinePlaceholder":110},[39,2679,2680,2682,2685,2688,2690,2692,2694,2696,2698,2700,2702,2705,2707,2710],{"class":41,"line":630},[39,2681,576],{"class":45},[39,2683,2684],{"class":49}," print_tree",[39,2686,2687],{"class":53},"(node",[39,2689,1139],{"class":45},[39,2691,1614],{"class":45},[39,2693,396],{"class":49},[39,2695,75],{"class":53},[39,2697,900],{"class":49},[39,2699,75],{"class":53},[39,2701,1155],{"class":49},[39,2703,2704],{"class":53},">>, depth",[39,2706,1139],{"class":45},[39,2708,2709],{"class":49}," usize",[39,2711,1715],{"class":53},[39,2713,2714,2716,2719,2721],{"class":41,"line":658},[39,2715,588],{"class":45},[39,2717,2718],{"class":53}," children_snapshot ",[39,2720,594],{"class":45},[39,2722,54],{"class":53},[39,2724,2725,2728,2731,2733,2736,2738,2740],{"class":41,"line":673},[39,2726,2727],{"class":45},"        let",[39,2729,2730],{"class":53}," n ",[39,2732,594],{"class":45},[39,2734,2735],{"class":53}," node",[39,2737,685],{"class":45},[39,2739,1652],{"class":49},[39,2741,699],{"class":53},[39,2743,2744,2746,2748,2751,2753,2756,2758,2761,2764,2766],{"class":41,"line":679},[39,2745,661],{"class":49},[39,2747,63],{"class":53},[39,2749,2750],{"class":666},"\"{}{}\"",[39,2752,69],{"class":53},[39,2754,2755],{"class":666},"\"  \"",[39,2757,685],{"class":45},[39,2759,2760],{"class":49},"repeat",[39,2762,2763],{"class":53},"(depth), n",[39,2765,685],{"class":45},[39,2767,2768],{"class":53},"value);\n",[39,2770,2771,2774,2776,2779,2781,2783,2785,2787,2790],{"class":41,"line":702},[39,2772,2773],{"class":53},"        n",[39,2775,685],{"class":45},[39,2777,2778],{"class":53},"children",[39,2780,685],{"class":45},[39,2782,1652],{"class":49},[39,2784,691],{"class":53},[39,2786,685],{"class":45},[39,2788,2789],{"class":49},"clone",[39,2791,1674],{"class":53},[39,2793,2794],{"class":41,"line":1749},[39,2795,2796],{"class":53},"    };\n",[39,2798,2799,2802,2805,2808,2811,2813,2815],{"class":41,"line":1767},[39,2800,2801],{"class":45},"    for",[39,2803,2804],{"class":53}," child ",[39,2806,2807],{"class":45},"in",[39,2809,2810],{"class":53}," children_snapshot",[39,2812,685],{"class":45},[39,2814,1664],{"class":49},[39,2816,582],{"class":53},[39,2818,2820,2823,2826,2829,2832],{"class":41,"line":2819},13,[39,2821,2822],{"class":49},"        print_tree",[39,2824,2825],{"class":53},"(child, depth ",[39,2827,2828],{"class":45},"+",[39,2830,2831],{"class":613}," 1",[39,2833,938],{"class":53},[39,2835,2837],{"class":41,"line":2836},14,[39,2838,2500],{"class":53},[39,2840,2842],{"class":41,"line":2841},15,[39,2843,96],{"class":53},[98,2845,2847,2857,2876,2884],{"className":2846},[101],[103,2848,2850,2852,2853,2856],{"className":2849},[106],[108,2851],{"disabled":110,"type":111}," The block is unnecessary style preference; ",[23,2854,2855],{},"node.borrow()"," could stay alive across the recursive calls with no issue",[103,2858,2860,2862,2863,2865,2866,2868,2869,2872,2873,2875],{"className":2859},[106],[108,2861],{"disabled":110,"type":111}," The block ensures the ",[23,2864,2362],{}," guard from ",[23,2867,2855],{}," is dropped before ",[23,2870,2871],{},"print_tree"," recurses, so the recursive call's own ",[23,2874,2855],{}," on a child doesn't conflict with a still-held parent borrow",[103,2877,2879,251,2881,2883],{"className":2878},[106],[108,2880],{"disabled":110,"type":111},[23,2882,900],{}," borrows are automatically released at the end of every statement, so the block does nothing",[103,2885,2887,2889,2890,2893],{"className":2886},[106],[108,2888],{"disabled":110,"type":111}," The block is required only because ",[23,2891,2892],{},"Vec::clone"," needs exclusive access",[147,2895,2896,2898,2911],{},[150,2897,152],{},[154,2899,2900,2902,2903,2865,2905,2868,2907,2872,2909,2875],{},[157,2901,159],{}," B — The block ensures the ",[23,2904,2362],{},[23,2906,2855],{},[23,2908,2871],{},[23,2910,2855],{},[154,2912,2913,251,2915,1860,2918,2920,2921,2924,2925,2927,2928,2931,2932,2935,2936,2939,2940,2943,2944,2946,2947,251,2950,2952,2953,2955,2956,2958,2959,2961,2962,2964],{},[157,2914,167],{},[23,2916,2917],{},"n",[23,2919,2362],{}," guard borrowed from ",[23,2922,2923],{},"node","; ending the block drops ",[23,2926,2917],{}," (and the implicit borrow taken by ",[23,2929,2930],{},"n.children.borrow()",") before ",[23,2933,2934],{},"children_snapshot"," is used in the ",[23,2937,2938],{},"for"," loop, so by the time ",[23,2941,2942],{},"print_tree(child, ...)"," runs, ",[23,2945,2923],{},"'s borrow is fully released. Since each recursive call borrows a ",[1474,2948,2949],{},"different",[23,2951,1107],{}," (a child, not the same node), this particular example wouldn't panic even without the block — but the pattern of scoping borrows tightly is the general discipline that prevents panics in less trivial call graphs (e.g., a function that re-borrows the ",[1474,2954,1482],{}," node it was passed, or mutates while an outer borrow is still live). ",[157,2957,1079],{},": assuming a ",[23,2960,900],{}," borrow can safely span an arbitrary amount of downstream code (A) is exactly the assumption that causes production panics once the call graph changes; borrows are not scope-magic released at every statement boundary, only when the guard value is actually dropped (rules out C); and ",[23,2963,2892],{}," needs a shared reference to source data, not exclusive access, and has nothing to do with why the block exists (rules out D).",[2966,2967,2968],"style",{},"html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}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 .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}",{"title":35,"searchDepth":57,"depth":57,"links":2970},[2971,2973,2975,2977,2979,2981,2982,2984,2985,2987,2989,2991,2993,2994,2996,2997,2999,3001,3003,3004],{"id":20,"depth":84,"text":2972},"Q1. What problem does Box\u003CT> primarily solve for a type like this?",{"id":200,"depth":84,"text":2974},"Q2. What is Rc\u003CT> used for?",{"id":286,"depth":84,"text":2976},"Q3. Given let b = Rc::clone(&a);, what is idiomatic about writing it this way instead of let b = a.clone();?",{"id":380,"depth":84,"text":2978},"Q4. When does the value inside an Rc\u003CT> actually get dropped?",{"id":449,"depth":84,"text":2980},"Q5. What does RefCell\u003CT> provide that a plain T behind a shared reference does not?",{"id":526,"depth":84,"text":527},{"id":803,"depth":84,"text":2983},"Q7. What is Box\u003Cdyn Trait> primarily used for?",{"id":876,"depth":84,"text":877},{"id":1103,"depth":84,"text":2986},"Q9. This code builds a parent-child tree using Rc\u003CRefCell\u003CNode>> where each parent also stores an Rc back to its child, and each child stores an Rc back to its parent. What is the consequence?",{"id":1255,"depth":84,"text":2988},"Q10. Weak\u003CT> is obtained via Rc::downgrade(&rc). What does calling .upgrade() on a Weak\u003CT> return once every strong Rc to the value has been dropped?",{"id":1355,"depth":84,"text":2990},"Q11. On a typical 64-bit target, what is std::mem::size_of::\u003CRc\u003Ci32>>()?",{"id":1447,"depth":84,"text":2992},"Q12. What's the difference between let b2 = Box::new(42); let b3 = b2.clone(); and let r2 = Rc::new(42); let r3 = Rc::clone(&r2);?",{"id":1571,"depth":84,"text":1572},{"id":1921,"depth":84,"text":2995},"Q14. What is the effect of calling drop(rc_handle) on one clone of an Rc\u003CT> that has two other clones still alive elsewhere?",{"id":2010,"depth":84,"text":2011},{"id":2095,"depth":84,"text":2998},"Q16. In a single-threaded tree structure using Rc\u003CRefCell\u003CNode>> for parent\u002Fchild links, what is the idiomatic way to prevent the reference-cycle leak described earlier?",{"id":2194,"depth":84,"text":3000},"Q17. When is reaching for Rc\u003CRefCell\u003CT>> considered good practice versus a design smell?",{"id":2267,"depth":84,"text":3002},"Q18. Cell\u003CT> and RefCell\u003CT> both provide interior mutability. What's the key practical difference?",{"id":2384,"depth":84,"text":2385},{"id":2608,"depth":84,"text":3005},"Q20. In this recursive tree-printing function using Rc\u003CRefCell\u003CNode>>, why is the explicit block around borrow() necessary to avoid a panic?","md",{},"\u002Frust\u002F19-smart-pointers",{"title":5,"description":35},"rust\u002F19-smart-pointers","NfenOegpA9kQTxNlbTXxvvFivOZOzTCFDfkt-Nf1EVI",1787335398404]