<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Cuong Le]]></title><description><![CDATA[Head of Engineering at Bitmark, building Feral File.
Rust from first principles. Clear, step by step.]]></description><link>https://blog.cuongle.dev</link><image><url>https://substackcdn.com/image/fetch/$s_!V6nQ!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84283fdb-1137-44a7-b7d6-33654ca0ab9b_511x511.png</url><title>Cuong Le</title><link>https://blog.cuongle.dev</link></image><generator>Substack</generator><lastBuildDate>Wed, 13 May 2026 09:14:21 GMT</lastBuildDate><atom:link href="https://blog.cuongle.dev/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Cuong Le]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[cuongleqq@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[cuongleqq@substack.com]]></itunes:email><itunes:name><![CDATA[Cuong Le]]></itunes:name></itunes:owner><itunes:author><![CDATA[Cuong Le]]></itunes:author><googleplay:owner><![CDATA[cuongleqq@substack.com]]></googleplay:owner><googleplay:email><![CDATA[cuongleqq@substack.com]]></googleplay:email><googleplay:author><![CDATA[Cuong Le]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Inside Rust's std and parking_lot mutexes - who wins?]]></title><description><![CDATA[A teardown of Rust's mutex internals plus real benchmarks so you know when to choose std or parking_lot.]]></description><link>https://blog.cuongle.dev/p/inside-rusts-std-and-parking-lot-mutexes-who-win</link><guid isPermaLink="false">https://blog.cuongle.dev/p/inside-rusts-std-and-parking-lot-mutexes-who-win</guid><dc:creator><![CDATA[Cuong Le]]></dc:creator><pubDate>Thu, 30 Oct 2025 14:45:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Qw15!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2306f9-c81b-4035-a4da-a1b68f70c3a9_1800x960.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A while ago, our team was working on a Rust project where <strong>std::sync::Mutex</strong> was everywhere. A team member suggested switching to <strong>parking_lot::Mutex</strong> instead. They heard that it has better performance, smaller memory footprint, and more predictable behavior under contention.</p><p>I had no idea how to evaluate this claim. A quick search online returned results favoring parking_lot. This felt wrong to me. Why? It contradicted my belief that std should be the gold standard. The standard library team knows what they&#8217;re doing, right? And if parking_lot&#8217;s mutex really was the performance winner, there had to be trade-offs between the two implementations that people weren&#8217;t talking about.</p><p>That mystery haunted me. I couldn&#8217;t just take it on faith. So I jumped down the rabbit hole: read both implementations, wrote the benchmarks, and here we are. In this post, I will:</p><ul><li><p>Explain how std implements the mutex (v1.90.0)</p></li><li><p>Explain how parking_lot implements their mutex (v0.12.5)</p></li><li><p>Show you the benchmark with key findings</p></li><li><p>Give you a decision guide for when to use each</p></li></ul><p>But first, let&#8217;s ground our foundation on mutexes (skim it if you&#8217;re already familiar).</p><h2>What Is a Mutex, Really?</h2><p>A classic example of the kind of problem that mutex solves is withdrawing and receiving money at the same time. Imagine you have $100 in your account. Thread A tries to withdraw $80, and Thread B tries to deposit $50. Without proper synchronization, both threads might read the balance as $100 simultaneously, then write back their results independently:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tCcw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10eed961-c27c-4fc9-95ab-27a9ae9d9451_668x264.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tCcw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10eed961-c27c-4fc9-95ab-27a9ae9d9451_668x264.png 424w, https://substackcdn.com/image/fetch/$s_!tCcw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10eed961-c27c-4fc9-95ab-27a9ae9d9451_668x264.png 848w, https://substackcdn.com/image/fetch/$s_!tCcw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10eed961-c27c-4fc9-95ab-27a9ae9d9451_668x264.png 1272w, https://substackcdn.com/image/fetch/$s_!tCcw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10eed961-c27c-4fc9-95ab-27a9ae9d9451_668x264.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tCcw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10eed961-c27c-4fc9-95ab-27a9ae9d9451_668x264.png" width="668" height="264" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/10eed961-c27c-4fc9-95ab-27a9ae9d9451_668x264.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:264,&quot;width&quot;:668,&quot;resizeWidth&quot;:668,&quot;bytes&quot;:36291,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10eed961-c27c-4fc9-95ab-27a9ae9d9451_668x264.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tCcw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10eed961-c27c-4fc9-95ab-27a9ae9d9451_668x264.png 424w, https://substackcdn.com/image/fetch/$s_!tCcw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10eed961-c27c-4fc9-95ab-27a9ae9d9451_668x264.png 848w, https://substackcdn.com/image/fetch/$s_!tCcw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10eed961-c27c-4fc9-95ab-27a9ae9d9451_668x264.png 1272w, https://substackcdn.com/image/fetch/$s_!tCcw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10eed961-c27c-4fc9-95ab-27a9ae9d9451_668x264.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Mutex solves this nicely by having a thread wait until the other finishes its update:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!36kg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f26bcb8-127f-46cc-baf7-4743e02d8088_646x374.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!36kg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f26bcb8-127f-46cc-baf7-4743e02d8088_646x374.png 424w, https://substackcdn.com/image/fetch/$s_!36kg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f26bcb8-127f-46cc-baf7-4743e02d8088_646x374.png 848w, https://substackcdn.com/image/fetch/$s_!36kg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f26bcb8-127f-46cc-baf7-4743e02d8088_646x374.png 1272w, https://substackcdn.com/image/fetch/$s_!36kg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f26bcb8-127f-46cc-baf7-4743e02d8088_646x374.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!36kg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f26bcb8-127f-46cc-baf7-4743e02d8088_646x374.png" width="646" height="374" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3f26bcb8-127f-46cc-baf7-4743e02d8088_646x374.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:374,&quot;width&quot;:646,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:77908,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f26bcb8-127f-46cc-baf7-4743e02d8088_646x374.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!36kg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f26bcb8-127f-46cc-baf7-4743e02d8088_646x374.png 424w, https://substackcdn.com/image/fetch/$s_!36kg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f26bcb8-127f-46cc-baf7-4743e02d8088_646x374.png 848w, https://substackcdn.com/image/fetch/$s_!36kg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f26bcb8-127f-46cc-baf7-4743e02d8088_646x374.png 1272w, https://substackcdn.com/image/fetch/$s_!36kg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f26bcb8-127f-46cc-baf7-4743e02d8088_646x374.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The operations that read and write the balance are what we need to protect - these are called <strong>critical sections</strong>. Any code that accesses shared data needs to be inside a critical section, guarded by a mutex.</p><p>Simple enough, right? Now let&#8217;s see how to use a mutex. (Again, skim this if it&#8217;s too basic for you)</p><h3>How to use mutex</h3><p>In languages other than Rust, you typically declare a mutex separately from your data, then manually lock it before entering the critical section and unlock it afterward. Here&#8217;s how it looks in C++:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2Y36!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5bb72b0-812e-4ef2-a5f2-3239c22daea3_1160x714.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2Y36!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5bb72b0-812e-4ef2-a5f2-3239c22daea3_1160x714.png 424w, https://substackcdn.com/image/fetch/$s_!2Y36!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5bb72b0-812e-4ef2-a5f2-3239c22daea3_1160x714.png 848w, https://substackcdn.com/image/fetch/$s_!2Y36!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5bb72b0-812e-4ef2-a5f2-3239c22daea3_1160x714.png 1272w, https://substackcdn.com/image/fetch/$s_!2Y36!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5bb72b0-812e-4ef2-a5f2-3239c22daea3_1160x714.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2Y36!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5bb72b0-812e-4ef2-a5f2-3239c22daea3_1160x714.png" width="1160" height="714" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f5bb72b0-812e-4ef2-a5f2-3239c22daea3_1160x714.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:714,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:103118,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5bb72b0-812e-4ef2-a5f2-3239c22daea3_1160x714.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2Y36!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5bb72b0-812e-4ef2-a5f2-3239c22daea3_1160x714.png 424w, https://substackcdn.com/image/fetch/$s_!2Y36!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5bb72b0-812e-4ef2-a5f2-3239c22daea3_1160x714.png 848w, https://substackcdn.com/image/fetch/$s_!2Y36!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5bb72b0-812e-4ef2-a5f2-3239c22daea3_1160x714.png 1272w, https://substackcdn.com/image/fetch/$s_!2Y36!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5bb72b0-812e-4ef2-a5f2-3239c22daea3_1160x714.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The problem? Nothing stops you from accessing <strong>account</strong> without locking the mutex first. The compiler won&#8217;t catch this bug.</p><p>Rust takes a completely different approach - the mutex wraps and owns the data:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0DUz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F527dfd6d-3347-45db-ab9e-0b14e40357ba_1160x752.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0DUz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F527dfd6d-3347-45db-ab9e-0b14e40357ba_1160x752.png 424w, https://substackcdn.com/image/fetch/$s_!0DUz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F527dfd6d-3347-45db-ab9e-0b14e40357ba_1160x752.png 848w, https://substackcdn.com/image/fetch/$s_!0DUz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F527dfd6d-3347-45db-ab9e-0b14e40357ba_1160x752.png 1272w, https://substackcdn.com/image/fetch/$s_!0DUz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F527dfd6d-3347-45db-ab9e-0b14e40357ba_1160x752.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0DUz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F527dfd6d-3347-45db-ab9e-0b14e40357ba_1160x752.png" width="1160" height="752" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/527dfd6d-3347-45db-ab9e-0b14e40357ba_1160x752.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:752,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:123218,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F527dfd6d-3347-45db-ab9e-0b14e40357ba_1160x752.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0DUz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F527dfd6d-3347-45db-ab9e-0b14e40357ba_1160x752.png 424w, https://substackcdn.com/image/fetch/$s_!0DUz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F527dfd6d-3347-45db-ab9e-0b14e40357ba_1160x752.png 848w, https://substackcdn.com/image/fetch/$s_!0DUz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F527dfd6d-3347-45db-ab9e-0b14e40357ba_1160x752.png 1272w, https://substackcdn.com/image/fetch/$s_!0DUz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F527dfd6d-3347-45db-ab9e-0b14e40357ba_1160x752.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Three things to pay close attention to:</p><ul><li><p><strong>The mutex wraps the data</strong>: This makes it impossible to access <strong>account</strong> without holding the lock. The compiler enforces this.</p></li><li><p><strong>Automatic unlock</strong>: When you lock, you receive a guard. When the guard goes out of scope, it automatically unlocks. No manual cleanup needed.</p></li><li><p><strong>Lock can fail</strong>: Notice the <strong>.unwrap()</strong> on <strong>.lock()</strong>? It returns a <strong>Result</strong> because locking can fail due to poisoning. I&#8217;ll explain this shortly.</p></li></ul><p>That&#8217;s enough of the basics. Let&#8217;s have some fun. Here is how mutex is implemented, starting with Rust std.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Want more like this? Rust and systems, from real work. Every two weeks.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>How Rust&#8217;s std::Mutex Works</h2><h3>Overview</h3><p>A quick look into std::Mutex gives us this</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!s6rZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F634dc677-ea09-4213-911f-57888b36c471_1160x342.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!s6rZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F634dc677-ea09-4213-911f-57888b36c471_1160x342.png 424w, https://substackcdn.com/image/fetch/$s_!s6rZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F634dc677-ea09-4213-911f-57888b36c471_1160x342.png 848w, https://substackcdn.com/image/fetch/$s_!s6rZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F634dc677-ea09-4213-911f-57888b36c471_1160x342.png 1272w, https://substackcdn.com/image/fetch/$s_!s6rZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F634dc677-ea09-4213-911f-57888b36c471_1160x342.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!s6rZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F634dc677-ea09-4213-911f-57888b36c471_1160x342.png" width="1160" height="342" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/634dc677-ea09-4213-911f-57888b36c471_1160x342.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:342,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!s6rZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F634dc677-ea09-4213-911f-57888b36c471_1160x342.png 424w, https://substackcdn.com/image/fetch/$s_!s6rZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F634dc677-ea09-4213-911f-57888b36c471_1160x342.png 848w, https://substackcdn.com/image/fetch/$s_!s6rZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F634dc677-ea09-4213-911f-57888b36c471_1160x342.png 1272w, https://substackcdn.com/image/fetch/$s_!s6rZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F634dc677-ea09-4213-911f-57888b36c471_1160x342.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><ul><li><p><strong>data</strong> is the easy part. Since the mutex enforces exclusive access, Rust uses UnsafeCell to give you safe mutable access once it&#8217;s locked.</p></li><li><p><strong>poison</strong> is just <strong>Atomic&lt;bool&gt;</strong> flag to tell if the last thread acquired the lock panic. So, maybe you would want to handle it next time you lock it.</p></li></ul><p><strong>inner</strong> is interesting part, let&#8217;s look at it next. The code is really long, so I just show a simplified version here</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!slfu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e02fd8e-b3ce-402e-8059-eea9fb3d4965_1160x976.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!slfu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e02fd8e-b3ce-402e-8059-eea9fb3d4965_1160x976.png 424w, https://substackcdn.com/image/fetch/$s_!slfu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e02fd8e-b3ce-402e-8059-eea9fb3d4965_1160x976.png 848w, https://substackcdn.com/image/fetch/$s_!slfu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e02fd8e-b3ce-402e-8059-eea9fb3d4965_1160x976.png 1272w, https://substackcdn.com/image/fetch/$s_!slfu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e02fd8e-b3ce-402e-8059-eea9fb3d4965_1160x976.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!slfu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e02fd8e-b3ce-402e-8059-eea9fb3d4965_1160x976.png" width="1160" height="976" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0e02fd8e-b3ce-402e-8059-eea9fb3d4965_1160x976.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:976,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:153206,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e02fd8e-b3ce-402e-8059-eea9fb3d4965_1160x976.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!slfu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e02fd8e-b3ce-402e-8059-eea9fb3d4965_1160x976.png 424w, https://substackcdn.com/image/fetch/$s_!slfu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e02fd8e-b3ce-402e-8059-eea9fb3d4965_1160x976.png 848w, https://substackcdn.com/image/fetch/$s_!slfu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e02fd8e-b3ce-402e-8059-eea9fb3d4965_1160x976.png 1272w, https://substackcdn.com/image/fetch/$s_!slfu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e02fd8e-b3ce-402e-8059-eea9fb3d4965_1160x976.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The main idea is that for different OS (and OS version), Rust uses different Mutex implementation. However, we can divide these implementation to 2 big groups: Futex and other platform primitive.</p><ul><li><p>Futex (short for &#8220;fast userspace mutex&#8221;) is used where the OS kernels expose a &#8220;wait on this address&#8221; API. We will dive deeper into this one soon.</p></li><li><p>When that API is missing, Rust falls back to the best available platform traditional locks.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xPH1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8125b1da-37ca-4fa9-8641-86692fc7fa1f_620x330.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xPH1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8125b1da-37ca-4fa9-8641-86692fc7fa1f_620x330.png 424w, https://substackcdn.com/image/fetch/$s_!xPH1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8125b1da-37ca-4fa9-8641-86692fc7fa1f_620x330.png 848w, https://substackcdn.com/image/fetch/$s_!xPH1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8125b1da-37ca-4fa9-8641-86692fc7fa1f_620x330.png 1272w, https://substackcdn.com/image/fetch/$s_!xPH1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8125b1da-37ca-4fa9-8641-86692fc7fa1f_620x330.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xPH1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8125b1da-37ca-4fa9-8641-86692fc7fa1f_620x330.png" width="620" height="330" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8125b1da-37ca-4fa9-8641-86692fc7fa1f_620x330.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:330,&quot;width&quot;:620,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:196492,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8125b1da-37ca-4fa9-8641-86692fc7fa1f_620x330.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xPH1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8125b1da-37ca-4fa9-8641-86692fc7fa1f_620x330.png 424w, https://substackcdn.com/image/fetch/$s_!xPH1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8125b1da-37ca-4fa9-8641-86692fc7fa1f_620x330.png 848w, https://substackcdn.com/image/fetch/$s_!xPH1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8125b1da-37ca-4fa9-8641-86692fc7fa1f_620x330.png 1272w, https://substackcdn.com/image/fetch/$s_!xPH1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8125b1da-37ca-4fa9-8641-86692fc7fa1f_620x330.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>(I&#8217;m in awe btw - that&#8217;s a lot of different implementations. Writing and maintaining all this platform-specific stuff must be exhausting. Major respect to whoever&#8217;s doing this.)</p><p>Since Futex is the most used and is quite a typical implementation for Mutex. Let&#8217;s look inside it.</p><h3>Futex</h3><p>At its heart, futex is just an atomic u32 (simplified here):</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4h93!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252d9b86-c436-4fb9-aba5-5dde4d5690b5_1160x194.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4h93!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252d9b86-c436-4fb9-aba5-5dde4d5690b5_1160x194.png 424w, https://substackcdn.com/image/fetch/$s_!4h93!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252d9b86-c436-4fb9-aba5-5dde4d5690b5_1160x194.png 848w, https://substackcdn.com/image/fetch/$s_!4h93!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252d9b86-c436-4fb9-aba5-5dde4d5690b5_1160x194.png 1272w, https://substackcdn.com/image/fetch/$s_!4h93!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252d9b86-c436-4fb9-aba5-5dde4d5690b5_1160x194.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4h93!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252d9b86-c436-4fb9-aba5-5dde4d5690b5_1160x194.png" width="1160" height="194" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/252d9b86-c436-4fb9-aba5-5dde4d5690b5_1160x194.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:194,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20139,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252d9b86-c436-4fb9-aba5-5dde4d5690b5_1160x194.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4h93!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252d9b86-c436-4fb9-aba5-5dde4d5690b5_1160x194.png 424w, https://substackcdn.com/image/fetch/$s_!4h93!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252d9b86-c436-4fb9-aba5-5dde4d5690b5_1160x194.png 848w, https://substackcdn.com/image/fetch/$s_!4h93!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252d9b86-c436-4fb9-aba5-5dde4d5690b5_1160x194.png 1272w, https://substackcdn.com/image/fetch/$s_!4h93!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252d9b86-c436-4fb9-aba5-5dde4d5690b5_1160x194.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Atomic type has this powerful operation called &#8220;Compare And Swap&#8221; (CAS) where the CPU executes it <strong>in an atomic call</strong>. It works by first comparing the value, if the value equals what is asked for, then it sets the value.</p><p>In other words, if we use value 0 for Unlocked state, and 1 for Locked state, we have a simple mutex where the thread can simply try to compare the state to 0 (Unlocked), and set to 1 (Locked). If the state is currently 1, keep doing that until successful.</p><p>So, a simplified version of mutex look like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vxbj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5feddc98-679e-4832-96dd-ffa33f4ad87d_562x451.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vxbj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5feddc98-679e-4832-96dd-ffa33f4ad87d_562x451.png 424w, https://substackcdn.com/image/fetch/$s_!vxbj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5feddc98-679e-4832-96dd-ffa33f4ad87d_562x451.png 848w, https://substackcdn.com/image/fetch/$s_!vxbj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5feddc98-679e-4832-96dd-ffa33f4ad87d_562x451.png 1272w, https://substackcdn.com/image/fetch/$s_!vxbj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5feddc98-679e-4832-96dd-ffa33f4ad87d_562x451.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vxbj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5feddc98-679e-4832-96dd-ffa33f4ad87d_562x451.png" width="562" height="451" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5feddc98-679e-4832-96dd-ffa33f4ad87d_562x451.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:451,&quot;width&quot;:562,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:139603,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5feddc98-679e-4832-96dd-ffa33f4ad87d_562x451.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vxbj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5feddc98-679e-4832-96dd-ffa33f4ad87d_562x451.png 424w, https://substackcdn.com/image/fetch/$s_!vxbj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5feddc98-679e-4832-96dd-ffa33f4ad87d_562x451.png 848w, https://substackcdn.com/image/fetch/$s_!vxbj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5feddc98-679e-4832-96dd-ffa33f4ad87d_562x451.png 1272w, https://substackcdn.com/image/fetch/$s_!vxbj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5feddc98-679e-4832-96dd-ffa33f4ad87d_562x451.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>But you might ask: if the first thread holds the lock for a long time, then the second thread needs to keep trying (like a infinite loop)? How about if there are hundreds or thousands of them? Maybe the CPU will soon be burnt.</p><p>Of course, there is the solution to this problem. In real implementation, Rust futex has 3 states:</p><ul><li><p>0: Unlocked</p></li><li><p>1: Locked</p></li><li><p>2: Contended - locked, but there are waiter.</p></li></ul><p>Notice the Contended state? A thread will try its best to acquire the lock. But if it can&#8217;t, it will mark the lock as contended and go to sleep, waiting for the process to wake it up when the mutex is released.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lkIj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F836e330a-b1c2-4d3a-af29-9bd29343e216_555x352.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lkIj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F836e330a-b1c2-4d3a-af29-9bd29343e216_555x352.png 424w, https://substackcdn.com/image/fetch/$s_!lkIj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F836e330a-b1c2-4d3a-af29-9bd29343e216_555x352.png 848w, https://substackcdn.com/image/fetch/$s_!lkIj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F836e330a-b1c2-4d3a-af29-9bd29343e216_555x352.png 1272w, https://substackcdn.com/image/fetch/$s_!lkIj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F836e330a-b1c2-4d3a-af29-9bd29343e216_555x352.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lkIj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F836e330a-b1c2-4d3a-af29-9bd29343e216_555x352.png" width="555" height="352" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/836e330a-b1c2-4d3a-af29-9bd29343e216_555x352.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:352,&quot;width&quot;:555,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:93565,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F836e330a-b1c2-4d3a-af29-9bd29343e216_555x352.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lkIj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F836e330a-b1c2-4d3a-af29-9bd29343e216_555x352.png 424w, https://substackcdn.com/image/fetch/$s_!lkIj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F836e330a-b1c2-4d3a-af29-9bd29343e216_555x352.png 848w, https://substackcdn.com/image/fetch/$s_!lkIj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F836e330a-b1c2-4d3a-af29-9bd29343e216_555x352.png 1272w, https://substackcdn.com/image/fetch/$s_!lkIj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F836e330a-b1c2-4d3a-af29-9bd29343e216_555x352.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Note:</strong> See that spinning part in the diagram? Before a thread goes to sleep, it keeps checking the lock state for about 100 loops - if it becomes unlocked, the thread immediately tries CAS. This avoids the <strong>expensive syscall</strong> if the lock is released quickly.</p><p>What happens when a thread goes to sleep? The kernel helps us put these sleeping threads into a queue. Take a look at the system call on Linux and Android to put the thread into sleeping state (this is usually called &#8220;park a thread&#8221;):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YKa0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6355b435-9dd7-40d3-bef1-8f4a7ae51e82_1160x640.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YKa0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6355b435-9dd7-40d3-bef1-8f4a7ae51e82_1160x640.png 424w, https://substackcdn.com/image/fetch/$s_!YKa0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6355b435-9dd7-40d3-bef1-8f4a7ae51e82_1160x640.png 848w, https://substackcdn.com/image/fetch/$s_!YKa0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6355b435-9dd7-40d3-bef1-8f4a7ae51e82_1160x640.png 1272w, https://substackcdn.com/image/fetch/$s_!YKa0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6355b435-9dd7-40d3-bef1-8f4a7ae51e82_1160x640.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YKa0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6355b435-9dd7-40d3-bef1-8f4a7ae51e82_1160x640.png" width="1160" height="640" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6355b435-9dd7-40d3-bef1-8f4a7ae51e82_1160x640.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:640,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!YKa0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6355b435-9dd7-40d3-bef1-8f4a7ae51e82_1160x640.png 424w, https://substackcdn.com/image/fetch/$s_!YKa0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6355b435-9dd7-40d3-bef1-8f4a7ae51e82_1160x640.png 848w, https://substackcdn.com/image/fetch/$s_!YKa0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6355b435-9dd7-40d3-bef1-8f4a7ae51e82_1160x640.png 1272w, https://substackcdn.com/image/fetch/$s_!YKa0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6355b435-9dd7-40d3-bef1-8f4a7ae51e82_1160x640.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The key part is <strong>futex as *const Atomic&lt;u32&gt;</strong> - you give the kernel a memory address, and it queues your thread there. Later, when you want to wake a thread, you give the kernel that same address, and it dequeues and wakes a sleeper.</p><p>When a thread finishes, it sets the state to unlocked. If the state was contended, it wakes one waiting thread via syscall. This continues until the queue empties.</p><p>The final piece of std&#8217;s mutex is poisoning, a unique feature you won&#8217;t find in most other languages.</p><h3>Poisoning: Panic Safety in Mutexes</h3><p>One unique feature of Rust&#8217;s standard mutex is poisoning. When a thread panics while holding a lock, the mutex becomes &#8220;poisoned.&#8221; Any subsequent attempts to lock it will return an <strong>Err(PoisonError)</strong>, but you still get the guard inside the error:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!I7Ry!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e83077c-c835-4b9a-a89e-c8b1c03d89fb_1160x1088.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!I7Ry!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e83077c-c835-4b9a-a89e-c8b1c03d89fb_1160x1088.png 424w, https://substackcdn.com/image/fetch/$s_!I7Ry!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e83077c-c835-4b9a-a89e-c8b1c03d89fb_1160x1088.png 848w, https://substackcdn.com/image/fetch/$s_!I7Ry!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e83077c-c835-4b9a-a89e-c8b1c03d89fb_1160x1088.png 1272w, https://substackcdn.com/image/fetch/$s_!I7Ry!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e83077c-c835-4b9a-a89e-c8b1c03d89fb_1160x1088.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!I7Ry!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e83077c-c835-4b9a-a89e-c8b1c03d89fb_1160x1088.png" width="1160" height="1088" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0e83077c-c835-4b9a-a89e-c8b1c03d89fb_1160x1088.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1088,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!I7Ry!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e83077c-c835-4b9a-a89e-c8b1c03d89fb_1160x1088.png 424w, https://substackcdn.com/image/fetch/$s_!I7Ry!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e83077c-c835-4b9a-a89e-c8b1c03d89fb_1160x1088.png 848w, https://substackcdn.com/image/fetch/$s_!I7Ry!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e83077c-c835-4b9a-a89e-c8b1c03d89fb_1160x1088.png 1272w, https://substackcdn.com/image/fetch/$s_!I7Ry!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e83077c-c835-4b9a-a89e-c8b1c03d89fb_1160x1088.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>How does poisoning work? Conceptually, it happens in the <strong>MutexGuard::drop()</strong> path (simplified here for clarity):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nQZQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13c0888e-1b1d-4db3-9b24-c9325faf1b0c_1160x566.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nQZQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13c0888e-1b1d-4db3-9b24-c9325faf1b0c_1160x566.png 424w, https://substackcdn.com/image/fetch/$s_!nQZQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13c0888e-1b1d-4db3-9b24-c9325faf1b0c_1160x566.png 848w, https://substackcdn.com/image/fetch/$s_!nQZQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13c0888e-1b1d-4db3-9b24-c9325faf1b0c_1160x566.png 1272w, https://substackcdn.com/image/fetch/$s_!nQZQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13c0888e-1b1d-4db3-9b24-c9325faf1b0c_1160x566.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nQZQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13c0888e-1b1d-4db3-9b24-c9325faf1b0c_1160x566.png" width="1160" height="566" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/13c0888e-1b1d-4db3-9b24-c9325faf1b0c_1160x566.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:566,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:98586,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13c0888e-1b1d-4db3-9b24-c9325faf1b0c_1160x566.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nQZQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13c0888e-1b1d-4db3-9b24-c9325faf1b0c_1160x566.png 424w, https://substackcdn.com/image/fetch/$s_!nQZQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13c0888e-1b1d-4db3-9b24-c9325faf1b0c_1160x566.png 848w, https://substackcdn.com/image/fetch/$s_!nQZQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13c0888e-1b1d-4db3-9b24-c9325faf1b0c_1160x566.png 1272w, https://substackcdn.com/image/fetch/$s_!nQZQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13c0888e-1b1d-4db3-9b24-c9325faf1b0c_1160x566.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The guard captures whether the thread was panicking when the lock was acquired. If we weren&#8217;t panicking then but we are now, a panic must have occurred in the critical section. The mutex is marked as poisoned with a simple atomic store.</p><p>This is a &#8220;best effort&#8221; mechanism. It won&#8217;t catch all cases (like double panics or non-Rust exceptions), but it provides a useful safety net. The key insight is that you still get access to the data even if the mutex is poisoned, allowing you to inspect and potentially recover from the corrupted state.</p><p><strong>Big note:</strong> mutex poisoning gets both love and hate. It catches data corruption but feels awkward compared to other languages (Me too, I know it&#8217;s helpful. But I still hate it, lol). The Rust team is adding a non-poisoning variant - see <a href="https://github.com/rust-lang/rust/issues/134645">issue#134645</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Rust from first principles, explained plainly. A new deep dive every two weeks.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>How parking_lot does it differently?</h2><p>parking_lot takes a fundamentally different approach. Two key differences:</p><ul><li><p>std uses different mutex implementations per platform. parking_lot uses one algorithm everywhere, calling platform-specific code only for sleep/wake.</p></li><li><p>std&#8217;s queues live in the kernel. parking_lot manages its own queues in user space via a global hash table.</p></li></ul><h3>A Mutex That Fits in One Byte</h3><p>parking_lot&#8217;s mutex is remarkably small:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tu7E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51bf2366-be3b-41bc-9edd-4f90c49e5d67_1160x380.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tu7E!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51bf2366-be3b-41bc-9edd-4f90c49e5d67_1160x380.png 424w, https://substackcdn.com/image/fetch/$s_!tu7E!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51bf2366-be3b-41bc-9edd-4f90c49e5d67_1160x380.png 848w, https://substackcdn.com/image/fetch/$s_!tu7E!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51bf2366-be3b-41bc-9edd-4f90c49e5d67_1160x380.png 1272w, https://substackcdn.com/image/fetch/$s_!tu7E!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51bf2366-be3b-41bc-9edd-4f90c49e5d67_1160x380.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tu7E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51bf2366-be3b-41bc-9edd-4f90c49e5d67_1160x380.png" width="1160" height="380" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/51bf2366-be3b-41bc-9edd-4f90c49e5d67_1160x380.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:380,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:67513,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51bf2366-be3b-41bc-9edd-4f90c49e5d67_1160x380.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tu7E!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51bf2366-be3b-41bc-9edd-4f90c49e5d67_1160x380.png 424w, https://substackcdn.com/image/fetch/$s_!tu7E!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51bf2366-be3b-41bc-9edd-4f90c49e5d67_1160x380.png 848w, https://substackcdn.com/image/fetch/$s_!tu7E!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51bf2366-be3b-41bc-9edd-4f90c49e5d67_1160x380.png 1272w, https://substackcdn.com/image/fetch/$s_!tu7E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51bf2366-be3b-41bc-9edd-4f90c49e5d67_1160x380.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Why can parking_lot use just one byte while std needs more? It comes down to how queues work.</p><p>std&#8217;s futex uses the kernel to manage wait queues. When you call the futex syscall, you pass the memory address of your atomic variable, and the kernel uses that address as the queue ID. But there&#8217;s a catch: the kernel requires this address to be aligned to a 32-bit boundary. So std&#8217;s mutex must use <strong>AtomicU32</strong>, even though it only needs a few bits for state.</p><p>parking_lot manages its own queues in user space. It hashes the mutex&#8217;s memory address to find the right queue bucket. Since it doesn&#8217;t need to satisfy kernel alignment requirements, it can use a single <strong>AtomicU8</strong>.</p><p><strong>More states for queue bookkeeping</strong></p><p>Using separate bits gives parking_lot four possible states:</p><ul><li><p><strong>00</strong>: Unlocked, no waiters</p></li><li><p><strong>01</strong>: Locked, no waiters</p></li><li><p><strong>10</strong>: Unlocked, but threads still waiting</p></li><li><p><strong>11</strong>: Locked with waiters</p></li></ul><p>That third state (<strong>10</strong>) might seem odd at first. Why would a mutex be unlocked but still have waiting threads? This is a transient state that happens during parking_lot&#8217;s unlock process. Because parking_lot manages its own queue, it uses the PARKED_BIT as bookkeeping to track whether threads are still in the queue. This helps avoid lost wakeups where a thread might miss its notification. It&#8217;s not an advantage over std, just a consequence of managing queues in user space rather than delegating to the kernel.</p><h3>The Global Queue and Fairness Mechanism</h3><p>When a thread can&#8217;t acquire the lock, it needs somewhere to wait. This is where parking_lot&#8217;s global hash table comes in.</p><h4>How the global queue works</h4><p>Instead of each mutex maintaining its own queue (like kernel futexes do), parking_lot uses a single global hash table shared by all mutexes in your program. When a thread needs to wait:</p><ol><li><p>Hash the mutex&#8217;s memory address to find a bucket in the global table</p></li><li><p>Add the thread to the bucket&#8217;s wait queue</p></li><li><p>Go to sleep</p></li></ol><p>Being able to manage the thread queue itself is important for parking_lot to enforce fairness. As you can see right away in the next section.</p><h4>Eventual fairness</h4><p>Here&#8217;s where parking_lot differs from std in behavior. std&#8217;s futex uses a &#8220;barging&#8221; strategy where any active thread can grab the lock when it&#8217;s released, even if others have been waiting in the queue longer. This maximizes throughput but can cause starvation.</p><p>When a thread unlocks, there are two sources of threads that can lock again:</p><ul><li><p>An active thread that is calling for locking</p></li><li><p>A sleeping thread in the queue</p></li></ul><p>As you can see, the active thread will tend to win the fight of &#8220;who locks first&#8221;. So if a thread keeps calling for lock, finishes its work, then locks right away, it keeps all other threads starved.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Hkew!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d858958-c7c5-447b-bc3a-e136f2ff5c5d_571x497.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Hkew!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d858958-c7c5-447b-bc3a-e136f2ff5c5d_571x497.png 424w, https://substackcdn.com/image/fetch/$s_!Hkew!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d858958-c7c5-447b-bc3a-e136f2ff5c5d_571x497.png 848w, https://substackcdn.com/image/fetch/$s_!Hkew!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d858958-c7c5-447b-bc3a-e136f2ff5c5d_571x497.png 1272w, https://substackcdn.com/image/fetch/$s_!Hkew!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d858958-c7c5-447b-bc3a-e136f2ff5c5d_571x497.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Hkew!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d858958-c7c5-447b-bc3a-e136f2ff5c5d_571x497.png" width="571" height="497" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d858958-c7c5-447b-bc3a-e136f2ff5c5d_571x497.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:497,&quot;width&quot;:571,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:68043,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d858958-c7c5-447b-bc3a-e136f2ff5c5d_571x497.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Hkew!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d858958-c7c5-447b-bc3a-e136f2ff5c5d_571x497.png 424w, https://substackcdn.com/image/fetch/$s_!Hkew!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d858958-c7c5-447b-bc3a-e136f2ff5c5d_571x497.png 848w, https://substackcdn.com/image/fetch/$s_!Hkew!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d858958-c7c5-447b-bc3a-e136f2ff5c5d_571x497.png 1272w, https://substackcdn.com/image/fetch/$s_!Hkew!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d858958-c7c5-447b-bc3a-e136f2ff5c5d_571x497.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As you can see, thread A keeps grabbing the lock immediately after releasing it. Threads B and C do get woken up by the syscall, but by the time they try to acquire the lock, thread A has already grabbed it again. They&#8217;re completely starved.</p><p>parking_lot implements &#8220;eventual fairness&#8221; to prevent this.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Jqnq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc03117-98e2-42df-ac25-59170049763f_571x441.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Jqnq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc03117-98e2-42df-ac25-59170049763f_571x441.png 424w, https://substackcdn.com/image/fetch/$s_!Jqnq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc03117-98e2-42df-ac25-59170049763f_571x441.png 848w, https://substackcdn.com/image/fetch/$s_!Jqnq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc03117-98e2-42df-ac25-59170049763f_571x441.png 1272w, https://substackcdn.com/image/fetch/$s_!Jqnq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc03117-98e2-42df-ac25-59170049763f_571x441.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Jqnq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc03117-98e2-42df-ac25-59170049763f_571x441.png" width="571" height="441" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4cc03117-98e2-42df-ac25-59170049763f_571x441.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:441,&quot;width&quot;:571,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:60764,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc03117-98e2-42df-ac25-59170049763f_571x441.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Jqnq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc03117-98e2-42df-ac25-59170049763f_571x441.png 424w, https://substackcdn.com/image/fetch/$s_!Jqnq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc03117-98e2-42df-ac25-59170049763f_571x441.png 848w, https://substackcdn.com/image/fetch/$s_!Jqnq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc03117-98e2-42df-ac25-59170049763f_571x441.png 1272w, https://substackcdn.com/image/fetch/$s_!Jqnq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc03117-98e2-42df-ac25-59170049763f_571x441.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Each bucket in the hash table has a timer that fires approximately every 0.5 milliseconds. When the timer fires, the next unlock becomes a &#8220;fair unlock&#8221;:</p><ol><li><p>The unlocker keeps the LOCKED_BIT set</p></li><li><p>The woken thread receives the lock directly (a &#8220;handoff&#8221;)</p></li><li><p>That thread owns the lock immediately without racing with other active threads</p></li></ol><p>So this means, instead of letting anyone who is fast grab the lock, parking_lot forces the lock to be given directly to the next one in the queue (it keeps the LOCKED_BIT set and hands off; it doesn&#8217;t even unlock).</p><p>This timer-based approach means parking_lot is unfair most of the time (for performance), but guarantees fairness every ~0.5ms to prevent any thread from being starved indefinitely. You can also force a fair unlock explicitly with <strong>unlock_fair()</strong> if needed.</p><p>This eventual fairness technique from parking_lot is pretty clever, isn&#8217;t it?</p><h3>How parking_lot actually parks threads</h3><p>You might wonder by now: how does parking_lot put threads to sleep without storing a 32-bit futex word inside every mutex? The answer is thread-local storage.</p><p>parking_lot still uses the same futex syscall as std, but it doesn&#8217;t pass the mutex address to the kernel. Instead, each thread owns a <strong>ThreadData</strong> record containing a reusable <strong>i32</strong>. Because this integer lives in thread-local storage, each thread has a unique address to use for the syscall. In the kernel, every blocked thread sits in its own single-entry queue.</p><p>The code looks almost identical to std&#8217;s futex path. The only difference? parking_lot points the syscall at the thread-local integer instead of the mutex:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!APi2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b26c0b0-eee1-47e3-baf0-e9d32ea15da1_1160x462.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!APi2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b26c0b0-eee1-47e3-baf0-e9d32ea15da1_1160x462.png 424w, https://substackcdn.com/image/fetch/$s_!APi2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b26c0b0-eee1-47e3-baf0-e9d32ea15da1_1160x462.png 848w, https://substackcdn.com/image/fetch/$s_!APi2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b26c0b0-eee1-47e3-baf0-e9d32ea15da1_1160x462.png 1272w, https://substackcdn.com/image/fetch/$s_!APi2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b26c0b0-eee1-47e3-baf0-e9d32ea15da1_1160x462.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!APi2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b26c0b0-eee1-47e3-baf0-e9d32ea15da1_1160x462.png" width="1160" height="462" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5b26c0b0-eee1-47e3-baf0-e9d32ea15da1_1160x462.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:462,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:59471,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b26c0b0-eee1-47e3-baf0-e9d32ea15da1_1160x462.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!APi2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b26c0b0-eee1-47e3-baf0-e9d32ea15da1_1160x462.png 424w, https://substackcdn.com/image/fetch/$s_!APi2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b26c0b0-eee1-47e3-baf0-e9d32ea15da1_1160x462.png 848w, https://substackcdn.com/image/fetch/$s_!APi2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b26c0b0-eee1-47e3-baf0-e9d32ea15da1_1160x462.png 1272w, https://substackcdn.com/image/fetch/$s_!APi2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b26c0b0-eee1-47e3-baf0-e9d32ea15da1_1160x462.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>When unlocking, parking_lot uses the same per-thread integer and issues <strong>FUTEX_WAKE</strong> on that address. This way, the mutex stays just one byte while the thread-local helper handles all the sleeping and waking.</p><p>On platforms without futexes, the parker swaps in the local blocking primitive (<strong>pthread_cond_t</strong> on macOS/BSD, Windows&#8217; <strong>WaitOnAddress</strong>/keyed events, or a plain spin loop) while keeping the same per-thread queue design.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">What worked, what did not, and why. New post every two weeks.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Benchmark Results: The Real Performance Story</h2><p>Now let&#8217;s see how these implementations perform in practice. I ran benchmarks across four scenarios that reveal different aspects of mutex behavior. All benchmarks ran on Linux with the futex backend for std. You can find the source code and full report at <a href="https://github.com/cuongleqq/mutex-benches">https://github.com/cuongleqq/mutex-benches</a>.</p><p>For each scenario, you&#8217;ll see:</p><ul><li><p><strong>Per-thread operation counts</strong>: Shows how many lock acquisitions each thread completed</p></li><li><p><strong>Performance metrics</strong>: Throughput, wait latencies (median, mean, P99), and standard deviation</p></li><li><p><strong>Analysis</strong>: What the results tell us about each mutex&#8217;s behavior</p></li></ul><p>(If the numbers feel overwhelming, just read the <strong>scenario configuration</strong> and skip straight to the <strong>takeaway</strong>.)</p><h3>Scenario 1: Short Hold (Moderate Contention)</h3><p><strong>Configuration:</strong> 4 threads, 10 seconds, minimal work in critical section</p><p><strong>Scenario:</strong> This simulates a typical application where threads frequently acquire and release locks with very little work inside the critical section. Each thread simply increments a counter, representing the common case of protecting small data structures or quick state updates.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!In6t!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8f8550f-5b10-41ba-809e-6f60656bf7f6_1600x900.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!In6t!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8f8550f-5b10-41ba-809e-6f60656bf7f6_1600x900.png 424w, https://substackcdn.com/image/fetch/$s_!In6t!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8f8550f-5b10-41ba-809e-6f60656bf7f6_1600x900.png 848w, https://substackcdn.com/image/fetch/$s_!In6t!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8f8550f-5b10-41ba-809e-6f60656bf7f6_1600x900.png 1272w, https://substackcdn.com/image/fetch/$s_!In6t!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8f8550f-5b10-41ba-809e-6f60656bf7f6_1600x900.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!In6t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8f8550f-5b10-41ba-809e-6f60656bf7f6_1600x900.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f8f8550f-5b10-41ba-809e-6f60656bf7f6_1600x900.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:104329,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8f8550f-5b10-41ba-809e-6f60656bf7f6_1600x900.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!In6t!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8f8550f-5b10-41ba-809e-6f60656bf7f6_1600x900.png 424w, https://substackcdn.com/image/fetch/$s_!In6t!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8f8550f-5b10-41ba-809e-6f60656bf7f6_1600x900.png 848w, https://substackcdn.com/image/fetch/$s_!In6t!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8f8550f-5b10-41ba-809e-6f60656bf7f6_1600x900.png 1272w, https://substackcdn.com/image/fetch/$s_!In6t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8f8550f-5b10-41ba-809e-6f60656bf7f6_1600x900.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FvEh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66dc8c33-8a6f-468d-97d1-61be2e0ea81c_1134x302.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FvEh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66dc8c33-8a6f-468d-97d1-61be2e0ea81c_1134x302.png 424w, https://substackcdn.com/image/fetch/$s_!FvEh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66dc8c33-8a6f-468d-97d1-61be2e0ea81c_1134x302.png 848w, https://substackcdn.com/image/fetch/$s_!FvEh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66dc8c33-8a6f-468d-97d1-61be2e0ea81c_1134x302.png 1272w, https://substackcdn.com/image/fetch/$s_!FvEh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66dc8c33-8a6f-468d-97d1-61be2e0ea81c_1134x302.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FvEh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66dc8c33-8a6f-468d-97d1-61be2e0ea81c_1134x302.png" width="1134" height="302" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/66dc8c33-8a6f-468d-97d1-61be2e0ea81c_1134x302.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:302,&quot;width&quot;:1134,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:80626,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66dc8c33-8a6f-468d-97d1-61be2e0ea81c_1134x302.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FvEh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66dc8c33-8a6f-468d-97d1-61be2e0ea81c_1134x302.png 424w, https://substackcdn.com/image/fetch/$s_!FvEh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66dc8c33-8a6f-468d-97d1-61be2e0ea81c_1134x302.png 848w, https://substackcdn.com/image/fetch/$s_!FvEh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66dc8c33-8a6f-468d-97d1-61be2e0ea81c_1134x302.png 1272w, https://substackcdn.com/image/fetch/$s_!FvEh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66dc8c33-8a6f-468d-97d1-61be2e0ea81c_1134x302.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Takeaway:</strong> In moderate contention with short critical sections, std&#8217;s futex shines with 9% higher throughput and lower average latency. The uncontended fast path and efficient kernel-managed queues work well here. However, look at the per-thread operations: std has 5.6% variation (20.6M vs 19.4M) while parking_lot has only 3.9% (18.9M vs 18.2M). Even in this favorable scenario for std, parking_lot&#8217;s fairness mechanism ensures more even work distribution across threads.</p><h3>Scenario 2: Long Hold (Heavy Contention)</h3><p><strong>Configuration:</strong> 8 threads, 10 seconds, 500&#181;s sleep while holding lock</p><p><strong>Scenario:</strong> This tests heavy contention where threads hold the lock for a long time (500 microseconds). This simulates scenarios like I/O operations, slow computation, or accessing remote resources while holding a lock. With 8 threads competing for a lock that&#8217;s held for 500&#181;s each time, contention is severe.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Qw15!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2306f9-c81b-4035-a4da-a1b68f70c3a9_1800x960.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Qw15!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2306f9-c81b-4035-a4da-a1b68f70c3a9_1800x960.png 424w, https://substackcdn.com/image/fetch/$s_!Qw15!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2306f9-c81b-4035-a4da-a1b68f70c3a9_1800x960.png 848w, https://substackcdn.com/image/fetch/$s_!Qw15!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2306f9-c81b-4035-a4da-a1b68f70c3a9_1800x960.png 1272w, https://substackcdn.com/image/fetch/$s_!Qw15!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2306f9-c81b-4035-a4da-a1b68f70c3a9_1800x960.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Qw15!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2306f9-c81b-4035-a4da-a1b68f70c3a9_1800x960.png" width="1456" height="777" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8a2306f9-c81b-4035-a4da-a1b68f70c3a9_1800x960.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:777,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:125138,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2306f9-c81b-4035-a4da-a1b68f70c3a9_1800x960.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Qw15!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2306f9-c81b-4035-a4da-a1b68f70c3a9_1800x960.png 424w, https://substackcdn.com/image/fetch/$s_!Qw15!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2306f9-c81b-4035-a4da-a1b68f70c3a9_1800x960.png 848w, https://substackcdn.com/image/fetch/$s_!Qw15!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2306f9-c81b-4035-a4da-a1b68f70c3a9_1800x960.png 1272w, https://substackcdn.com/image/fetch/$s_!Qw15!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2306f9-c81b-4035-a4da-a1b68f70c3a9_1800x960.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2-q6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa68288df-cde7-4f8b-82e7-6b23419e8a73_1134x302.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2-q6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa68288df-cde7-4f8b-82e7-6b23419e8a73_1134x302.png 424w, https://substackcdn.com/image/fetch/$s_!2-q6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa68288df-cde7-4f8b-82e7-6b23419e8a73_1134x302.png 848w, https://substackcdn.com/image/fetch/$s_!2-q6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa68288df-cde7-4f8b-82e7-6b23419e8a73_1134x302.png 1272w, https://substackcdn.com/image/fetch/$s_!2-q6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa68288df-cde7-4f8b-82e7-6b23419e8a73_1134x302.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2-q6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa68288df-cde7-4f8b-82e7-6b23419e8a73_1134x302.png" width="1134" height="302" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a68288df-cde7-4f8b-82e7-6b23419e8a73_1134x302.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:302,&quot;width&quot;:1134,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:87282,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa68288df-cde7-4f8b-82e7-6b23419e8a73_1134x302.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2-q6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa68288df-cde7-4f8b-82e7-6b23419e8a73_1134x302.png 424w, https://substackcdn.com/image/fetch/$s_!2-q6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa68288df-cde7-4f8b-82e7-6b23419e8a73_1134x302.png 848w, https://substackcdn.com/image/fetch/$s_!2-q6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa68288df-cde7-4f8b-82e7-6b23419e8a73_1134x302.png 1272w, https://substackcdn.com/image/fetch/$s_!2-q6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa68288df-cde7-4f8b-82e7-6b23419e8a73_1134x302.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Takeaway:</strong> This benchmark reveals std&#8217;s critical weakness under heavy contention. Look at thread 3 in std: it completed only 66 operations while thread 5 completed 1,394. That&#8217;s a 95.3% variation - complete starvation. The extremely low median (125ns) combined with massive standard deviation (188.73ms) shows most lock attempts are fast, but some threads suffer extreme delays and essentially never get the lock.</p><p>parking_lot tells a different story. Every thread completed 860-877 operations (1.9% variation). The fairness mechanism worked exactly as designed. Yes, parking_lot has 7.5% lower throughput and higher median wait time, but that&#8217;s because it&#8217;s ensuring all threads make progress. The 51x more stable wait times (3.67ms vs 188.73ms standard deviation) show the predictability benefit. When fairness matters, parking_lot prevents the pathological starvation that std exhibits.</p><h3>Scenario 3: Burst (Periodic Contention Spikes)</h3><p><strong>Configuration:</strong> 8 threads, 15 seconds, 200ms active / 800ms idle</p><p><strong>Scenario:</strong> This simulates bursty workloads where threads alternate between periods of high activity (200ms of rapid lock acquisitions) and idle periods (800ms sleep). Think of web servers handling traffic spikes, batch processing systems, or applications with periodic activity patterns. This tests how mutexes handle sudden contention spikes followed by quiet periods.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2m9I!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe244d11d-3f22-46cf-91c1-dff34281d3c8_1800x960.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2m9I!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe244d11d-3f22-46cf-91c1-dff34281d3c8_1800x960.png 424w, https://substackcdn.com/image/fetch/$s_!2m9I!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe244d11d-3f22-46cf-91c1-dff34281d3c8_1800x960.png 848w, https://substackcdn.com/image/fetch/$s_!2m9I!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe244d11d-3f22-46cf-91c1-dff34281d3c8_1800x960.png 1272w, https://substackcdn.com/image/fetch/$s_!2m9I!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe244d11d-3f22-46cf-91c1-dff34281d3c8_1800x960.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2m9I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe244d11d-3f22-46cf-91c1-dff34281d3c8_1800x960.png" width="1456" height="777" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e244d11d-3f22-46cf-91c1-dff34281d3c8_1800x960.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:777,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:91034,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe244d11d-3f22-46cf-91c1-dff34281d3c8_1800x960.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2m9I!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe244d11d-3f22-46cf-91c1-dff34281d3c8_1800x960.png 424w, https://substackcdn.com/image/fetch/$s_!2m9I!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe244d11d-3f22-46cf-91c1-dff34281d3c8_1800x960.png 848w, https://substackcdn.com/image/fetch/$s_!2m9I!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe244d11d-3f22-46cf-91c1-dff34281d3c8_1800x960.png 1272w, https://substackcdn.com/image/fetch/$s_!2m9I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe244d11d-3f22-46cf-91c1-dff34281d3c8_1800x960.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R_rJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2db2e-9cca-4f18-83d9-5b9a007d66f5_1134x302.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R_rJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2db2e-9cca-4f18-83d9-5b9a007d66f5_1134x302.png 424w, https://substackcdn.com/image/fetch/$s_!R_rJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2db2e-9cca-4f18-83d9-5b9a007d66f5_1134x302.png 848w, https://substackcdn.com/image/fetch/$s_!R_rJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2db2e-9cca-4f18-83d9-5b9a007d66f5_1134x302.png 1272w, https://substackcdn.com/image/fetch/$s_!R_rJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2db2e-9cca-4f18-83d9-5b9a007d66f5_1134x302.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R_rJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2db2e-9cca-4f18-83d9-5b9a007d66f5_1134x302.png" width="1134" height="302" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/51a2db2e-9cca-4f18-83d9-5b9a007d66f5_1134x302.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:302,&quot;width&quot;:1134,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:85433,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2db2e-9cca-4f18-83d9-5b9a007d66f5_1134x302.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!R_rJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2db2e-9cca-4f18-83d9-5b9a007d66f5_1134x302.png 424w, https://substackcdn.com/image/fetch/$s_!R_rJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2db2e-9cca-4f18-83d9-5b9a007d66f5_1134x302.png 848w, https://substackcdn.com/image/fetch/$s_!R_rJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2db2e-9cca-4f18-83d9-5b9a007d66f5_1134x302.png 1272w, https://substackcdn.com/image/fetch/$s_!R_rJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2db2e-9cca-4f18-83d9-5b9a007d66f5_1134x302.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Takeaway:</strong> parking_lot excels in bursty workloads, achieving 18.5% higher throughput than std. During activity bursts, all 8 threads compete intensely for the lock. parking_lot&#8217;s adaptive spinning and fairness mechanisms handle these periodic spikes better, ensuring more even work distribution (9.9% variation vs 13.6%). The 24.8% more stable wait times show parking_lot handles the transitions between idle and active periods more smoothly. While std has lower tail latencies, parking_lot&#8217;s better stability and fairness during bursts translate to higher overall throughput.</p><h3>Scenario 4: Hog (Monopolization Scenario)</h3><p><strong>Configuration:</strong> 6 threads, 15 seconds, one thread monopolizes (sleeps 500&#181;s while holding lock)</p><p><strong>Scenario:</strong> This tests the worst-case scenario: one &#8220;hog&#8221; thread repeatedly acquires the lock and holds it for 500&#181;s, while 5 other threads compete normally. This simulates real-world situations like priority inversion, where a high-priority or busy thread keeps grabbing the lock immediately after releasing it, potentially starving other threads. Can the mutex prevent monopolization?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Sv15!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8322e2fc-9ad0-4789-8d8a-a363d6fa22fb_1800x960.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Sv15!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8322e2fc-9ad0-4789-8d8a-a363d6fa22fb_1800x960.png 424w, https://substackcdn.com/image/fetch/$s_!Sv15!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8322e2fc-9ad0-4789-8d8a-a363d6fa22fb_1800x960.png 848w, https://substackcdn.com/image/fetch/$s_!Sv15!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8322e2fc-9ad0-4789-8d8a-a363d6fa22fb_1800x960.png 1272w, https://substackcdn.com/image/fetch/$s_!Sv15!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8322e2fc-9ad0-4789-8d8a-a363d6fa22fb_1800x960.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Sv15!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8322e2fc-9ad0-4789-8d8a-a363d6fa22fb_1800x960.png" width="1456" height="777" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8322e2fc-9ad0-4789-8d8a-a363d6fa22fb_1800x960.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:777,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:104889,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8322e2fc-9ad0-4789-8d8a-a363d6fa22fb_1800x960.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Sv15!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8322e2fc-9ad0-4789-8d8a-a363d6fa22fb_1800x960.png 424w, https://substackcdn.com/image/fetch/$s_!Sv15!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8322e2fc-9ad0-4789-8d8a-a363d6fa22fb_1800x960.png 848w, https://substackcdn.com/image/fetch/$s_!Sv15!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8322e2fc-9ad0-4789-8d8a-a363d6fa22fb_1800x960.png 1272w, https://substackcdn.com/image/fetch/$s_!Sv15!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8322e2fc-9ad0-4789-8d8a-a363d6fa22fb_1800x960.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xW_A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab1a3581-cfd5-4c77-b9aa-66b908d59488_1134x302.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xW_A!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab1a3581-cfd5-4c77-b9aa-66b908d59488_1134x302.png 424w, https://substackcdn.com/image/fetch/$s_!xW_A!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab1a3581-cfd5-4c77-b9aa-66b908d59488_1134x302.png 848w, https://substackcdn.com/image/fetch/$s_!xW_A!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab1a3581-cfd5-4c77-b9aa-66b908d59488_1134x302.png 1272w, https://substackcdn.com/image/fetch/$s_!xW_A!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab1a3581-cfd5-4c77-b9aa-66b908d59488_1134x302.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xW_A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab1a3581-cfd5-4c77-b9aa-66b908d59488_1134x302.png" width="1134" height="302" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ab1a3581-cfd5-4c77-b9aa-66b908d59488_1134x302.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:302,&quot;width&quot;:1134,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:91395,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/177427186?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab1a3581-cfd5-4c77-b9aa-66b908d59488_1134x302.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xW_A!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab1a3581-cfd5-4c77-b9aa-66b908d59488_1134x302.png 424w, https://substackcdn.com/image/fetch/$s_!xW_A!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab1a3581-cfd5-4c77-b9aa-66b908d59488_1134x302.png 848w, https://substackcdn.com/image/fetch/$s_!xW_A!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab1a3581-cfd5-4c77-b9aa-66b908d59488_1134x302.png 1272w, https://substackcdn.com/image/fetch/$s_!xW_A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab1a3581-cfd5-4c77-b9aa-66b908d59488_1134x302.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Takeaway:</strong> This is the smoking gun that demonstrates std&#8217;s fundamental unfairness. The hog thread completed 12,242 operations while the other threads completed only 6-16 operations each. That&#8217;s complete starvation - the non-hog threads essentially never got the lock. The 100% variation and 130ms standard deviation show the extreme unpredictability.</p><p>parking_lot&#8217;s fairness timer prevented this catastrophe. The hog still got more operations (9,168) but nowhere near monopolization. All other threads made meaningful progress (7,023-7,109 operations). The result: 261.6% higher overall throughput because all 6 threads contributed work instead of 5 threads sitting idle. The 120x more stable wait times (1.09ms vs 130.76ms) show parking_lot&#8217;s predictability. The 0.5ms fairness timer does exactly what it promises: prevent any thread from monopolizing the lock indefinitely.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">One real Rust problem, unpacked every two weeks.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Decision Guide</h2><p>After diving deep into the implementations and running comprehensive benchmarks, here&#8217;s when to use each:</p><h3>Choose std::Mutex When:</h3><ol><li><p><strong>You need zero dependencies</strong> - It&#8217;s in std, always available</p></li><li><p><strong>Low to moderate contention with short critical sections</strong> - futex implementation is excellent here (9% faster throughput in our short-hold test)</p></li><li><p><strong>You want poisoning for debugging</strong> - Helps catch panic-related bugs during development</p></li><li><p><strong>Platform-specific optimizations matter</strong> - Gets priority inheritance on Fuchsia, etc.</p></li></ol><h3>Choose parking_lot::Mutex When:</h3><ol><li><p><strong>Fairness is critical</strong> - Prevents thread starvation (49x better fairness in heavy contention)</p></li><li><p><strong>Risk of monopolization exists</strong> - The hog scenario showed 261.6% better throughput by preventing starvation</p></li><li><p><strong>Bursty workloads</strong> - 18.5% faster in our burst scenario</p></li><li><p><strong>You need predictable behavior</strong> - 51x more stable latency under heavy load</p></li><li><p><strong>Memory footprint matters</strong> - Always 1 byte regardless of platform</p></li><li><p><strong>You want timeouts or fairness control</strong> - <strong>try_lock_for()</strong>, <strong>unlock_fair()</strong>, etc.</p></li><li><p><strong>Cross-platform consistency is important</strong> - Same behavior everywhere</p></li></ol><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/p/inside-rusts-std-and-parking-lot-mutexes-who-win?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.cuongle.dev/p/inside-rusts-std-and-parking-lot-mutexes-who-win?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><h2>Key Takeaways</h2><p>The benchmarks reveal a fundamental trade-off: <strong>std::Mutex optimizes for throughput in the average case</strong>, while <strong>parking_lot::Mutex optimizes for fairness and predictability in the worst case</strong>.</p><p>For most applications, where contention is light and critical sections are short, std::Mutex performs excellently. But if your application has any of these characteristics:</p><ul><li><p>Long-running critical sections</p></li><li><p>Risk of lock monopolization (e.g., one high-priority thread)</p></li><li><p>Need for predictable latency across all threads</p></li><li><p>Requirement that all threads make forward progress</p></li></ul><p>Then parking_lot::Mutex&#8217;s eventual fairness mechanism becomes invaluable. The 0.5ms fairness timer is a small price to pay for preventing complete thread starvation.</p><p>If you made it this far, you&#8217;re probably as obsessed with understanding how things really work as I am. I&#8217;m Cuong, and I write about Rust and programming. If you share the same passion, I&#8217;d love to connect with you. Feel free to reach out on <a href="https://x.com/cuongleqq">X</a>, <a href="https://www.linkedin.com/in/cuong-le/">LinkedIn</a>, or subscribe to my blog (<a href="https://blog.cuongle.dev/">substack</a>, <a href="https://medium.com/@cuongleqq">medium</a>) to keep pushing the boundaries together!</p>]]></content:encoded></item><item><title><![CDATA[Level Up your Rust pattern matching]]></title><description><![CDATA[Rust&#8217;s pattern matching feels simple enough: match on enums, destructure tuples, handle Option and Result.]]></description><link>https://blog.cuongle.dev/p/level-up-your-rust-pattern-matching</link><guid isPermaLink="false">https://blog.cuongle.dev/p/level-up-your-rust-pattern-matching</guid><dc:creator><![CDATA[Cuong Le]]></dc:creator><pubDate>Mon, 29 Sep 2025 14:09:27 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e87c56dc-d51c-48a5-b0a0-191ca9d7d767_503x266.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Rust&#8217;s pattern matching feels simple enough: match on enums, destructure tuples, handle Option and Result. I stuck with these basics for months because, well, they work. But there&#8217;s a whole world of pattern techniques I wasn&#8217;t using. Once I discovered what&#8217;s actually possible, I kicked myself for all the verbose code I&#8217;d written.</p><p>Here&#8217;s what advanced pattern matching can look like (don&#8217;t worry if you don&#8217;t understand it now):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uTvr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67a390d4-bbb2-4d69-b159-29be061b0b6b_1160x1058.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uTvr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67a390d4-bbb2-4d69-b159-29be061b0b6b_1160x1058.png 424w, https://substackcdn.com/image/fetch/$s_!uTvr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67a390d4-bbb2-4d69-b159-29be061b0b6b_1160x1058.png 848w, https://substackcdn.com/image/fetch/$s_!uTvr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67a390d4-bbb2-4d69-b159-29be061b0b6b_1160x1058.png 1272w, https://substackcdn.com/image/fetch/$s_!uTvr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67a390d4-bbb2-4d69-b159-29be061b0b6b_1160x1058.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uTvr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67a390d4-bbb2-4d69-b159-29be061b0b6b_1160x1058.png" width="1160" height="1058" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/67a390d4-bbb2-4d69-b159-29be061b0b6b_1160x1058.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1058,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:151749,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67a390d4-bbb2-4d69-b159-29be061b0b6b_1160x1058.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uTvr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67a390d4-bbb2-4d69-b159-29be061b0b6b_1160x1058.png 424w, https://substackcdn.com/image/fetch/$s_!uTvr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67a390d4-bbb2-4d69-b159-29be061b0b6b_1160x1058.png 848w, https://substackcdn.com/image/fetch/$s_!uTvr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67a390d4-bbb2-4d69-b159-29be061b0b6b_1160x1058.png 1272w, https://substackcdn.com/image/fetch/$s_!uTvr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67a390d4-bbb2-4d69-b159-29be061b0b6b_1160x1058.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=027d3d0de96b0d0b2d171f068447b053">Rust Playground</a>)</figcaption></figure></div><p>It took me way too long to discover these techniques. This post is so you don&#8217;t have to. I&#8217;ll cover:</p><ul><li><p>The basics (plus hidden details)</p></li><li><p>Advanced techniques that matter</p></li><li><p>Best practices I learned the hard way</p></li></ul><p>Let&#8217;s start with the fundamentals.</p><h2>Basic pattern matching</h2><p>If you&#8217;re already comfortable with basic pattern matching, feel free to skim this section.</p><h3>Matching literals, variables, and wildcards</h3><p>The simplest patterns match exact values or capture anything:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZGOX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3505dd4f-0e85-4d53-8bc0-fd58b0f56866_898x498.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZGOX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3505dd4f-0e85-4d53-8bc0-fd58b0f56866_898x498.png 424w, https://substackcdn.com/image/fetch/$s_!ZGOX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3505dd4f-0e85-4d53-8bc0-fd58b0f56866_898x498.png 848w, https://substackcdn.com/image/fetch/$s_!ZGOX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3505dd4f-0e85-4d53-8bc0-fd58b0f56866_898x498.png 1272w, https://substackcdn.com/image/fetch/$s_!ZGOX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3505dd4f-0e85-4d53-8bc0-fd58b0f56866_898x498.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZGOX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3505dd4f-0e85-4d53-8bc0-fd58b0f56866_898x498.png" width="898" height="498" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3505dd4f-0e85-4d53-8bc0-fd58b0f56866_898x498.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:498,&quot;width&quot;:898,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:96484,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3505dd4f-0e85-4d53-8bc0-fd58b0f56866_898x498.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZGOX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3505dd4f-0e85-4d53-8bc0-fd58b0f56866_898x498.png 424w, https://substackcdn.com/image/fetch/$s_!ZGOX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3505dd4f-0e85-4d53-8bc0-fd58b0f56866_898x498.png 848w, https://substackcdn.com/image/fetch/$s_!ZGOX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3505dd4f-0e85-4d53-8bc0-fd58b0f56866_898x498.png 1272w, https://substackcdn.com/image/fetch/$s_!ZGOX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3505dd4f-0e85-4d53-8bc0-fd58b0f56866_898x498.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=2f22b5477f6fa2d2d74e4b80a0a8186a">Rust Playground</a>)</figcaption></figure></div><p>This example shows:</p><ul><li><p>Literal matching (200)</p></li><li><p><strong>Or</strong> patterns for multiple values (301 | 302 | 307 | 308)</p></li><li><p>Range matching (500..=599)</p></li><li><p>Variable binding (code)</p></li><li><p>Wildcard (_) to ignore the value</p></li></ul><h3>Destructuring tuples and structs</h3><p>Pattern matching shines when breaking apart compound data:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kHve!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F261df817-199b-4e7d-82f7-c2eda5de2139_1160x908.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kHve!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F261df817-199b-4e7d-82f7-c2eda5de2139_1160x908.png 424w, https://substackcdn.com/image/fetch/$s_!kHve!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F261df817-199b-4e7d-82f7-c2eda5de2139_1160x908.png 848w, https://substackcdn.com/image/fetch/$s_!kHve!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F261df817-199b-4e7d-82f7-c2eda5de2139_1160x908.png 1272w, https://substackcdn.com/image/fetch/$s_!kHve!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F261df817-199b-4e7d-82f7-c2eda5de2139_1160x908.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kHve!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F261df817-199b-4e7d-82f7-c2eda5de2139_1160x908.png" width="1160" height="908" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/261df817-199b-4e7d-82f7-c2eda5de2139_1160x908.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:908,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:128511,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F261df817-199b-4e7d-82f7-c2eda5de2139_1160x908.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kHve!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F261df817-199b-4e7d-82f7-c2eda5de2139_1160x908.png 424w, https://substackcdn.com/image/fetch/$s_!kHve!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F261df817-199b-4e7d-82f7-c2eda5de2139_1160x908.png 848w, https://substackcdn.com/image/fetch/$s_!kHve!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F261df817-199b-4e7d-82f7-c2eda5de2139_1160x908.png 1272w, https://substackcdn.com/image/fetch/$s_!kHve!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F261df817-199b-4e7d-82f7-c2eda5de2139_1160x908.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=83ce62998b60f6bafc5a5d94c7c76d3b">Rust Playground</a>)</figcaption></figure></div><p>Key points:</p><ul><li><p><strong>..</strong> ignores remaining fields you don&#8217;t care about</p></li><li><p>Patterns are checked top-to-bottom, so <strong>active: false</strong> catches inactive users first</p></li></ul><h3>Working with arrays and slices</h3><p>You can match on array and slice structure:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ybky!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708bea0e-5db3-4d8e-95dd-b5b2d3308f37_1160x864.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ybky!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708bea0e-5db3-4d8e-95dd-b5b2d3308f37_1160x864.png 424w, https://substackcdn.com/image/fetch/$s_!ybky!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708bea0e-5db3-4d8e-95dd-b5b2d3308f37_1160x864.png 848w, https://substackcdn.com/image/fetch/$s_!ybky!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708bea0e-5db3-4d8e-95dd-b5b2d3308f37_1160x864.png 1272w, https://substackcdn.com/image/fetch/$s_!ybky!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708bea0e-5db3-4d8e-95dd-b5b2d3308f37_1160x864.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ybky!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708bea0e-5db3-4d8e-95dd-b5b2d3308f37_1160x864.png" width="1160" height="864" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/708bea0e-5db3-4d8e-95dd-b5b2d3308f37_1160x864.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:864,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:129680,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708bea0e-5db3-4d8e-95dd-b5b2d3308f37_1160x864.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ybky!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708bea0e-5db3-4d8e-95dd-b5b2d3308f37_1160x864.png 424w, https://substackcdn.com/image/fetch/$s_!ybky!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708bea0e-5db3-4d8e-95dd-b5b2d3308f37_1160x864.png 848w, https://substackcdn.com/image/fetch/$s_!ybky!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708bea0e-5db3-4d8e-95dd-b5b2d3308f37_1160x864.png 1272w, https://substackcdn.com/image/fetch/$s_!ybky!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708bea0e-5db3-4d8e-95dd-b5b2d3308f37_1160x864.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=83ce62998b60f6bafc5a5d94c7c76d3b">Rust Playground</a>)</figcaption></figure></div><p>Notice the difference: The array match requires exactly 5 elements, while slice patterns adapt to any length. The <strong>..</strong> matches however many elements are between the specified positions.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Want more like this? Rust and systems, from real work. Every two weeks.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Advanced techniques</h2><p>Time for the fun stuff. These techniques will make your code beautiful and a joy to write.</p><h3>Taking references instead of consuming values</h3><p>By default, pattern matching moves values, like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!V7Vp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29d42a77-08ed-4d18-9995-08276bd39fc6_1160x498.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!V7Vp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29d42a77-08ed-4d18-9995-08276bd39fc6_1160x498.png 424w, https://substackcdn.com/image/fetch/$s_!V7Vp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29d42a77-08ed-4d18-9995-08276bd39fc6_1160x498.png 848w, https://substackcdn.com/image/fetch/$s_!V7Vp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29d42a77-08ed-4d18-9995-08276bd39fc6_1160x498.png 1272w, https://substackcdn.com/image/fetch/$s_!V7Vp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29d42a77-08ed-4d18-9995-08276bd39fc6_1160x498.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!V7Vp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29d42a77-08ed-4d18-9995-08276bd39fc6_1160x498.png" width="1160" height="498" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/29d42a77-08ed-4d18-9995-08276bd39fc6_1160x498.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:498,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:81308,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29d42a77-08ed-4d18-9995-08276bd39fc6_1160x498.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!V7Vp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29d42a77-08ed-4d18-9995-08276bd39fc6_1160x498.png 424w, https://substackcdn.com/image/fetch/$s_!V7Vp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29d42a77-08ed-4d18-9995-08276bd39fc6_1160x498.png 848w, https://substackcdn.com/image/fetch/$s_!V7Vp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29d42a77-08ed-4d18-9995-08276bd39fc6_1160x498.png 1272w, https://substackcdn.com/image/fetch/$s_!V7Vp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29d42a77-08ed-4d18-9995-08276bd39fc6_1160x498.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=81c1369cf6e13f4f5f17a91fd4d6e1b5">Rust Playground</a>)</figcaption></figure></div><p>When we match <strong>Some(s)</strong>, Rust transfers ownership of the <strong>String</strong> to variable <strong>s</strong>. This leaves <strong>data</strong> partially moved since the <strong>Option</strong> wrapper exists but its contents are gone. Rust prevents using partially moved values.</p><p>But you can work with references using two approaches below.</p><p><strong>First approach: Match on a reference</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wwRG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cef8db-6a61-4674-af12-ccc59e2fd310_1160x386.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wwRG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cef8db-6a61-4674-af12-ccc59e2fd310_1160x386.png 424w, https://substackcdn.com/image/fetch/$s_!wwRG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cef8db-6a61-4674-af12-ccc59e2fd310_1160x386.png 848w, https://substackcdn.com/image/fetch/$s_!wwRG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cef8db-6a61-4674-af12-ccc59e2fd310_1160x386.png 1272w, https://substackcdn.com/image/fetch/$s_!wwRG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cef8db-6a61-4674-af12-ccc59e2fd310_1160x386.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wwRG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cef8db-6a61-4674-af12-ccc59e2fd310_1160x386.png" width="1160" height="386" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e0cef8db-6a61-4674-af12-ccc59e2fd310_1160x386.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:386,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:71344,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cef8db-6a61-4674-af12-ccc59e2fd310_1160x386.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wwRG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cef8db-6a61-4674-af12-ccc59e2fd310_1160x386.png 424w, https://substackcdn.com/image/fetch/$s_!wwRG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cef8db-6a61-4674-af12-ccc59e2fd310_1160x386.png 848w, https://substackcdn.com/image/fetch/$s_!wwRG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cef8db-6a61-4674-af12-ccc59e2fd310_1160x386.png 1272w, https://substackcdn.com/image/fetch/$s_!wwRG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cef8db-6a61-4674-af12-ccc59e2fd310_1160x386.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=65da114045a76d35c1dcae4e2d91f0da">Rust Playground</a>)</figcaption></figure></div><p>Notice the match is on <strong>&amp;data</strong>, Rust automatically borrows the inner fields for you.</p><p><strong>Second approach: Use ref</strong></p><p>You can achieve the same goal using <strong>ref</strong>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LcGP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffefd2ee7-ec4f-4a70-ae10-8ff25d7bd3d5_1160x386.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LcGP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffefd2ee7-ec4f-4a70-ae10-8ff25d7bd3d5_1160x386.png 424w, https://substackcdn.com/image/fetch/$s_!LcGP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffefd2ee7-ec4f-4a70-ae10-8ff25d7bd3d5_1160x386.png 848w, https://substackcdn.com/image/fetch/$s_!LcGP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffefd2ee7-ec4f-4a70-ae10-8ff25d7bd3d5_1160x386.png 1272w, https://substackcdn.com/image/fetch/$s_!LcGP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffefd2ee7-ec4f-4a70-ae10-8ff25d7bd3d5_1160x386.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LcGP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffefd2ee7-ec4f-4a70-ae10-8ff25d7bd3d5_1160x386.png" width="1160" height="386" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fefd2ee7-ec4f-4a70-ae10-8ff25d7bd3d5_1160x386.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:386,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:79992,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffefd2ee7-ec4f-4a70-ae10-8ff25d7bd3d5_1160x386.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LcGP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffefd2ee7-ec4f-4a70-ae10-8ff25d7bd3d5_1160x386.png 424w, https://substackcdn.com/image/fetch/$s_!LcGP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffefd2ee7-ec4f-4a70-ae10-8ff25d7bd3d5_1160x386.png 848w, https://substackcdn.com/image/fetch/$s_!LcGP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffefd2ee7-ec4f-4a70-ae10-8ff25d7bd3d5_1160x386.png 1272w, https://substackcdn.com/image/fetch/$s_!LcGP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffefd2ee7-ec4f-4a70-ae10-8ff25d7bd3d5_1160x386.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=33db00565b87d53255b3d4bb65749c09">Rust Playground</a>)</figcaption></figure></div><p>But wait, if using <strong>&amp;</strong> and <strong>ref</strong> is just doing the same thing, why do we even need ref?</p><p>Ref shines when you want to mix move and borrow of the same object. Look at this example:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ETAc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37867ea0-4e5f-445e-8078-bc6c1c244b77_1160x760.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ETAc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37867ea0-4e5f-445e-8078-bc6c1c244b77_1160x760.png 424w, https://substackcdn.com/image/fetch/$s_!ETAc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37867ea0-4e5f-445e-8078-bc6c1c244b77_1160x760.png 848w, https://substackcdn.com/image/fetch/$s_!ETAc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37867ea0-4e5f-445e-8078-bc6c1c244b77_1160x760.png 1272w, https://substackcdn.com/image/fetch/$s_!ETAc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37867ea0-4e5f-445e-8078-bc6c1c244b77_1160x760.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ETAc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37867ea0-4e5f-445e-8078-bc6c1c244b77_1160x760.png" width="1160" height="760" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/37867ea0-4e5f-445e-8078-bc6c1c244b77_1160x760.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:760,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:133116,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37867ea0-4e5f-445e-8078-bc6c1c244b77_1160x760.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ETAc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37867ea0-4e5f-445e-8078-bc6c1c244b77_1160x760.png 424w, https://substackcdn.com/image/fetch/$s_!ETAc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37867ea0-4e5f-445e-8078-bc6c1c244b77_1160x760.png 848w, https://substackcdn.com/image/fetch/$s_!ETAc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37867ea0-4e5f-445e-8078-bc6c1c244b77_1160x760.png 1272w, https://substackcdn.com/image/fetch/$s_!ETAc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37867ea0-4e5f-445e-8078-bc6c1c244b77_1160x760.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=6678b1cedff89f2e287895b3e6866328">Rust Playground</a>)</figcaption></figure></div><p>In this example, we move <strong>user_id</strong> (cheap to copy) but borrow <strong>image</strong> (potentially large) for the quota check, and keep <strong>task</strong> intact for passing to <strong>do_task</strong> later.</p><p>Why <strong>ref</strong> works better than alternatives:</p><ul><li><p><strong>&amp;task approach</strong>: Forces <strong>user_id</strong> to be <strong>&amp;u64</strong> instead of <strong>u64</strong>, adding unnecessary indirection for a Copy type</p></li><li><p><strong>Owned matching</strong>: Consumes the entire <strong>task</strong>, making it unavailable for <strong>do_task(task)</strong> later</p></li></ul><h3>Match guards</h3><p>So far, patterns let us match exact values or ranges. But what about much more complicated conditions?</p><p>Guards let you add any boolean expression after the pattern matches:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bByx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f8a0253-948a-4fc9-bb79-eb892cba1f19_1160x462.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bByx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f8a0253-948a-4fc9-bb79-eb892cba1f19_1160x462.png 424w, https://substackcdn.com/image/fetch/$s_!bByx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f8a0253-948a-4fc9-bb79-eb892cba1f19_1160x462.png 848w, https://substackcdn.com/image/fetch/$s_!bByx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f8a0253-948a-4fc9-bb79-eb892cba1f19_1160x462.png 1272w, https://substackcdn.com/image/fetch/$s_!bByx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f8a0253-948a-4fc9-bb79-eb892cba1f19_1160x462.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bByx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f8a0253-948a-4fc9-bb79-eb892cba1f19_1160x462.png" width="1160" height="462" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5f8a0253-948a-4fc9-bb79-eb892cba1f19_1160x462.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:462,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:72890,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f8a0253-948a-4fc9-bb79-eb892cba1f19_1160x462.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bByx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f8a0253-948a-4fc9-bb79-eb892cba1f19_1160x462.png 424w, https://substackcdn.com/image/fetch/$s_!bByx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f8a0253-948a-4fc9-bb79-eb892cba1f19_1160x462.png 848w, https://substackcdn.com/image/fetch/$s_!bByx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f8a0253-948a-4fc9-bb79-eb892cba1f19_1160x462.png 1272w, https://substackcdn.com/image/fetch/$s_!bByx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f8a0253-948a-4fc9-bb79-eb892cba1f19_1160x462.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in Rust <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=eec1eb9daa3b38375fa53895ff715a79">Playground</a>)</figcaption></figure></div><p><strong>Important:</strong> Rust evaluates patterns first, then guards. The pattern extracts values (like <strong>url</strong> or <strong>path</strong> from <strong>Some</strong>), making them available for the guard condition. If the guard fails, Rust moves to the next pattern.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Rust from first principles, explained plainly. A new deep dive every two weeks.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h3>Binding the whole value with @</h3><p>So far, patterns let you destructure data into its components. But what if you want to match on structure while keeping the whole value for function calls? Enter the <strong>@</strong> symbol. Not sure why they picked that particular character, but here&#8217;s how it works:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!V0Rw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4be915d6-7d11-4b3e-a7cb-564226a782f8_1160x574.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!V0Rw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4be915d6-7d11-4b3e-a7cb-564226a782f8_1160x574.png 424w, https://substackcdn.com/image/fetch/$s_!V0Rw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4be915d6-7d11-4b3e-a7cb-564226a782f8_1160x574.png 848w, https://substackcdn.com/image/fetch/$s_!V0Rw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4be915d6-7d11-4b3e-a7cb-564226a782f8_1160x574.png 1272w, https://substackcdn.com/image/fetch/$s_!V0Rw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4be915d6-7d11-4b3e-a7cb-564226a782f8_1160x574.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!V0Rw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4be915d6-7d11-4b3e-a7cb-564226a782f8_1160x574.png" width="1160" height="574" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4be915d6-7d11-4b3e-a7cb-564226a782f8_1160x574.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:574,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:96835,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4be915d6-7d11-4b3e-a7cb-564226a782f8_1160x574.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!V0Rw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4be915d6-7d11-4b3e-a7cb-564226a782f8_1160x574.png 424w, https://substackcdn.com/image/fetch/$s_!V0Rw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4be915d6-7d11-4b3e-a7cb-564226a782f8_1160x574.png 848w, https://substackcdn.com/image/fetch/$s_!V0Rw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4be915d6-7d11-4b3e-a7cb-564226a782f8_1160x574.png 1272w, https://substackcdn.com/image/fetch/$s_!V0Rw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4be915d6-7d11-4b3e-a7cb-564226a782f8_1160x574.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in Rust <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=971c33758045ac86013bf70eba452fe7">Playground</a>)</figcaption></figure></div><p>Now that you&#8217;ve seen the advanced techniques, let&#8217;s step back and look at the bigger picture. Pattern matching isn&#8217;t limited to <strong>match</strong> expressions&#8212;Rust lets you use patterns in several different contexts, each with its own rules.</p><h2>Where patterns are allowed</h2><p>Rust divides pattern contexts into two categories based on whether the pattern must always succeed.</p><ul><li><p><strong>Irrefutable patterns</strong>: Destructure data with known structure (let bindings, function parameters)</p></li><li><p><strong>Refutable patterns</strong>: Handle multiple possibilities with conditional logic (match, if let)</p></li></ul><h3>Irrefutable patterns</h3><p>These contexts require patterns that always succeed:<strong> </strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xzIf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3dd922e-fac5-4065-ae62-db0f4a409fc2_1160x834.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xzIf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3dd922e-fac5-4065-ae62-db0f4a409fc2_1160x834.png 424w, https://substackcdn.com/image/fetch/$s_!xzIf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3dd922e-fac5-4065-ae62-db0f4a409fc2_1160x834.png 848w, https://substackcdn.com/image/fetch/$s_!xzIf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3dd922e-fac5-4065-ae62-db0f4a409fc2_1160x834.png 1272w, https://substackcdn.com/image/fetch/$s_!xzIf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3dd922e-fac5-4065-ae62-db0f4a409fc2_1160x834.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xzIf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3dd922e-fac5-4065-ae62-db0f4a409fc2_1160x834.png" width="1160" height="834" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b3dd922e-fac5-4065-ae62-db0f4a409fc2_1160x834.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:834,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:143737,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3dd922e-fac5-4065-ae62-db0f4a409fc2_1160x834.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xzIf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3dd922e-fac5-4065-ae62-db0f4a409fc2_1160x834.png 424w, https://substackcdn.com/image/fetch/$s_!xzIf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3dd922e-fac5-4065-ae62-db0f4a409fc2_1160x834.png 848w, https://substackcdn.com/image/fetch/$s_!xzIf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3dd922e-fac5-4065-ae62-db0f4a409fc2_1160x834.png 1272w, https://substackcdn.com/image/fetch/$s_!xzIf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3dd922e-fac5-4065-ae62-db0f4a409fc2_1160x834.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in Rust <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=2bf5a9152638d9244c55bf82460eab9a">Playground</a>)</figcaption></figure></div><h3>Refutable patterns</h3><p>These contexts handle patterns that might not match:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xEFy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8de6445-b06b-4041-a89a-1935b72dc4e5_1160x872.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xEFy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8de6445-b06b-4041-a89a-1935b72dc4e5_1160x872.png 424w, https://substackcdn.com/image/fetch/$s_!xEFy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8de6445-b06b-4041-a89a-1935b72dc4e5_1160x872.png 848w, https://substackcdn.com/image/fetch/$s_!xEFy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8de6445-b06b-4041-a89a-1935b72dc4e5_1160x872.png 1272w, https://substackcdn.com/image/fetch/$s_!xEFy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8de6445-b06b-4041-a89a-1935b72dc4e5_1160x872.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xEFy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8de6445-b06b-4041-a89a-1935b72dc4e5_1160x872.png" width="1160" height="872" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f8de6445-b06b-4041-a89a-1935b72dc4e5_1160x872.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:872,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:142151,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8de6445-b06b-4041-a89a-1935b72dc4e5_1160x872.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xEFy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8de6445-b06b-4041-a89a-1935b72dc4e5_1160x872.png 424w, https://substackcdn.com/image/fetch/$s_!xEFy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8de6445-b06b-4041-a89a-1935b72dc4e5_1160x872.png 848w, https://substackcdn.com/image/fetch/$s_!xEFy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8de6445-b06b-4041-a89a-1935b72dc4e5_1160x872.png 1272w, https://substackcdn.com/image/fetch/$s_!xEFy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8de6445-b06b-4041-a89a-1935b72dc4e5_1160x872.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in Rust <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=8ffbccfa67c5a277502a9d17e55f3e25">Playground</a>)</figcaption></figure></div><p>let-else is interesting. It&#8217;s relatively new (Rust 1.65). It requires the <strong>else</strong> block to diverge (it must <strong>return</strong>, <strong>panic!</strong>, or exit the function). This ensures the variable is definitely assigned if execution continues.</p><h2>Best practices</h2><p>Here are some guidelines for using pattern matching effectively in real-world Rust code.</p><h3>Consider performance for hot paths</h3><p>Match patterns are checked top-down, so put specific patterns before general ones to avoid unreachable arms. For complex conditions where order doesn&#8217;t affect logic, prioritize hot paths or cheaper conditions first (see example below).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nllS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276ed220-7087-47f3-a75f-6402b16c0ea4_1160x722.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nllS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276ed220-7087-47f3-a75f-6402b16c0ea4_1160x722.png 424w, https://substackcdn.com/image/fetch/$s_!nllS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276ed220-7087-47f3-a75f-6402b16c0ea4_1160x722.png 848w, https://substackcdn.com/image/fetch/$s_!nllS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276ed220-7087-47f3-a75f-6402b16c0ea4_1160x722.png 1272w, https://substackcdn.com/image/fetch/$s_!nllS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276ed220-7087-47f3-a75f-6402b16c0ea4_1160x722.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nllS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276ed220-7087-47f3-a75f-6402b16c0ea4_1160x722.png" width="1160" height="722" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/276ed220-7087-47f3-a75f-6402b16c0ea4_1160x722.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:722,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:132394,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276ed220-7087-47f3-a75f-6402b16c0ea4_1160x722.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nllS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276ed220-7087-47f3-a75f-6402b16c0ea4_1160x722.png 424w, https://substackcdn.com/image/fetch/$s_!nllS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276ed220-7087-47f3-a75f-6402b16c0ea4_1160x722.png 848w, https://substackcdn.com/image/fetch/$s_!nllS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276ed220-7087-47f3-a75f-6402b16c0ea4_1160x722.png 1272w, https://substackcdn.com/image/fetch/$s_!nllS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276ed220-7087-47f3-a75f-6402b16c0ea4_1160x722.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in Rust <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=848cbc863ea872e6b55457bad23d2719">Playground</a>)</figcaption></figure></div><p>Note: For simple enum or integer matches, the compiler generates efficient jump tables regardless of arm order. So this rule doesn&#8217;t apply.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">What worked, what did not, and why. New post every two weeks.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h3>Prefer match over if/else chains for enums</h3><p>When handling enums, prefer <strong>match</strong> over if/else chains for better compiler optimization and exhaustiveness checking. While both approaches often compile to similar code in release mode, <strong>match</strong> gives the compiler more information to work with, and there are cases where if/else chains prevent certain optimizations that <strong>match</strong> enables.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Drwm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F400563f6-c16a-4209-95fb-7a9e1da86040_1160x684.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Drwm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F400563f6-c16a-4209-95fb-7a9e1da86040_1160x684.png 424w, https://substackcdn.com/image/fetch/$s_!Drwm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F400563f6-c16a-4209-95fb-7a9e1da86040_1160x684.png 848w, https://substackcdn.com/image/fetch/$s_!Drwm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F400563f6-c16a-4209-95fb-7a9e1da86040_1160x684.png 1272w, https://substackcdn.com/image/fetch/$s_!Drwm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F400563f6-c16a-4209-95fb-7a9e1da86040_1160x684.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Drwm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F400563f6-c16a-4209-95fb-7a9e1da86040_1160x684.png" width="1160" height="684" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/400563f6-c16a-4209-95fb-7a9e1da86040_1160x684.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:684,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:144093,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F400563f6-c16a-4209-95fb-7a9e1da86040_1160x684.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Drwm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F400563f6-c16a-4209-95fb-7a9e1da86040_1160x684.png 424w, https://substackcdn.com/image/fetch/$s_!Drwm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F400563f6-c16a-4209-95fb-7a9e1da86040_1160x684.png 848w, https://substackcdn.com/image/fetch/$s_!Drwm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F400563f6-c16a-4209-95fb-7a9e1da86040_1160x684.png 1272w, https://substackcdn.com/image/fetch/$s_!Drwm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F400563f6-c16a-4209-95fb-7a9e1da86040_1160x684.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in Rust <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=44c9e19ab9d5d67add80565f2cb7cf8a">Playground</a>)</figcaption></figure></div><h3>Destructure multiple fields in one pattern</h3><p>When you need several fields from a struct, destructure them all in the pattern instead of accessing them individually:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vPqN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23688ac-75a4-4432-8a70-603b3c8cb088_1160x796.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vPqN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23688ac-75a4-4432-8a70-603b3c8cb088_1160x796.png 424w, https://substackcdn.com/image/fetch/$s_!vPqN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23688ac-75a4-4432-8a70-603b3c8cb088_1160x796.png 848w, https://substackcdn.com/image/fetch/$s_!vPqN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23688ac-75a4-4432-8a70-603b3c8cb088_1160x796.png 1272w, https://substackcdn.com/image/fetch/$s_!vPqN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23688ac-75a4-4432-8a70-603b3c8cb088_1160x796.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vPqN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23688ac-75a4-4432-8a70-603b3c8cb088_1160x796.png" width="1160" height="796" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f23688ac-75a4-4432-8a70-603b3c8cb088_1160x796.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:796,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:130654,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23688ac-75a4-4432-8a70-603b3c8cb088_1160x796.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vPqN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23688ac-75a4-4432-8a70-603b3c8cb088_1160x796.png 424w, https://substackcdn.com/image/fetch/$s_!vPqN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23688ac-75a4-4432-8a70-603b3c8cb088_1160x796.png 848w, https://substackcdn.com/image/fetch/$s_!vPqN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23688ac-75a4-4432-8a70-603b3c8cb088_1160x796.png 1272w, https://substackcdn.com/image/fetch/$s_!vPqN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23688ac-75a4-4432-8a70-603b3c8cb088_1160x796.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in Rust <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=0858e19e7fdacc5e8398056ceeefbdfd">Playground</a>)</figcaption></figure></div><p>This makes the data dependencies explicit and often reads more clearly than repeated field access.</p><h3>Use matches! for simple boolean checks</h3><p>For yes/no questions, <strong>matches!</strong> is more concise than single-arm match:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!w_ZR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7833468-49db-4ea8-9693-63b440ac6443_1160x684.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!w_ZR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7833468-49db-4ea8-9693-63b440ac6443_1160x684.png 424w, https://substackcdn.com/image/fetch/$s_!w_ZR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7833468-49db-4ea8-9693-63b440ac6443_1160x684.png 848w, https://substackcdn.com/image/fetch/$s_!w_ZR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7833468-49db-4ea8-9693-63b440ac6443_1160x684.png 1272w, https://substackcdn.com/image/fetch/$s_!w_ZR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7833468-49db-4ea8-9693-63b440ac6443_1160x684.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!w_ZR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7833468-49db-4ea8-9693-63b440ac6443_1160x684.png" width="1160" height="684" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f7833468-49db-4ea8-9693-63b440ac6443_1160x684.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:684,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:105421,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/174808868?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7833468-49db-4ea8-9693-63b440ac6443_1160x684.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!w_ZR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7833468-49db-4ea8-9693-63b440ac6443_1160x684.png 424w, https://substackcdn.com/image/fetch/$s_!w_ZR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7833468-49db-4ea8-9693-63b440ac6443_1160x684.png 848w, https://substackcdn.com/image/fetch/$s_!w_ZR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7833468-49db-4ea8-9693-63b440ac6443_1160x684.png 1272w, https://substackcdn.com/image/fetch/$s_!w_ZR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7833468-49db-4ea8-9693-63b440ac6443_1160x684.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Open in Rust <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=a810306442fe399d0001666cad4077d2">Playground</a>)</figcaption></figure></div><p>These practices help you write pattern matching code that&#8217;s both performant and maintainable. The key is choosing the right tool for each situation rather than defaulting to complex <strong>match</strong> expressions everywhere.</p><h2>Key takeaways</h2><p>Pattern matching is one of Rust&#8217;s most distinctive features, and mastering it transforms how you write Rust code. If you can&#8217;t remember everything from this post, bookmark it and come back when you need any of these:</p><ul><li><p>Advanced destructuring with tuples, structs, arrays, and slices</p></li><li><p>Reference patterns and match ergonomics for ownership control</p></li><li><p>Strategic use of guards, and <strong>@</strong> bindings</p></li><li><p>Best practices for choosing the right pattern matching tool</p></li></ul><p>With these techniques in your toolkit, you&#8217;ll write more expressive, safer, and more maintainable Rust code.</p><p>If you made it this far, you&#8217;re probably as obsessed with understanding how things really work as I am. I&#8217;m Cuong, and I write about Rust and programming. If you share the same passion, I&#8217;d love to connect with you. Feel free to reach out on <a href="https://x.com/cuongleqq">X</a>, <a href="https://www.linkedin.com/in/cuong-le/">LinkedIn</a>, or subscribe to my blog (<a href="https://blog.cuongle.dev/">substack</a>, <a href="https://medium.com/@cuongleqq">medium</a>) to keep pushing the boundaries together!</p>]]></content:encoded></item><item><title><![CDATA[The Hidden Rules Behind Rust Functions & Closures ]]></title><description><![CDATA[Demystifying fn, Fn, FnMut, and FnOnce from everyday usage to compiler magic under the hood]]></description><link>https://blog.cuongle.dev/p/the-hidden-rules-behind-rust-functions</link><guid isPermaLink="false">https://blog.cuongle.dev/p/the-hidden-rules-behind-rust-functions</guid><dc:creator><![CDATA[Cuong Le]]></dc:creator><pubDate>Wed, 10 Sep 2025 14:34:44 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!89eA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b843acf-a4eb-4014-a4f4-ee2cec2429c4_1370x1202.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Rust is famous for its steep learning curve for a reason. Besides the borrow checker, lifetime, and many other concepts, functions and closures are among the most confusing concepts to grasp for Rust newcomers. Take a look:</p><p><strong>Example 1: Function and Closure Confusion</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sYrG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F718a35c4-e751-470f-a68d-44e8fc65cab2_920x602.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sYrG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F718a35c4-e751-470f-a68d-44e8fc65cab2_920x602.png 424w, https://substackcdn.com/image/fetch/$s_!sYrG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F718a35c4-e751-470f-a68d-44e8fc65cab2_920x602.png 848w, https://substackcdn.com/image/fetch/$s_!sYrG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F718a35c4-e751-470f-a68d-44e8fc65cab2_920x602.png 1272w, https://substackcdn.com/image/fetch/$s_!sYrG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F718a35c4-e751-470f-a68d-44e8fc65cab2_920x602.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sYrG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F718a35c4-e751-470f-a68d-44e8fc65cab2_920x602.png" width="920" height="602" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/718a35c4-e751-470f-a68d-44e8fc65cab2_920x602.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:602,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:89949,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F718a35c4-e751-470f-a68d-44e8fc65cab2_920x602.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sYrG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F718a35c4-e751-470f-a68d-44e8fc65cab2_920x602.png 424w, https://substackcdn.com/image/fetch/$s_!sYrG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F718a35c4-e751-470f-a68d-44e8fc65cab2_920x602.png 848w, https://substackcdn.com/image/fetch/$s_!sYrG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F718a35c4-e751-470f-a68d-44e8fc65cab2_920x602.png 1272w, https://substackcdn.com/image/fetch/$s_!sYrG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F718a35c4-e751-470f-a68d-44e8fc65cab2_920x602.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>process_data</strong> expects a function that takes an <strong>i32</strong> and returns an <strong>i32</strong>. Both closures match this signature exactly. The first closure <strong>|x| x + 1</strong> works perfectly, but the second closure <strong>|x| x * multiplier</strong> fails. What's the difference?</p><p><strong>Error:</strong><em> error[E0308]: mismatched types (expected fn pointer, found closure)</em></p><p><strong>Example 2: Variable Capturing Confusion</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rh57!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b87b69-5ccf-4514-98fc-980939a95f70_920x564.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rh57!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b87b69-5ccf-4514-98fc-980939a95f70_920x564.png 424w, https://substackcdn.com/image/fetch/$s_!rh57!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b87b69-5ccf-4514-98fc-980939a95f70_920x564.png 848w, https://substackcdn.com/image/fetch/$s_!rh57!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b87b69-5ccf-4514-98fc-980939a95f70_920x564.png 1272w, https://substackcdn.com/image/fetch/$s_!rh57!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b87b69-5ccf-4514-98fc-980939a95f70_920x564.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rh57!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b87b69-5ccf-4514-98fc-980939a95f70_920x564.png" width="920" height="564" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/76b87b69-5ccf-4514-98fc-980939a95f70_920x564.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:564,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:96934,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b87b69-5ccf-4514-98fc-980939a95f70_920x564.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rh57!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b87b69-5ccf-4514-98fc-980939a95f70_920x564.png 424w, https://substackcdn.com/image/fetch/$s_!rh57!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b87b69-5ccf-4514-98fc-980939a95f70_920x564.png 848w, https://substackcdn.com/image/fetch/$s_!rh57!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b87b69-5ccf-4514-98fc-980939a95f70_920x564.png 1272w, https://substackcdn.com/image/fetch/$s_!rh57!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b87b69-5ccf-4514-98fc-980939a95f70_920x564.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Both closures use <strong>data</strong>, but one works multiple times while the other stops working after the first call. What's the difference?</p><p><strong>Error:</strong> <strong>error[E0382]: use of moved value: 'closure2'</strong></p><div><hr></div><p>If you've encountered any of these scenarios, you're not alone. In this post, I'll:</p><ul><li><p>Explain what functions and closures (with their traits) really are</p></li><li><p>Show the relationships between them</p></li><li><p>Dive into the internals that explain these confusing behaviors</p></li></ul><p>By the end, you'll have mastered one of Rust's most difficult topics inside out. Let's go.</p><h2>Function &amp; Function Pointer</h2><p>Let's start by examining how Rust handles regular functions. There are some surprising details about function types that most developers never encounter.</p><h3>Function</h3><p>A function in Rust is exactly what you'd expect:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Xn-I!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6199aece-5e26-4062-9759-2f327f171300_920x444.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Xn-I!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6199aece-5e26-4062-9759-2f327f171300_920x444.png 424w, https://substackcdn.com/image/fetch/$s_!Xn-I!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6199aece-5e26-4062-9759-2f327f171300_920x444.png 848w, https://substackcdn.com/image/fetch/$s_!Xn-I!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6199aece-5e26-4062-9759-2f327f171300_920x444.png 1272w, https://substackcdn.com/image/fetch/$s_!Xn-I!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6199aece-5e26-4062-9759-2f327f171300_920x444.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Xn-I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6199aece-5e26-4062-9759-2f327f171300_920x444.png" width="920" height="444" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6199aece-5e26-4062-9759-2f327f171300_920x444.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:444,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:52209,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6199aece-5e26-4062-9759-2f327f171300_920x444.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Xn-I!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6199aece-5e26-4062-9759-2f327f171300_920x444.png 424w, https://substackcdn.com/image/fetch/$s_!Xn-I!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6199aece-5e26-4062-9759-2f327f171300_920x444.png 848w, https://substackcdn.com/image/fetch/$s_!Xn-I!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6199aece-5e26-4062-9759-2f327f171300_920x444.png 1272w, https://substackcdn.com/image/fetch/$s_!Xn-I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6199aece-5e26-4062-9759-2f327f171300_920x444.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Simple enough. But here's where it gets interesting: when you mention a function by name like <strong>add_one</strong>, you don't get a pointer to it. Instead, you get a special zero-sized value that represents that exact function, and calling it is a direct call. This zero-sized value is called a <strong>function item</strong>.</p><h3>Function Item</h3><p>Every function you define creates a unique, zero-sized type called a function item. This type is compiler-generated and cannot be named directly in your code:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!see0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe35ac8-cc14-4b24-b1b8-e3174f3b246c_920x742.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!see0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe35ac8-cc14-4b24-b1b8-e3174f3b246c_920x742.png 424w, https://substackcdn.com/image/fetch/$s_!see0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe35ac8-cc14-4b24-b1b8-e3174f3b246c_920x742.png 848w, https://substackcdn.com/image/fetch/$s_!see0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe35ac8-cc14-4b24-b1b8-e3174f3b246c_920x742.png 1272w, https://substackcdn.com/image/fetch/$s_!see0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe35ac8-cc14-4b24-b1b8-e3174f3b246c_920x742.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!see0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe35ac8-cc14-4b24-b1b8-e3174f3b246c_920x742.png" width="920" height="742" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dbe35ac8-cc14-4b24-b1b8-e3174f3b246c_920x742.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:742,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:124614,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe35ac8-cc14-4b24-b1b8-e3174f3b246c_920x742.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!see0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe35ac8-cc14-4b24-b1b8-e3174f3b246c_920x742.png 424w, https://substackcdn.com/image/fetch/$s_!see0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe35ac8-cc14-4b24-b1b8-e3174f3b246c_920x742.png 848w, https://substackcdn.com/image/fetch/$s_!see0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe35ac8-cc14-4b24-b1b8-e3174f3b246c_920x742.png 1272w, https://substackcdn.com/image/fetch/$s_!see0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe35ac8-cc14-4b24-b1b8-e3174f3b246c_920x742.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>f1</strong> and <strong>f2</strong> have different function item types even though they have identical function signatures. When you assign <strong>add_two</strong> to <strong>f1</strong> at the end of the example, you get a type mismatch error because of that.</p><p>This unique typing enables powerful compiler optimizations. Since the compiler knows exactly which function will be called at compile time, it can:</p><ul><li><p><strong>Inline the function call</strong> - Replace the call with the function's body directly</p></li><li><p><strong>Use static dispatch</strong> - No runtime lookup needed to find the function</p></li><li><p><strong>Apply aggressive optimizations</strong> - Dead code elimination, constant folding, etc.</p></li></ul><p>For example, <strong>f1(x)</strong> gets replaced by <strong>x + 1</strong> directly, eliminating the function call overhead entirely.</p><h3>Function Pointer</h3><p>So how do we store different functions in the same variable? We convert them to <strong>function pointers</strong>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7AnI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ffc471-500f-4ea3-9d63-8de3534a9e3a_920x892.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7AnI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ffc471-500f-4ea3-9d63-8de3534a9e3a_920x892.png 424w, https://substackcdn.com/image/fetch/$s_!7AnI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ffc471-500f-4ea3-9d63-8de3534a9e3a_920x892.png 848w, https://substackcdn.com/image/fetch/$s_!7AnI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ffc471-500f-4ea3-9d63-8de3534a9e3a_920x892.png 1272w, https://substackcdn.com/image/fetch/$s_!7AnI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ffc471-500f-4ea3-9d63-8de3534a9e3a_920x892.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7AnI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ffc471-500f-4ea3-9d63-8de3534a9e3a_920x892.png" width="920" height="892" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/60ffc471-500f-4ea3-9d63-8de3534a9e3a_920x892.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:892,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:144354,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ffc471-500f-4ea3-9d63-8de3534a9e3a_920x892.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7AnI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ffc471-500f-4ea3-9d63-8de3534a9e3a_920x892.png 424w, https://substackcdn.com/image/fetch/$s_!7AnI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ffc471-500f-4ea3-9d63-8de3534a9e3a_920x892.png 848w, https://substackcdn.com/image/fetch/$s_!7AnI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ffc471-500f-4ea3-9d63-8de3534a9e3a_920x892.png 1272w, https://substackcdn.com/image/fetch/$s_!7AnI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ffc471-500f-4ea3-9d63-8de3534a9e3a_920x892.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Now, we explicitly tell the compiler that we want function pointers <strong>fn(i32) -&gt; i32</strong> for <strong>f1</strong> and <strong>f2</strong>. Rust coerces <strong>add_one</strong> and <strong>add_two</strong> (function items) to function pointers and assigns them to <strong>f1</strong> and <strong>f2</strong>. You can see at the end that I am able to assign both <strong>add_two</strong> and even <strong>f2</strong> to <strong>f1</strong> just fine, unlike the previous example.</p><p>The trade-off is that function pointer calls use dynamic dispatch (indirect calls through the pointer), which typically prevents inlining unlike direct calls from function items, but we gain flexibility.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Closure &amp; Trait</h2><p>Now let's understand closures and why they're different from functions.</p><h3>Closure</h3><p>A closure is an anonymous function that can <strong>capture variables</strong> from its surrounding environment:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4BFV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19e31f6-93ce-4fb2-a859-7111de8ccef3_920x444.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4BFV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19e31f6-93ce-4fb2-a859-7111de8ccef3_920x444.png 424w, https://substackcdn.com/image/fetch/$s_!4BFV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19e31f6-93ce-4fb2-a859-7111de8ccef3_920x444.png 848w, https://substackcdn.com/image/fetch/$s_!4BFV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19e31f6-93ce-4fb2-a859-7111de8ccef3_920x444.png 1272w, https://substackcdn.com/image/fetch/$s_!4BFV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19e31f6-93ce-4fb2-a859-7111de8ccef3_920x444.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4BFV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19e31f6-93ce-4fb2-a859-7111de8ccef3_920x444.png" width="920" height="444" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a19e31f6-93ce-4fb2-a859-7111de8ccef3_920x444.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:444,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:61135,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19e31f6-93ce-4fb2-a859-7111de8ccef3_920x444.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4BFV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19e31f6-93ce-4fb2-a859-7111de8ccef3_920x444.png 424w, https://substackcdn.com/image/fetch/$s_!4BFV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19e31f6-93ce-4fb2-a859-7111de8ccef3_920x444.png 848w, https://substackcdn.com/image/fetch/$s_!4BFV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19e31f6-93ce-4fb2-a859-7111de8ccef3_920x444.png 1272w, https://substackcdn.com/image/fetch/$s_!4BFV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19e31f6-93ce-4fb2-a859-7111de8ccef3_920x444.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The key difference: closures can access variables from their enclosing scope, while regular functions cannot.</p><h3>The Three Closure Traits</h3><p>Closures don't all capture variables in the same way. The <strong>manner of capture</strong> depends on what the closure does with those variables, and this directly determines which traits the closure implements.</p><p>The Rust compiler automatically assigns one of three traits to each closure based on how it uses captured variables:</p><p><strong>FnOnce - Moves Captured Variables</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cTYL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F869dfcf8-05b6-4964-9fa7-5ac383051246_920x482.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cTYL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F869dfcf8-05b6-4964-9fa7-5ac383051246_920x482.png 424w, https://substackcdn.com/image/fetch/$s_!cTYL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F869dfcf8-05b6-4964-9fa7-5ac383051246_920x482.png 848w, https://substackcdn.com/image/fetch/$s_!cTYL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F869dfcf8-05b6-4964-9fa7-5ac383051246_920x482.png 1272w, https://substackcdn.com/image/fetch/$s_!cTYL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F869dfcf8-05b6-4964-9fa7-5ac383051246_920x482.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cTYL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F869dfcf8-05b6-4964-9fa7-5ac383051246_920x482.png" width="920" height="482" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/869dfcf8-05b6-4964-9fa7-5ac383051246_920x482.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:482,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:69066,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F869dfcf8-05b6-4964-9fa7-5ac383051246_920x482.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cTYL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F869dfcf8-05b6-4964-9fa7-5ac383051246_920x482.png 424w, https://substackcdn.com/image/fetch/$s_!cTYL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F869dfcf8-05b6-4964-9fa7-5ac383051246_920x482.png 848w, https://substackcdn.com/image/fetch/$s_!cTYL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F869dfcf8-05b6-4964-9fa7-5ac383051246_920x482.png 1272w, https://substackcdn.com/image/fetch/$s_!cTYL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F869dfcf8-05b6-4964-9fa7-5ac383051246_920x482.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Once <strong>data</strong> is dropped, calling the closure again would attempt to drop the same memory twice, leading to undefined behavior. Rust prevents this by making such closures callable only once.</p><p><strong>FnMut - Mutates Captured Variables</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uFNp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44cf64fa-4d8e-4f8c-80e8-26644d4dedf8_920x520.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uFNp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44cf64fa-4d8e-4f8c-80e8-26644d4dedf8_920x520.png 424w, https://substackcdn.com/image/fetch/$s_!uFNp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44cf64fa-4d8e-4f8c-80e8-26644d4dedf8_920x520.png 848w, https://substackcdn.com/image/fetch/$s_!uFNp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44cf64fa-4d8e-4f8c-80e8-26644d4dedf8_920x520.png 1272w, https://substackcdn.com/image/fetch/$s_!uFNp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44cf64fa-4d8e-4f8c-80e8-26644d4dedf8_920x520.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uFNp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44cf64fa-4d8e-4f8c-80e8-26644d4dedf8_920x520.png" width="920" height="520" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/44cf64fa-4d8e-4f8c-80e8-26644d4dedf8_920x520.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:520,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:71105,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44cf64fa-4d8e-4f8c-80e8-26644d4dedf8_920x520.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uFNp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44cf64fa-4d8e-4f8c-80e8-26644d4dedf8_920x520.png 424w, https://substackcdn.com/image/fetch/$s_!uFNp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44cf64fa-4d8e-4f8c-80e8-26644d4dedf8_920x520.png 848w, https://substackcdn.com/image/fetch/$s_!uFNp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44cf64fa-4d8e-4f8c-80e8-26644d4dedf8_920x520.png 1272w, https://substackcdn.com/image/fetch/$s_!uFNp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44cf64fa-4d8e-4f8c-80e8-26644d4dedf8_920x520.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Fn - Only Reads Captured Variables</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1-Ge!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9730d1a-d709-44eb-b937-7db1eb98e139_920x520.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1-Ge!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9730d1a-d709-44eb-b937-7db1eb98e139_920x520.png 424w, https://substackcdn.com/image/fetch/$s_!1-Ge!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9730d1a-d709-44eb-b937-7db1eb98e139_920x520.png 848w, https://substackcdn.com/image/fetch/$s_!1-Ge!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9730d1a-d709-44eb-b937-7db1eb98e139_920x520.png 1272w, https://substackcdn.com/image/fetch/$s_!1-Ge!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9730d1a-d709-44eb-b937-7db1eb98e139_920x520.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1-Ge!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9730d1a-d709-44eb-b937-7db1eb98e139_920x520.png" width="920" height="520" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f9730d1a-d709-44eb-b937-7db1eb98e139_920x520.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:520,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83773,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9730d1a-d709-44eb-b937-7db1eb98e139_920x520.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1-Ge!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9730d1a-d709-44eb-b937-7db1eb98e139_920x520.png 424w, https://substackcdn.com/image/fetch/$s_!1-Ge!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9730d1a-d709-44eb-b937-7db1eb98e139_920x520.png 848w, https://substackcdn.com/image/fetch/$s_!1-Ge!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9730d1a-d709-44eb-b937-7db1eb98e139_920x520.png 1272w, https://substackcdn.com/image/fetch/$s_!1-Ge!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9730d1a-d709-44eb-b937-7db1eb98e139_920x520.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Note about the move keyword:</strong> Sometimes you'll see closures with the <strong>move</strong> keyword, which forces the closure to take ownership of captured variables. However, <strong>move</strong> doesn't always mean <strong>FnOnce</strong>. If the captured variables aren't dropped or consumed, the closure can still be called multiple times and won't be <strong>FnOnce</strong>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!A_si!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8158f08c-cf52-4f8a-8e09-b72b5ec1c144_920x556.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!A_si!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8158f08c-cf52-4f8a-8e09-b72b5ec1c144_920x556.png 424w, https://substackcdn.com/image/fetch/$s_!A_si!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8158f08c-cf52-4f8a-8e09-b72b5ec1c144_920x556.png 848w, https://substackcdn.com/image/fetch/$s_!A_si!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8158f08c-cf52-4f8a-8e09-b72b5ec1c144_920x556.png 1272w, https://substackcdn.com/image/fetch/$s_!A_si!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8158f08c-cf52-4f8a-8e09-b72b5ec1c144_920x556.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!A_si!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8158f08c-cf52-4f8a-8e09-b72b5ec1c144_920x556.png" width="920" height="556" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8158f08c-cf52-4f8a-8e09-b72b5ec1c144_920x556.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:556,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:90755,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8158f08c-cf52-4f8a-8e09-b72b5ec1c144_920x556.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!A_si!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8158f08c-cf52-4f8a-8e09-b72b5ec1c144_920x556.png 424w, https://substackcdn.com/image/fetch/$s_!A_si!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8158f08c-cf52-4f8a-8e09-b72b5ec1c144_920x556.png 848w, https://substackcdn.com/image/fetch/$s_!A_si!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8158f08c-cf52-4f8a-8e09-b72b5ec1c144_920x556.png 1272w, https://substackcdn.com/image/fetch/$s_!A_si!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8158f08c-cf52-4f8a-8e09-b72b5ec1c144_920x556.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Trait Hierarchy</h3><p>Let's look at a function that accepts an <strong>FnOnce</strong> closure:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R48T!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba87cf03-d453-4659-88d9-067d36000d9d_920x334.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R48T!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba87cf03-d453-4659-88d9-067d36000d9d_920x334.png 424w, https://substackcdn.com/image/fetch/$s_!R48T!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba87cf03-d453-4659-88d9-067d36000d9d_920x334.png 848w, https://substackcdn.com/image/fetch/$s_!R48T!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba87cf03-d453-4659-88d9-067d36000d9d_920x334.png 1272w, https://substackcdn.com/image/fetch/$s_!R48T!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba87cf03-d453-4659-88d9-067d36000d9d_920x334.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R48T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba87cf03-d453-4659-88d9-067d36000d9d_920x334.png" width="920" height="334" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba87cf03-d453-4659-88d9-067d36000d9d_920x334.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:334,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:47001,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba87cf03-d453-4659-88d9-067d36000d9d_920x334.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!R48T!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba87cf03-d453-4659-88d9-067d36000d9d_920x334.png 424w, https://substackcdn.com/image/fetch/$s_!R48T!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba87cf03-d453-4659-88d9-067d36000d9d_920x334.png 848w, https://substackcdn.com/image/fetch/$s_!R48T!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba87cf03-d453-4659-88d9-067d36000d9d_920x334.png 1272w, https://substackcdn.com/image/fetch/$s_!R48T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba87cf03-d453-4659-88d9-067d36000d9d_920x334.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This function promises to call the closure only once. That's the only restriction it places on the closure.</p><p>Now, if you have an <strong>Fn</strong> closure that can be called multiple times, can you pass it to <strong>execute_once</strong>? Absolutely! A closure that can be called multiple times can certainly be called just once. The same logic applies to <strong>FnMut</strong> closures - they can be called multiple times, so they can also be called once.</p><p>This creates a hierarchy: <strong>Fn</strong> can be used anywhere, <strong>FnMut</strong> works where <strong>FnMut</strong> or <strong>FnOnce</strong> is needed, and <strong>FnOnce</strong> only works where <strong>FnOnce</strong> is required.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!89eA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b843acf-a4eb-4014-a4f4-ee2cec2429c4_1370x1202.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!89eA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b843acf-a4eb-4014-a4f4-ee2cec2429c4_1370x1202.png 424w, https://substackcdn.com/image/fetch/$s_!89eA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b843acf-a4eb-4014-a4f4-ee2cec2429c4_1370x1202.png 848w, https://substackcdn.com/image/fetch/$s_!89eA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b843acf-a4eb-4014-a4f4-ee2cec2429c4_1370x1202.png 1272w, https://substackcdn.com/image/fetch/$s_!89eA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b843acf-a4eb-4014-a4f4-ee2cec2429c4_1370x1202.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!89eA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b843acf-a4eb-4014-a4f4-ee2cec2429c4_1370x1202.png" width="1370" height="1202" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0b843acf-a4eb-4014-a4f4-ee2cec2429c4_1370x1202.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1202,&quot;width&quot;:1370,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:132456,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b843acf-a4eb-4014-a4f4-ee2cec2429c4_1370x1202.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!89eA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b843acf-a4eb-4014-a4f4-ee2cec2429c4_1370x1202.png 424w, https://substackcdn.com/image/fetch/$s_!89eA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b843acf-a4eb-4014-a4f4-ee2cec2429c4_1370x1202.png 848w, https://substackcdn.com/image/fetch/$s_!89eA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b843acf-a4eb-4014-a4f4-ee2cec2429c4_1370x1202.png 1272w, https://substackcdn.com/image/fetch/$s_!89eA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b843acf-a4eb-4014-a4f4-ee2cec2429c4_1370x1202.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Alright, that's a lot of rules to remember about functions and closures. Remembering these rules is good, but we'll quickly forget them. That's why it's much better to understand what happens behind the scenes. Let's dive into how Rust actually implements closures.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/p/the-hidden-rules-behind-rust-functions?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/p/the-hidden-rules-behind-rust-functions?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.cuongle.dev/p/the-hidden-rules-behind-rust-functions?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><h2>Closure Behind the Scene</h2><h3>How Rust Desugars Closures</h3><p>When you write a closure, the Rust compiler internally transforms it into a <strong>compiler-generated anonymous struct</strong> with trait implementations:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QiLh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7767a16-e0d3-4e48-9907-38965f9615a8_920x444.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QiLh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7767a16-e0d3-4e48-9907-38965f9615a8_920x444.png 424w, https://substackcdn.com/image/fetch/$s_!QiLh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7767a16-e0d3-4e48-9907-38965f9615a8_920x444.png 848w, https://substackcdn.com/image/fetch/$s_!QiLh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7767a16-e0d3-4e48-9907-38965f9615a8_920x444.png 1272w, https://substackcdn.com/image/fetch/$s_!QiLh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7767a16-e0d3-4e48-9907-38965f9615a8_920x444.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QiLh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7767a16-e0d3-4e48-9907-38965f9615a8_920x444.png" width="920" height="444" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f7767a16-e0d3-4e48-9907-38965f9615a8_920x444.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:444,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:69332,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7767a16-e0d3-4e48-9907-38965f9615a8_920x444.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QiLh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7767a16-e0d3-4e48-9907-38965f9615a8_920x444.png 424w, https://substackcdn.com/image/fetch/$s_!QiLh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7767a16-e0d3-4e48-9907-38965f9615a8_920x444.png 848w, https://substackcdn.com/image/fetch/$s_!QiLh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7767a16-e0d3-4e48-9907-38965f9615a8_920x444.png 1272w, https://substackcdn.com/image/fetch/$s_!QiLh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7767a16-e0d3-4e48-9907-38965f9615a8_920x444.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The compiler conceptually transforms this closure into something like:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8QjL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9e89137-e386-4014-a9e6-ccb13d78c7d2_920x780.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8QjL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9e89137-e386-4014-a9e6-ccb13d78c7d2_920x780.png 424w, https://substackcdn.com/image/fetch/$s_!8QjL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9e89137-e386-4014-a9e6-ccb13d78c7d2_920x780.png 848w, https://substackcdn.com/image/fetch/$s_!8QjL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9e89137-e386-4014-a9e6-ccb13d78c7d2_920x780.png 1272w, https://substackcdn.com/image/fetch/$s_!8QjL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9e89137-e386-4014-a9e6-ccb13d78c7d2_920x780.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8QjL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9e89137-e386-4014-a9e6-ccb13d78c7d2_920x780.png" width="920" height="780" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b9e89137-e386-4014-a9e6-ccb13d78c7d2_920x780.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:780,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:116160,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9e89137-e386-4014-a9e6-ccb13d78c7d2_920x780.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8QjL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9e89137-e386-4014-a9e6-ccb13d78c7d2_920x780.png 424w, https://substackcdn.com/image/fetch/$s_!8QjL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9e89137-e386-4014-a9e6-ccb13d78c7d2_920x780.png 848w, https://substackcdn.com/image/fetch/$s_!8QjL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9e89137-e386-4014-a9e6-ccb13d78c7d2_920x780.png 1272w, https://substackcdn.com/image/fetch/$s_!8QjL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9e89137-e386-4014-a9e6-ccb13d78c7d2_920x780.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In this transformation, the original <strong>data</strong> variable is moved into the <strong>ClosureEnvironment</strong> struct. When the closure is called, it consumes itself (<strong>self</strong>) and drops the moved data. This is why the closure can only be called once. After the first call, both the closure struct and its captured data are consumed.</p><p>The same idea applies for <strong>Fn</strong> and <strong>FnMut</strong>. Rust transforms every closure into a compiler-generated struct with the appropriate trait implementation based on how it uses captured variables.</p><p>The compiler chooses the least intrusive capture mode it can. For each captured variable, it starts with the most permissive option (immutable borrow) and only escalates to more restrictive modes (mutable borrow, then move) when the closure's body requires it.</p><h3>Why the Trait Hierarchy Works</h3><p>Earlier we saw that you can pass an <strong>Fn</strong> closure where <strong>FnOnce</strong> is expected, but how is this possible when they're different traits? The answer lies in how the traits are defined.</p><p>The three closure traits form a hierarchy through trait inheritance:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2yBP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0ece501-14a7-4b1a-9583-643dc3461120_920x780.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2yBP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0ece501-14a7-4b1a-9583-643dc3461120_920x780.png 424w, https://substackcdn.com/image/fetch/$s_!2yBP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0ece501-14a7-4b1a-9583-643dc3461120_920x780.png 848w, https://substackcdn.com/image/fetch/$s_!2yBP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0ece501-14a7-4b1a-9583-643dc3461120_920x780.png 1272w, https://substackcdn.com/image/fetch/$s_!2yBP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0ece501-14a7-4b1a-9583-643dc3461120_920x780.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2yBP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0ece501-14a7-4b1a-9583-643dc3461120_920x780.png" width="920" height="780" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a0ece501-14a7-4b1a-9583-643dc3461120_920x780.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:780,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:127123,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0ece501-14a7-4b1a-9583-643dc3461120_920x780.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2yBP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0ece501-14a7-4b1a-9583-643dc3461120_920x780.png 424w, https://substackcdn.com/image/fetch/$s_!2yBP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0ece501-14a7-4b1a-9583-643dc3461120_920x780.png 848w, https://substackcdn.com/image/fetch/$s_!2yBP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0ece501-14a7-4b1a-9583-643dc3461120_920x780.png 1272w, https://substackcdn.com/image/fetch/$s_!2yBP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0ece501-14a7-4b1a-9583-643dc3461120_920x780.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Notice the <strong>: FnOnce&lt;Args&gt;</strong> and <strong>: FnMut&lt;Args&gt;</strong> syntax, this means:</p><ul><li><p>Every type that implements <strong>FnMut</strong> must also implement <strong>FnOnce</strong></p></li><li><p>Every type that implements <strong>Fn</strong> must also implement both <strong>FnMut</strong> and <strong>FnOnce</strong></p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Relation Between Function Pointer &amp; Closure Trait</h2><p>As we saw earlier in Example 1, sometimes we can pass closures to functions expecting function pointers, but sometimes we can't. Let's understand why.</p><h3>Non-Capturing Closures Become Function Pointers</h3><p>When a closure doesn't capture any variables, it doesn't need the hidden struct we saw earlier. Since there's no captured state to store, Rust can coerce such closures directly to plain function pointers:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NxfQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93339203-cbba-4bd2-949c-0b3439e37794_920x520.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NxfQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93339203-cbba-4bd2-949c-0b3439e37794_920x520.png 424w, https://substackcdn.com/image/fetch/$s_!NxfQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93339203-cbba-4bd2-949c-0b3439e37794_920x520.png 848w, https://substackcdn.com/image/fetch/$s_!NxfQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93339203-cbba-4bd2-949c-0b3439e37794_920x520.png 1272w, https://substackcdn.com/image/fetch/$s_!NxfQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93339203-cbba-4bd2-949c-0b3439e37794_920x520.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NxfQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93339203-cbba-4bd2-949c-0b3439e37794_920x520.png" width="920" height="520" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/93339203-cbba-4bd2-949c-0b3439e37794_920x520.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:520,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:73379,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93339203-cbba-4bd2-949c-0b3439e37794_920x520.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NxfQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93339203-cbba-4bd2-949c-0b3439e37794_920x520.png 424w, https://substackcdn.com/image/fetch/$s_!NxfQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93339203-cbba-4bd2-949c-0b3439e37794_920x520.png 848w, https://substackcdn.com/image/fetch/$s_!NxfQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93339203-cbba-4bd2-949c-0b3439e37794_920x520.png 1272w, https://substackcdn.com/image/fetch/$s_!NxfQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93339203-cbba-4bd2-949c-0b3439e37794_920x520.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>But as soon as the closure captures variables, this coercion is no longer possible:<code> </code></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!t0Ui!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89cf466a-8598-4073-b91f-a0b6bd340571_920x556.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!t0Ui!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89cf466a-8598-4073-b91f-a0b6bd340571_920x556.png 424w, https://substackcdn.com/image/fetch/$s_!t0Ui!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89cf466a-8598-4073-b91f-a0b6bd340571_920x556.png 848w, https://substackcdn.com/image/fetch/$s_!t0Ui!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89cf466a-8598-4073-b91f-a0b6bd340571_920x556.png 1272w, https://substackcdn.com/image/fetch/$s_!t0Ui!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89cf466a-8598-4073-b91f-a0b6bd340571_920x556.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!t0Ui!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89cf466a-8598-4073-b91f-a0b6bd340571_920x556.png" width="920" height="556" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/89cf466a-8598-4073-b91f-a0b6bd340571_920x556.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:556,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:79076,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89cf466a-8598-4073-b91f-a0b6bd340571_920x556.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!t0Ui!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89cf466a-8598-4073-b91f-a0b6bd340571_920x556.png 424w, https://substackcdn.com/image/fetch/$s_!t0Ui!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89cf466a-8598-4073-b91f-a0b6bd340571_920x556.png 848w, https://substackcdn.com/image/fetch/$s_!t0Ui!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89cf466a-8598-4073-b91f-a0b6bd340571_920x556.png 1272w, https://substackcdn.com/image/fetch/$s_!t0Ui!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89cf466a-8598-4073-b91f-a0b6bd340571_920x556.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Note:</strong> There are additional restrictions (like the closure being non-async), but we won't cover those here.</p><h3>Function Pointers Implement All Closure Traits</h3><p>Functions are essentially like non-capturing closures, they have no state and can be called repeatedly without side effects. Therefore, function pointers implement all three closure traits (<strong>Fn</strong>, <strong>FnMut</strong>, and <strong>FnOnce</strong>):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sjDw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08124da8-e626-4d21-9ecf-5636f794b4fd_920x854.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sjDw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08124da8-e626-4d21-9ecf-5636f794b4fd_920x854.png 424w, https://substackcdn.com/image/fetch/$s_!sjDw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08124da8-e626-4d21-9ecf-5636f794b4fd_920x854.png 848w, https://substackcdn.com/image/fetch/$s_!sjDw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08124da8-e626-4d21-9ecf-5636f794b4fd_920x854.png 1272w, https://substackcdn.com/image/fetch/$s_!sjDw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08124da8-e626-4d21-9ecf-5636f794b4fd_920x854.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sjDw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08124da8-e626-4d21-9ecf-5636f794b4fd_920x854.png" width="920" height="854" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/08124da8-e626-4d21-9ecf-5636f794b4fd_920x854.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:854,&quot;width&quot;:920,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:142587,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/173253918?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08124da8-e626-4d21-9ecf-5636f794b4fd_920x854.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sjDw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08124da8-e626-4d21-9ecf-5636f794b4fd_920x854.png 424w, https://substackcdn.com/image/fetch/$s_!sjDw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08124da8-e626-4d21-9ecf-5636f794b4fd_920x854.png 848w, https://substackcdn.com/image/fetch/$s_!sjDw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08124da8-e626-4d21-9ecf-5636f794b4fd_920x854.png 1272w, https://substackcdn.com/image/fetch/$s_!sjDw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08124da8-e626-4d21-9ecf-5636f794b4fd_920x854.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This bidirectional compatibility (non-capturing closures can become function pointers, and function pointers can be used as closures) creates a seamless integration between Rust's function and closure systems.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/p/the-hidden-rules-behind-rust-functions?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/p/the-hidden-rules-behind-rust-functions?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.cuongle.dev/p/the-hidden-rules-behind-rust-functions?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><h2>Key Takeaways</h2><p>Let's summarize what we've learned about Rust's function and closure system:</p><ol><li><p><strong>Function Items vs Function Pointers</strong>: Every function creates a unique, zero-sized, compiler-generated type that enables powerful optimizations through static dispatch. Function pointers use dynamic dispatch but allow storing different functions in the same variable.</p></li><li><p><strong>Closure Capture Modes</strong>: Closures are categorized by how they capture variables. <strong>FnOnce</strong> moves captured variables, <strong>FnMut</strong> mutates them, and <strong>Fn</strong> only reads them. The compiler chooses the least intrusive capture mode possible.</p></li><li><p><strong>Trait Hierarchy</strong>: The closure traits form a hierarchy through supertraits where <strong>Fn</strong> extends <strong>FnMut</strong>, which extends <strong>FnOnce</strong>. This means an <strong>Fn</strong> closure can be used anywhere <strong>FnMut</strong> or <strong>FnOnce</strong> is expected.</p></li><li><p><strong>Compiler-Generated Structs</strong>: Closures are transformed into anonymous structs that hold captured variables and implement the appropriate closure traits.</p></li><li><p><strong>Seamless Integration</strong>: Non-capturing closures can be coerced to function pointers, while function pointers implement all closure traits. This creates bidirectional compatibility between functions and closures.</p></li></ol><p>If you made it this far, you're probably as obsessed with understanding how things really work as I am. I'm Cuong, and I write about Rust and programming. If you share the same passion, I'd love to connect with you. Feel free to reach out on <a href="https://x.com/cuongleqq">X</a>, <a href="https://www.linkedin.com/in/cuong-le/">LinkedIn</a>, or subscribe to my blog (<a href="https://blog.cuongle.dev/">substack</a>, <a href="https://medium.com/@cuongleqq">medium</a>) to keep pushing the boundaries together!</p>]]></content:encoded></item><item><title><![CDATA[If you aren't amazed by Rust enum, you don't know its power]]></title><description><![CDATA[Every time I explain Rust's enums to someone new, I get the same reaction: "Wait&#8230; enums can do that?"]]></description><link>https://blog.cuongle.dev/p/rust-enum-is-amazing</link><guid isPermaLink="false">https://blog.cuongle.dev/p/rust-enum-is-amazing</guid><dc:creator><![CDATA[Cuong Le]]></dc:creator><pubDate>Wed, 27 Aug 2025 14:54:06 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/26343c61-8090-418f-b1fe-d8d861481dfa_689x520.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've used enums in C, Java, Go, and plenty of other languages, and they were fine. Just named constants. Useful, sure, but honestly a little boring.</p><p>Then I saw what Rust did with enums: each option can hold real data inside it, the compiler makes sure you don't forget to handle any case, and the type system blocks you from creating combinations that don't make sense. And the kicker? It all compiles down to something efficient, with zero extra indirection and often memory-optimal layouts.</p><p>That's when it clicked: this isn't just an enum. This is one of Rust's secret weapons.</p><p>In this post, I'll show you why Rust's enums deserve your respect, how you've been relying on them without even noticing, and what makes them so efficient once you see how they're laid out in memory. By the end, I hope you'll never look at Rust enums the same way again.</p><h2>What's different about enums in Rust?</h2><p>In most languages, enums are just names slapped on top of integers. They don't hold data, and the compiler won't stop you from forgetting to handle a case.</p><p>Rust takes a very different approach.</p><p><strong>The first big difference</strong>: Rust enums can carry data. A variant isn't just a label. It can bundle real, typed information right inside.</p><pre><code>enum Shape {
    Circle(f64),
    Square(f64),
    Rectangle(f64, f64),
}</code></pre><p>Here, Shape isn't just "Circle = 0, Square = 1." Each variant carries the exact data it needs: a radius for Circle, a side length for Square, and width + height for Rectangle. This way, you can't create an impossible state. Every variant has exactly the fields it should, nothing extra, nothing missing.</p><p>You can even give the data names if it makes your code clearer:</p><pre><code>enum Shape {
    Circle { radius: f64 },
    Square { side: f64 },
    Rectangle { width: f64, height: f64 },
}</code></pre><p>Now when you create a shape, it's obvious what each number represents: <code>Shape::Rectangle { width: 10.0, height: 5.0 }</code> instead of trying to remember whether <code>Rectangle(10.0, 5.0)</code> means width-then-height or height-then-width.</p><p><strong>The second big difference</strong>: Rust forces you to handle every case. With pattern matching, you don't just check which variant you got. The compiler makes sure you didn't forget any.</p><pre><code>fn area(shape: Shape) -&gt; f64 {
    match shape {
        Shape::Circle(r) =&gt; std::f64::consts::PI * r * r,
        Shape::Square(s) =&gt; s * s,
        Shape::Rectangle(w, h) =&gt; w * h,
    }
}</code></pre><p>If you leave out Rectangle, this won't even compile. That's a huge step up from enums in other languages, where forgetting a case often triggers runtime bugs you might never notice.</p><p>Historical note: Rust didn't invent this magic. These ideas (variants that carry data and pattern matching) originated in the ML family (think Standard ML and OCaml) back in the 1970s, which pioneered what we now call tagged unions. Rust borrowed that power, but tailored it for systems programming.</p><p>These two differences (data inside variants and compiler-enforced case coverage) already set Rust's enums apart. But the real magic isn't just in the syntax. It's in the kinds of problems enums can solve for you. That's where their true power shows up.</p><h2>Why <code>enum</code> in Rust is powerful</h2><p>Imagine you're designing a configuration for a file uploader. You want to support two modes: anonymous upload (no username needed) or authenticated upload (which requires a username and password). You might try this with a struct:</p><pre><code>pub struct UploadConfig {
    pub destination: String,
    pub anonymous: bool,
    // username and password should only be set if anonymous == false
    pub username: Option&lt;String&gt;,
    pub password: Option&lt;String&gt;,
}</code></pre><p>This compiles, but it's awkward. Nothing prevents someone from setting anonymous = true and also filling in a username and password. Now you've got nonsense states your code has to tiptoe around. You're left relying on comments or runtime checks.</p><p>Enums fix this cleanly:</p><pre><code>pub enum Auth {
    Anonymous,
    Credentials { username: String, password: String },
}

pub struct UploadConfig {
    pub destination: String,
    pub auth: Auth,
}</code></pre><p>Now the invalid combination simply can't exist. If you have Anonymous, there's no username or password field lurking around. If you need credentials, you're forced to provide both. The compiler ensures every UploadConfig is valid by construction.</p><p>And that's the deeper point: Rust enums let you make invalid states impossible to represent. Entire categories of bugs disappear before your code even compiles. You're not just writing programs &#8212; you're encoding correctness into the design itself.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Two most common enums you use every day: <code>Option</code> and <code>Result</code></h2><p>Even if you've never written your own enum, you've been using them constantly. <code>Option&lt;T&gt;</code> is Rust's way of saying a value may or may not exist, without resorting to null. Its variants are simple:</p><pre><code>enum Option&lt;T&gt; {
    Some(T),
    None,
}</code></pre><p>Because it's an enum, you can't ignore the <code>None</code> case. The compiler forces you to deal with it. That's why null pointer exceptions (the nightmare bug that haunts every other language) simply don't exist in Rust.</p><p>Similarly, <code>Result&lt;T, E&gt;</code> encodes success or failure as an enum:</p><pre><code>enum Result&lt;T, E&gt; {
    Ok(T),
    Err(E),
}</code></pre><p>This design turns error handling into an explicit part of your program's flow. You can't accidentally forget that something might fail. The type system reminds you at every call site.</p><p>These two enums alone account for a huge amount of Rust's safety and reliability, and they're built on the same principles you can use in your own code.</p><p>If you're building systems software, you probably care about memory usage. So let's ask the practical question: how much space do these powerful enums actually take?</p><h2>Dive deeper into Rust <code>enum</code> memory layout</h2><p>The answer might surprise you. Despite all their flexibility, Rust enums are remarkably compact. The compiler uses a clever layout strategy that minimizes waste while keeping access fast.</p><p>Here's how it works. For any enum, Rust needs to track two pieces of information in memory:</p><ol><li><p><strong>Which variant is currently active</strong> (the tag)</p></li><li><p><strong>The data for that variant</strong> (the payload)</p></li></ol><p>Rather than storing these separately, Rust packs them together as efficiently as possible. Let me show you exactly what this looks like.</p><p><em>Important Note: These memory layouts show how the current Rust compiler typically arranges enums, but this isn't guaranteed to stay the same. With the default </em><code>repr(Rust)</code><em> representation, the compiler is free to change layout across different versions to optimize performance. You can rely on </em><code>size_of::&lt;T&gt;()</code><em> and </em><code>align_of::&lt;T&gt;()</code><em> for your compiled program, but the specific field arrangement and internal layout may change. Use these examples to understand concepts, not for low-level memory manipulation.</em></p><p><strong>Example 1</strong>: Simple enum with no data</p><p>Start with the simplest case, an enum where variants carry no data:</p><pre><code>enum Simple {
    A,
    B,
}</code></pre><p>The memory layout is straightforward:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FdEv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d854f6-2f77-4aa8-b707-173e844e1b23_277x305.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FdEv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d854f6-2f77-4aa8-b707-173e844e1b23_277x305.png 424w, https://substackcdn.com/image/fetch/$s_!FdEv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d854f6-2f77-4aa8-b707-173e844e1b23_277x305.png 848w, https://substackcdn.com/image/fetch/$s_!FdEv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d854f6-2f77-4aa8-b707-173e844e1b23_277x305.png 1272w, https://substackcdn.com/image/fetch/$s_!FdEv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d854f6-2f77-4aa8-b707-173e844e1b23_277x305.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FdEv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d854f6-2f77-4aa8-b707-173e844e1b23_277x305.png" width="277" height="305" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43d854f6-2f77-4aa8-b707-173e844e1b23_277x305.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:305,&quot;width&quot;:277,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:11346,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/172090785?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d854f6-2f77-4aa8-b707-173e844e1b23_277x305.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FdEv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d854f6-2f77-4aa8-b707-173e844e1b23_277x305.png 424w, https://substackcdn.com/image/fetch/$s_!FdEv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d854f6-2f77-4aa8-b707-173e844e1b23_277x305.png 848w, https://substackcdn.com/image/fetch/$s_!FdEv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d854f6-2f77-4aa8-b707-173e844e1b23_277x305.png 1272w, https://substackcdn.com/image/fetch/$s_!FdEv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43d854f6-2f77-4aa8-b707-173e844e1b23_277x305.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Since there's no payload data to store, Rust only needs a single byte to remember which variant you chose. No wasted space at all.</p><p><strong>Example 2</strong>: Enum with data of different sizes</p><p>Now let's see what happens when variants carry data:</p><pre><code>enum SingleOrPair {
    One(u8),        // needs 1 byte for the u8
    Pair(u8, u8),   // needs 2 bytes for two u8s
}</code></pre><p>Here, Rust has to accommodate the largest possible variant (<code>Pair</code>), plus space for the tag:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IXMX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1afdfd-30bd-44f3-8bee-298248681272_527x326.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IXMX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1afdfd-30bd-44f3-8bee-298248681272_527x326.png 424w, https://substackcdn.com/image/fetch/$s_!IXMX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1afdfd-30bd-44f3-8bee-298248681272_527x326.png 848w, https://substackcdn.com/image/fetch/$s_!IXMX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1afdfd-30bd-44f3-8bee-298248681272_527x326.png 1272w, https://substackcdn.com/image/fetch/$s_!IXMX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1afdfd-30bd-44f3-8bee-298248681272_527x326.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IXMX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1afdfd-30bd-44f3-8bee-298248681272_527x326.png" width="527" height="326" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7b1afdfd-30bd-44f3-8bee-298248681272_527x326.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:326,&quot;width&quot;:527,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:21109,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/172090785?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1afdfd-30bd-44f3-8bee-298248681272_527x326.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IXMX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1afdfd-30bd-44f3-8bee-298248681272_527x326.png 424w, https://substackcdn.com/image/fetch/$s_!IXMX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1afdfd-30bd-44f3-8bee-298248681272_527x326.png 848w, https://substackcdn.com/image/fetch/$s_!IXMX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1afdfd-30bd-44f3-8bee-298248681272_527x326.png 1272w, https://substackcdn.com/image/fetch/$s_!IXMX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1afdfd-30bd-44f3-8bee-298248681272_527x326.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Since all components (<code>u8</code> tag and <code>u8</code> data fields) have 1-byte alignment, no padding is needed. The enum takes exactly 3 bytes: 1 for the tag plus 2 for the largest variant (<code>Pair</code>).</p><p>The key insight: Rust allocates enough space for the largest variant, then reuses that same space for smaller variants. When you store <code>One(42)</code>, it uses just 1 byte of the payload space. When you store <code>Pair(10, 20)</code>, it uses both payload bytes. The enum always takes exactly 3 bytes regardless of which variant is active.</p><p><strong>Example 3</strong>: Advanced optimization with niche-filling</p><p>Now for the really clever part. Sometimes Rust can eliminate the tag entirely through a technique called <strong>niche-filling</strong>. The compiler frequently applies this optimization when it detects unused bit patterns (though this behavior isn't guaranteed and may vary between compiler versions).</p><pre><code>enum ByteOrText {
    Byte(u8),
    Text(String),
}</code></pre><p>A <code>String</code> in Rust contains three <code>usize</code> fields: a pointer to the data, the length, and the capacity. On a 64-bit system, that's 3 &#215; 8 = 24 bytes.</p><p>Normally you'd expect this enum to be 25 bytes (24 for String + 1 for tag). But here's what actually happens:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Bn8Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d47a2c-e251-48b9-a9a8-d079e7927035_689x498.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Bn8Q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d47a2c-e251-48b9-a9a8-d079e7927035_689x498.png 424w, https://substackcdn.com/image/fetch/$s_!Bn8Q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d47a2c-e251-48b9-a9a8-d079e7927035_689x498.png 848w, https://substackcdn.com/image/fetch/$s_!Bn8Q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d47a2c-e251-48b9-a9a8-d079e7927035_689x498.png 1272w, https://substackcdn.com/image/fetch/$s_!Bn8Q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d47a2c-e251-48b9-a9a8-d079e7927035_689x498.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Bn8Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d47a2c-e251-48b9-a9a8-d079e7927035_689x498.png" width="689" height="498" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02d47a2c-e251-48b9-a9a8-d079e7927035_689x498.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:498,&quot;width&quot;:689,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:55046,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/172090785?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49732811-cac6-4b19-93bb-bf0e2280ef97_689x520.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Bn8Q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d47a2c-e251-48b9-a9a8-d079e7927035_689x498.png 424w, https://substackcdn.com/image/fetch/$s_!Bn8Q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d47a2c-e251-48b9-a9a8-d079e7927035_689x498.png 848w, https://substackcdn.com/image/fetch/$s_!Bn8Q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d47a2c-e251-48b9-a9a8-d079e7927035_689x498.png 1272w, https://substackcdn.com/image/fetch/$s_!Bn8Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d47a2c-e251-48b9-a9a8-d079e7927035_689x498.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The magic: in a valid <code>String</code>, the pointer is <strong>never null</strong>. It always points to allocated memory. Rust exploits this by using the null pointer value as a signal meaning "this is actually the Byte variant, not the Text variant."</p><p>So when you have:</p><ul><li><p><code>Text("hello")</code>: pointer is non-null, so this is the String variant</p></li><li><p><code>Byte(42)</code>: pointer is null, so this is the Byte variant, and the actual <code>42</code> value is stored in the length field</p></li></ul><p>The tag disappeared entirely. Rust encoded the "which variant" information inside the existing data, using a bit pattern that would otherwise be invalid. The enum takes no more memory than a plain <code>String</code> would.</p><p>This optimization happens automatically whenever Rust finds "impossible" bit patterns it can repurpose. You get the benefits without changing your code.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Here's proof straight from the compiler.</p><pre><code>use std::mem::size_of;

enum Simple {
    A,
    B,
}

enum SingleOrPair {
    One(u8),
    Pair(u8, u8),
}

enum ByteOrText {
    Byte(u8),
    Text(String),
}

fn main() {
    println!("Size of Simple: {} bytes", size_of::&lt;Simple&gt;());
    println!("Size of SingleOrPair: {} bytes", size_of::&lt;SingleOrPair&gt;());
    println!("Size of ByteOrText: {} bytes", size_of::&lt;ByteOrText&gt;());
}</code></pre><p>These memory optimizations aren't just compiler tricks - they're what make Rust's powerful enum features practical for systems programming. When you can encode rich type information with minimal overhead, you get safety without sacrificing performance.</p><h2>Key takeaway</h2><ul><li><p>Rust enums go far beyond the enums you may know from other languages. They carry data, enforce exhaustive handling, and make invalid states impossible. At the same time, their memory layout is compact and efficient, thanks to compiler tricks like niche-filling.</p></li><li><p>You already rely on enums every day through <code>Option</code> and <code>Result</code>. But the real magic happens when you use them in your own types: modeling states, encoding invariants, and letting the compiler protect you from whole categories of bugs.</p></li></ul><p>If you made it this far, you're probably as obsessed with understanding how things really work as I am. I'm Cuong, and I write about Rust and programming. If you share the same passion, I'd love to connect with you&#8212;feel free to reach out on <a href="https://x.com/cuongleqq">X</a>, <a href="https://www.linkedin.com/in/cuong-le/">LinkedIn</a> , or subscribe to my blog (<a href="https://blog.cuongle.dev/">substack</a>, <a href="https://medium.com/@cuongleqq">medium</a>) to keep pushing the boundaries together!</p>]]></content:encoded></item><item><title><![CDATA[Constructor Best Practices in Rust]]></title><description><![CDATA[Constructor patterns every serious Rustacean should master to stop looking like a beginner.]]></description><link>https://blog.cuongle.dev/p/constructor-best-practices-in-rust</link><guid isPermaLink="false">https://blog.cuongle.dev/p/constructor-best-practices-in-rust</guid><dc:creator><![CDATA[Cuong Le]]></dc:creator><pubDate>Mon, 18 Aug 2025 14:16:43 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ecf02362-d65b-4de4-8f49-4d238bb23a4c_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I used to think <strong>new</strong> is <em>the</em> constructor in Rust. I was so wrong. it's just a conventional way to create a new struct instance. Then I came across <strong>with_capacity</strong>, <strong>Default</strong>, <strong>TryFrom</strong> and <strong>builder pattern</strong> (you will see it shortly). The list kept growing, and I started wondering: how many ways <em>are</em> there to construct a value in Rust? And more importantly, which patterns should my type implement, and why?</p><p>These aren't easy questions if you haven't been in the Rust ecosystem long enough. In fact, each constructor pattern solves specific problems, and once you understand the underlying design principles, they become just another tool in your toolbox. You stop asking "which patterns should I use?" and start asking "what problems am I solving?"</p><pre><code>// When designing your own types, which patterns should you support?
struct MyConfig { /* ... */ }

impl MyConfig {
    pub fn new() -&gt; Self { /* ... */ }       // Associated functions
    pub fn from_file(path: &amp;str) -&gt; Result&lt;Self, Error&gt; { /* ... */ }
}

impl Default for MyConfig { /* ... */ }      // Trait implementations

impl From&lt;&amp;str&gt; for MyConfig { /* ... */ }   // Conversion traits

// Or chained construction?
let config = MyConfigBuilder::new()
    .timeout(30)
    .retries(3)
    .build()?;</code></pre><p>In this post, we'll decode Rust's constructor approaches: associated functions, trait-based construction, and builder pattern. We'll explore the decision frameworks that guide when to use each.</p><p>But first, let's understand why this variety exists in the first place.</p><h2>Why do all these patterns exist?</h2><p>Unlike C++ or Java, Rust refuses to have a special constructor syntax and just uses regular functions instead. Rust dodged a bullet here. Traditional constructors are a mess, and Rust designers knew it. Let's look at a few:</p><ul><li><p>Traditional constructors let you initialize fields flexibly. You can do all sorts of magic with them, or you can forget to initialize some fields entirely. Then your program crashes at 2 AM on a Sunday, and you spend four hours hunting down a null pointer that could have been caught at compile time. Rust prevents this by requiring you to <strong>explicitly specify every field</strong>, catching mistakes at compile time. Predictability over convenience!</p></li><li><p>Traditional constructors can only express their intent through parameter lists. Try reading <strong>Server("localhost", 8080, 30)</strong> six months later. Is that 30 a timeout? A retry count? A connection limit? You'll waste 10 minutes just figuring out what your own code does. In contrast, Rust's explicit names like <strong>Server::with_timeout("localhost", 8080, 30)</strong> and <strong>Server::with_ssl("localhost", 8080)</strong> have much higher readability.</p></li><li><p>Traditional constructors hide whether they can fail. Will <strong>FileReader("/tmp/data.txt")</strong> throw an exception? You can't tell from the call site, making error handling unpredictable. Rust constructors are just functions that can return whatever type expresses their behavior: <strong>Result&lt;Self, Error&gt;</strong> for fallible construction, <strong>Option&lt;Self&gt;</strong> for operations that might not produce a value.</p></li></ul><p>Rust's language provides some solutions (associated functions and traits), while the community developed others (like builders). Together, they address three fundamental construction challenges:</p><ul><li><p><strong>Simple custom initialization</strong> &#8594; Associated functions</p></li><li><p><strong>Ecosystem compatibility</strong> (so your types work with <strong>Option::unwrap_or_default()</strong>, generic functions, etc.) &#8594; Trait implementations  </p></li><li><p><strong>Complex configuration with many options</strong> &#8594; Builder patterns</p></li></ul><p>So where do you start? What's the foundation that every Rust type should have?</p><p>Associated functions.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Associated Functions: The Rust Way to "Constructor"</h2><p>Associated functions are like class-level functions in other languages&#8212;they belong to the type but don't operate on a particular instance. (Regular methods take <strong>self</strong> to operate on a specific instance, while associated functions work at the type level.) They're Rust's primary way to create new instances, and you've probably used them without thinking about it:</p><pre><code>let vec = Vec::new();
let vec_with_space = Vec::with_capacity(100);
let string = String::new();
let file = File::open("config.txt");</code></pre><p>Unlike traditional constructors, each associated function has a descriptive name that tells you exactly what kind of construction is happening. <strong>Vec::new()</strong> creates an empty vector, while <strong>Vec::with_capacity(100)</strong> pre-allocates space for 100 elements.</p><h3>When to use associated functions</h3><p>Use associated functions when you have different ways to initialize the same type:</p><pre><code>impl Vec&lt;T&gt; {
    pub fn new() -&gt; Self { /* ... */ }
    pub fn with_capacity(capacity: usize) -&gt; Self { /* ... */ }
    pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -&gt; Self { /* ... */ }
}</code></pre><p>Each function name immediately communicates the construction strategy. The <strong>::new()</strong> function is universally expected in Rust and these functions are usually tiny and often inlined in optimized builds, so overhead is negligible. Half the time, <strong>new()</strong> is just syntactic sugar for <strong>Default::default()</strong>. Technically useless. But skip it and developers will assume your API is broken. The convention is that strong.</p><p>Since associated functions are regular functions, they can return any type that expresses their behavior: <strong>Result&lt;Self, Error&gt;</strong> for operations that might fail, this is called 'fallible construction,' <strong>Option&lt;Self&gt;</strong> for operations that might not produce a value, or in special cases you might return <strong>Arc&lt;Self&gt;</strong> to enforce shared ownership (reference-counted smart pointer).</p><h3>Common naming conventions</h3><p>The Rust ecosystem has developed consistent naming patterns:</p><ul><li><p><strong>new()</strong> - Basic constructor with sensible defaults that everyone expects</p></li><li><p><strong>with_*(...)</strong> - Constructor with specific configuration (<strong>Vec::with_capacity</strong>, <strong>ProgressBar::with_draw_target</strong>, <strong>Router::with_state</strong>)</p></li><li><p><strong>from_*(...)</strong> - Constructor from different data sources with validation/decoding (<strong>String::from_utf8</strong>, <strong>u32::from_be_bytes</strong>). This differs from the <strong>From</strong> trait, which is for simple, infallible conversions.</p></li><li><p><strong>Action verbs</strong> - For fallible operations (<strong>connect</strong>, <strong>open</strong>, <strong>load</strong>)</p></li></ul><p>These aren't enforced by the compiler, but following them makes your API predictable to other Rust developers.</p><h2>Trait-Based Construction: Standard Interfaces</h2><p>Once you have basic constructors working, the next step is making your types feel native to Rust&#8212;that's where standardized trait-based construction shines.</p><p>While associated functions give you custom constructors, traits provide standardized ways to create values that work across the entire ecosystem. When you implement these traits, your types automatically work with standard library functions and other code.</p><h3>Default: The zero-argument constructor</h3><p><strong>Default</strong> is Rust's closest equivalent to a parameterless constructor. You can derive it automatically for simple cases:</p><pre><code>#[derive(Default)]
struct Config {
    host: String,        // defaults to ""
    port: u16,          // defaults to 0
    enabled: bool,      // defaults to false
}</code></pre><p>Or implement it manually when you need custom default values:</p><pre><code>impl Default for Config {
    fn default() -&gt; Self {
        Self {
            host: "localhost".to_string(),
            port: 8080,
            enabled: true,
        }
    }
}</code></pre><p><strong>Default</strong> shines when working with functions that need to create instances of your type, and with collections. It enables your types to work seamlessly with APIs like <strong>Option::unwrap_or_default()</strong> (falls back to default value), <strong>mem::take(&amp;mut value)</strong> (replaces value with default), <strong>HashMap::entry().or_default()</strong> (inserts default if key missing), and any generic function that needs to create instances of your type.</p><h3>From, Into, TryFrom, and TryInto: Type conversions</h3><p><strong>From</strong> and <strong>Into</strong> handle infallible conversions between types (conversions that always succeed). When conversions might fail, use <strong>TryFrom</strong> and <strong>TryInto</strong> instead.</p><pre><code>use std::net::{IpAddr, Ipv4Addr};
use std::convert::TryFrom;

// From the standard library: infallible conversion
impl From&lt;Ipv4Addr&gt; for IpAddr {
    fn from(ipv4: Ipv4Addr) -&gt; IpAddr {
        IpAddr::V4(ipv4)
    }
}

// Usage works both ways automatically
let ipv4 = Ipv4Addr::new(127, 0, 0, 1);
let ip1 = IpAddr::from(ipv4);
let ip2: IpAddr = ipv4.into();  // Into is automatically available

// TryFrom example: fallible conversion between integer types
let big_number: i64 = 300;
let small_number: Result&lt;u8, _&gt; = u8::try_from(big_number); // Might fail if &gt; 255
let converted: u8 = small_number?; // Use with ? operator</code></pre><p>This pattern allows your types to integrate seamlessly with error handling using the <strong>?</strong> operator and <strong>Result</strong> chains.</p><h3>When to use trait-based construction</h3><p>Use traits when:</p><ul><li><p>Your type has an obvious "default" or "empty" state (<strong>Default</strong>)</p></li><li><p>You're converting from standard types like <strong>&amp;str</strong>, <strong>u32</strong>, or <strong>Vec&lt;T&gt;</strong> (<strong>From</strong>/<strong>Into</strong> for infallible conversions, <strong>TryFrom</strong>/<strong>TryInto</strong> for fallible ones)</p></li><li><p>You want your type to work seamlessly with generic code</p></li></ul><p>Traits make your types feel native to Rust's ecosystem rather than foreign additions.</p><p>While associated functions and traits handle most constructor needs, sometimes you encounter types with many optional parameters or complex configuration requirements. So what do you do when you have 15 optional parameters? When your constructor call looks like <strong>Config::new(None, Some(30), false, None, Some("localhost"), true, None)</strong>?</p><p>For these scenarios, Rust developers turn to the builder pattern.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Builder Pattern: Taming Complex Construction</h2><p>The builder pattern provides a fluent, readable interface for complex construction. Builders come with a cost. They're not free complexity&#8212;use them when the pain of not having them exceeds the pain of maintaining them. The complexity comes from additional types (the builder struct), and may introduce additional memory allocations depending on what data you store or convert during building, and more complex error handling (validation can happen at build time rather than construction time).</p><h3>Basic builder pattern</h3><p>Here's how reqwest (a popular HTTP client) implements its builder:</p><pre><code>// From the reqwest crate
impl ClientBuilder {
    pub fn new() -&gt; ClientBuilder { /* ... */ }
    pub fn timeout(mut self, timeout: Duration) -&gt; ClientBuilder { /* ... */ }
    pub fn redirect(mut self, policy: redirect::Policy) -&gt; ClientBuilder { /* ... */ }
    pub fn user_agent&lt;V&gt;(mut self, value: V) -&gt; ClientBuilder { /* ... */ }
    pub fn build(self) -&gt; Result&lt;Client, Error&gt; { /* ... */ }
}

// Usage becomes extremely readable:
let client = ClientBuilder::new()
    .timeout(Duration::from_secs(30))
    .redirect(redirect::Policy::limited(5))
    .user_agent("MyApp/1.0")
    .build()?;</code></pre><p>Notice how we use a separate builder struct (<strong>ClientBuilder</strong>) to collect configuration parameters through method chaining, then call <strong>build()</strong> to construct the final target struct (<strong>Client</strong>). This separation allows for flexible parameter setting while maintaining type safety. The <strong>build()</strong> method returns a <strong>Result</strong> to handle any validation errors or construction failures that might occur during the final assembly.</p><h3>Derive macros and automation</h3><p>For simple builders, use the <strong>derive_builder</strong> crate:</p><pre><code>use derive_builder::Builder;

#[derive(Builder)]
struct ServerConfig {
    host: String,
    #[builder(default = "8080")]
    port: u16,
    #[builder(default)]
    ssl_enabled: bool,
}

// Automatically generates ServerConfigBuilder with all methods
let config = ServerConfigBuilder::default()
    .host("localhost".to_string())
    .port(3000)
    .ssl_enabled(true)
    .build()?;</code></pre><p>Note that we use the <strong>#[derive(Builder)]</strong> macro to automatically generate the builder struct and methods, and <strong>#[builder(...)]</strong> attributes to configure default values.</p><p>Use derive macros for straightforward builders, hand-written builders when you need custom logic or validation.</p><h3>When to use builders</h3><p>Use the builder pattern when:</p><ul><li><p>You have many optional parameters (typically 4+ for simple types, or fewer if parameters are complex or need validation)</p></li><li><p>The parameter combinations create cognitive overhead when reading constructor calls</p></li><li><p>Parameter combinations need validation</p></li><li><p>The construction process has multiple steps (like connecting to a database, then authenticating, then configuring)</p></li><li><p>You need a fluent, self-documenting API for complex configuration (method names make intent clear: <strong>.timeout(30)</strong> vs a positional parameter)</p></li></ul><p>Builders excel at making complex APIs approachable and self-documenting.</p><h2>Bringing It All Together</h2><p>Now that we've explored the three main constructor patterns in Rust, you might wonder: do I have to choose just one? The answer is no. In practice, well-designed types often combine multiple patterns to serve different use cases.</p><h3>Combining Patterns</h3><p>Most well-designed types implement multiple constructor patterns:</p><pre><code>impl MyConfig {
    pub fn new() -&gt; Self { Self::default() }  // Convenience wrapper
    pub fn from_file(path: &amp;str) -&gt; Result&lt;Self, Error&gt; { /* ... */ }
    pub fn builder() -&gt; MyConfigBuilder { /* ... */ }
}

impl Default for MyConfig { /* ... */ }</code></pre><p>This gives users flexibility: <strong>Default</strong> for generic code, <strong>new()</strong> for common cases, <strong>from_file()</strong> for specific sources, and <strong>builder()</strong> for complex configuration. Each pattern serves its purpose, and together they create a comprehensive API that feels natural to Rust developers.</p><h2>Key Takeaways</h2><p>We've covered a lot of ground&#8212;from simple associated functions to complex builders. Here are the essential insights to guide your constructor design decisions:</p><ul><li><p>Choose the right pattern for your needs: Use associated functions for different initialization strategies, trait implementations when you want ecosystem integration, and builders for complex types with many optional parameters.</p></li><li><p>Follow established naming conventions (<strong>new()</strong>, <strong>with_*()</strong>, <strong>from_*()</strong>) and make error handling explicit through return types like <strong>Result</strong>.</p></li><li><p>Start simple with basic associated functions (<strong>new()</strong>) and trait implementations (<strong>Default</strong>), then evolve to builders as your API's complexity grows.</p></li></ul><p>If you made it this far, you're probably as obsessed with understanding how things really work as I am. I'm Cuong, and I write about Rust and programming. If you share the same passion, I'd love to connect with you&#8212;feel free to reach out on <a href="https://x.com/cuongleqq">X</a>, <a href="https://www.linkedin.com/in/cuong-le/">LinkedIn</a> , or subscribe to my blog (<a href="https://blog.cuongle.dev/">substack</a>, <a href="https://medium.com/@cuongleqq">medium</a>) to keep pushing the boundaries together!</p>]]></content:encoded></item><item><title><![CDATA[This Send/Sync Secret Separates Professional From Amateur Rust Developers]]></title><description><![CDATA[2 Months of Banging My Head Against Send/Sync, Explained in One Coffee Break]]></description><link>https://blog.cuongle.dev/p/this-sendsync-secret-separates-professional-and-amateur</link><guid isPermaLink="false">https://blog.cuongle.dev/p/this-sendsync-secret-separates-professional-and-amateur</guid><dc:creator><![CDATA[Cuong Le]]></dc:creator><pubDate>Wed, 06 Aug 2025 16:24:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Dl4A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb478c34b-913b-4f06-af11-6efb9152b5e4_810x582.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When I started learning Rust, everyone warned me about how hard ownership and borrowing would be. But honestly? Once I got my hands dirty, those concepts clicked much faster than expected.</p><p>That was, until I hit the traits <strong>Send</strong> and <strong>Sync</strong>&#8212;still ownership and borrowing but in the multithreaded context. I'd spend hours reading documentation, only to feel more lost than when I started. At one point, I genuinely thought about switching back to Go just to avoid the headache.</p><p>The official Rustonomicon definition only made things worse:</p><ul><li><p>A type is <strong>Send</strong> if it's safe to send it to another thread.</p></li><li><p>A type is <strong>Sync</strong> if it's safe to share between threads.</p></li></ul><p>This definition failed me badly because it told me what but never why. I could follow examples mechanically, but I couldn't reason about new types. Sure, I could memorize that <strong>Rc</strong> isn't <strong>Send</strong> and <strong>Arc</strong> usually is&#8212;but I had no idea why. I felt like I was just collecting random facts instead of actually understanding anything.</p><p>This motivates me to dig deeper and find the underlying principles that I will present to you today in this post.</p><p>Here's what finally clicked for me: these traits aren't arbitrary&#8212;they're Rust's way of encoding specific thread safety concerns into the type system. All those hours of confusion suddenly made sense when I stopped trying to memorize and started understanding the underlying danger. To grasp <strong>Send</strong> and <strong>Sync</strong>, we need to understand what makes threading dangerous in the first place.</p><h2>Send and Sync Are About Thread Safety</h2><p>The core danger in multithreaded programming is <strong>data races</strong>. A data race happens when multiple threads access the same memory at the same time, with at least one thread changing the data, and nothing to coordinate that access.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F5y2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f7fcf5c-fb2e-461d-adc8-2db305802510_922x287.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F5y2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f7fcf5c-fb2e-461d-adc8-2db305802510_922x287.png 424w, https://substackcdn.com/image/fetch/$s_!F5y2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f7fcf5c-fb2e-461d-adc8-2db305802510_922x287.png 848w, https://substackcdn.com/image/fetch/$s_!F5y2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f7fcf5c-fb2e-461d-adc8-2db305802510_922x287.png 1272w, https://substackcdn.com/image/fetch/$s_!F5y2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f7fcf5c-fb2e-461d-adc8-2db305802510_922x287.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F5y2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f7fcf5c-fb2e-461d-adc8-2db305802510_922x287.png" width="922" height="287" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3f7fcf5c-fb2e-461d-adc8-2db305802510_922x287.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:287,&quot;width&quot;:922,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:37248,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/170278146?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f7fcf5c-fb2e-461d-adc8-2db305802510_922x287.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!F5y2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f7fcf5c-fb2e-461d-adc8-2db305802510_922x287.png 424w, https://substackcdn.com/image/fetch/$s_!F5y2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f7fcf5c-fb2e-461d-adc8-2db305802510_922x287.png 848w, https://substackcdn.com/image/fetch/$s_!F5y2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f7fcf5c-fb2e-461d-adc8-2db305802510_922x287.png 1272w, https://substackcdn.com/image/fetch/$s_!F5y2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f7fcf5c-fb2e-461d-adc8-2db305802510_922x287.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Picture a website hit counter at 1000 visits when two users arrive simultaneously. Both requests read "1000", both compute "1001", both write "1001". Expected result after two visitors: 1002. Actual result: 1001.</p><p>Rust's <strong>Send</strong> and <strong>Sync</strong> traits are designed to prevent data races by encoding thread safety rules directly into the type system:</p><ul><li><p> <strong>Send</strong>: You can move this value to another thread without causing data races. (Think: <em>unique ownership</em> + thread safety)</p></li><li><p> <strong>Sync</strong>: Multiple threads can hold references to this value without causing data races. (Think: <em>shared access</em> + thread safety)</p></li></ul><p>The key insight is that <strong>Send</strong> is about <strong>unique ownership</strong> across threads, while <strong>Sync</strong> is about <strong>shared access</strong> across threads. When you move a value (<strong>Send</strong>), you're transferring complete control to another thread. When you share references (<strong>Sync</strong>), multiple threads have access but need coordination to avoid conflicts.</p><p>Let's see how this plays out with concrete examples.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>A Type That's Both Send and Sync</h2><p>Consider <strong>String</strong>&#8212;it's both <strong>Send</strong> and <strong>Sync</strong>. Here's why this makes sense:</p><p><strong>Send example:</strong></p><pre><code>// Send: Safe to move to another thread
let s = String::from("hello");
thread::spawn(move || {
    println!("{}", s); // s is now owned by this thread
});
// s is no longer accessible in the original thread</code></pre><p><em>Why this is safe</em>: Moving gives the new thread <strong>unique ownership</strong> of the string's data. Since only one thread can access it at a time, there's no possibility of a data race. The original thread can't touch the string anymore, it's been completely transferred.</p><p><strong>Sync example:</strong></p><pre><code>// Sync: Safe to share references across threads
let s = String::from("hello");
let s_ref = &amp;s;

thread::scope(|scope| {
    scope.spawn(|| {
        println!("{}", s_ref); // Reading via shared reference
    });
    scope.spawn(|| {
        println!("{}", s_ref); // Multiple threads can read simultaneously
    });
});</code></pre><p><em>Why this is safe</em>: Multiple threads have <strong>shared access</strong> to the string, but they can only read it. Since nobody can modify the data (you'd need <strong>&amp;mut s</strong> for that), the shared access is thread-safe. Multiple readers don't conflict with each other.</p><p><strong>From this String example, we can extract a general pattern</strong>. Most types are both <strong>Send</strong> and <strong>Sync</strong> because:</p><ol><li><p><strong>Send</strong>: Moving creates unique ownership in the new thread. Since only one thread can access the data at any time, there's no possibility of conflicts.</p></li><li><p><strong>Sync</strong>: Shared references only allow reading. Multiple threads reading the same data simultaneously doesn't cause problems.</p></li></ol><p>This simple model works perfectly for basic types like <strong>i32</strong>, <strong>String</strong>, <strong>Vec&lt;T&gt;</strong>, and most structs you'll create. The thread safety comes from Rust's ownership rules: either one thread owns the data (Send), or multiple threads can read but none can write (Sync).</p><p>I really wish Rust's type system were this simple. But of course, Rust wouldn't let us off that easy. <strong>Interior mutability</strong> breaks all our nice assumptions about "move = unique ownership" and "shared = read-only." Let's dive in.</p><h2>What Makes a Type !Sync</h2><p>Here's where our simple "shared references = read-only" rule breaks down. Some types in Rust allow <strong>interior mutability</strong>&#8212;they let you change data even when you only have a shared reference. If you'd like a deeper explanation of interior mutability and why Rust needs it, let me know in the comments&#8212;I'll write a dedicated post about it. For now, just understand that it breaks the usual "shared reference = read-only" rule.</p><p>To understand why this is problematic, let's look at <strong>Cell&lt;u64&gt;</strong>:</p><pre><code>use std::cell::Cell;

let cell = Cell::new(42);
let cell_ref = &amp;cell; // Just a shared reference, no &amp;mut
cell_ref.set(100);    // But we can still modify the value inside!
println!("{}", cell_ref.get());</code></pre><p>Notice what's happening here: we have a shared reference (<strong>&amp;cell</strong>), not a mutable one (<strong>&amp;mut cell</strong>), but we can still change the data inside through <strong>set()</strong>. This breaks Rust's usual rule that shared references are read-only.</p><p><strong>Cell&lt;T&gt;</strong> exists because sometimes you need to modify simple values (like counters or flags) even when you only have shared access to the containing structure. It's particularly useful when you need to track simple state like hit counters, flags, or retry attempts within otherwise immutable structures. <strong>Cell</strong> allows you to replace the entire value atomically without complex borrowing.</p><p>Now here's the threading problem: <strong>Cell&lt;u64&gt;</strong> lets you change data through a shared reference, but it has no protection against multiple threads doing this at the same time. If two threads both tried to call <strong>set()</strong>, you'd get a data race:</p><pre><code>// This WILL NOT compile
let cell = Cell::new(0);
thread::scope(|scope| {
    // error[E0277]: `Cell&lt;i32&gt;` cannot be shared between threads safely
    scope.spawn(|| cell.set(1)); // Thread 1 writing
    scope.spawn(|| cell.set(2)); // Thread 2 writing simultaneously
});</code></pre><p>That's why <strong>Cell&lt;T&gt;</strong> is <strong>!Sync</strong>, it can't be safely shared between threads. The interior mutability breaks our "shared references are safe" assumption.</p><p>But interior mutability doesn't automatically make a type <strong>!Sync</strong>. If the type can prevent data races, it can still be <strong>Sync</strong>. Some types solve this problem by adding their own synchronization. That's the case with <strong>AtomicU64</strong> and <strong>Mutex&lt;T&gt;</strong>:</p><pre><code>use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Mutex;

// AtomicU64: Uses hardware-level atomic operations
let atomic = AtomicU64::new(0);
thread::scope(|scope| {
    scope.spawn(|| atomic.store(1, Ordering::Relaxed)); // Safe
    scope.spawn(|| atomic.store(2, Ordering::Relaxed)); // Safe
});

// Mutex: Uses locking to serialize access
let mutex = Mutex::new(0);
thread::scope(|scope| {
    scope.spawn(|| *mutex.lock().unwrap() = 1); // Safe
    scope.spawn(|| *mutex.lock().unwrap() = 2); // Safe
});</code></pre><p>Both types allow interior mutability <em>with</em> protection against data races, so they stay <strong>Sync</strong>. The key difference is that <strong>AtomicU64</strong> uses hardware-level atomic operations that happen in a single step, while <strong>Mutex&lt;T&gt;</strong> makes threads take turns&#8212;only one thread can hold the lock at a time, so changes happen one after another instead of simultaneously.</p><p><strong>The refined model for Sync:</strong></p><ul><li><p>If shared references can't change the data &#8594; <strong>Sync</strong></p></li><li><p>If shared references can change the data without synchronization &#8594; <strong>!Sync</strong></p></li><li><p>If shared references can change the data <em>with</em> synchronization (atomics, locks) &#8594; <strong>Sync</strong></p></li></ul><p>Now, time for <strong>!Send</strong>&#8212;let's go.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>What Makes a Type !Send</h2><p>You might think that <strong>Send</strong> would be simpler than <strong>Sync</strong>. After all, when you move a value to another thread, you're giving that thread complete ownership&#8212;what could go wrong?</p><p>The problem is that some types maintain <strong>hidden shared state</strong> even after being moved. The move operation transfers the obvious data, but there might be invisible connections to the original thread that create thread safety issues.</p><p>The classic example is <strong>Rc&lt;T&gt;</strong> (reference-counted pointer):</p><pre><code>use std::rc::Rc;

let rc1 = Rc::new(42);
let rc2 = rc1.clone(); // Both point to the same data

// If we could send rc1 to another thread (we can't!)...
thread::spawn(move || {
    drop(rc1); // Decrements reference count
});

// ...while rc2 exists on the original thread
drop(rc2); // Also decrements the same reference count</code></pre><p>Here's what's happening: <strong>Rc&lt;T&gt;</strong> works by keeping a reference counter&#8212;when you clone an <strong>Rc</strong>, it increases the counter, and when you drop an <strong>Rc</strong>, it decreases the counter. When the counter reaches zero, the data gets cleaned up.</p><p>The critical insight: even after moving <strong>rc1</strong> to another thread, you don't have <strong>unique ownership</strong> of the reference counter&#8212;it's still <strong>shared</strong> with <strong>rc2</strong> on the original thread. Since <strong>Rc&lt;T&gt;</strong> uses a non-atomic reference counter, if two threads change that counter at the same time, you get a data race.</p><p>That's why <strong>Rc&lt;T&gt;</strong> is <strong>!Send</strong>, moving it doesn't actually create unique ownership of all the relevant data. There's hidden shared state (the reference counter) that remains unsafe.</p><p>So how do we fix this? How can we have reference counting that works across threads?</p><p>The solution is <strong>Arc&lt;T&gt;</strong> (atomic reference-counted pointer), which makes the shared reference counter thread-safe:</p><pre><code>use std::sync::Arc;

let arc1 = Arc::new(42);
let arc2 = arc1.clone();

// This works because Arc makes the shared state thread-safe
thread::spawn(move || {
    drop(arc1); // Atomically decrements counter
});

drop(arc2); // Also atomically decrements counter</code></pre><p><strong>Arc</strong> solves the problem by making the reference counter atomic, multiple threads can safely increment and decrement it simultaneously without data races.</p><p><em>Note: <strong>Arc&lt;T&gt;</strong> is only <strong>Send</strong> + <strong>Sync</strong> if <strong>T</strong> is also <strong>Send</strong> + <strong>Sync</strong>. For example, <strong>Arc&lt;Cell&lt;T&gt;&gt;</strong> is not <strong>Sync</strong> because <strong>Cell&lt;T&gt;</strong> isn't <strong>Sync</strong>. Arc makes the counter thread-safe, but the data it contains still depends on the inner type's thread safety properties. I won't dive too deep into this in this post&#8212;let me know in the comments if you'd like a dedicated post about it.</em></p><p><em>Note: There's another category of <strong>!Send</strong> types with thread-local constraints (like <strong>MutexGuard&lt;T&gt;</strong>), but <strong>Rc&lt;T&gt;</strong>-style shared state is the most common case you'll encounter.</em></p><p><strong>The refined model for Send:</strong></p><p>- If moving creates true unique ownership (no hidden shared state) &#8594; <strong>Send</strong></p><p>- If moving still leaves shared state that isn't thread-safe &#8594; <strong>!Send</strong></p><p>- If moving leaves shared state that <em>is</em> thread-safe &#8594; <strong>Send</strong></p><p>Now that we understand the underlying principles, let's turn these insights into a practical decision-making tool.</p><h2>Practical Decision Tree: Is Type X Send/Sync?</h2><p>Instead of memorizing every type's Send/Sync status, you can reason through it systematically. Here's the mental framework I use, built from the principles we just explored:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Dl4A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb478c34b-913b-4f06-af11-6efb9152b5e4_810x582.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Dl4A!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb478c34b-913b-4f06-af11-6efb9152b5e4_810x582.png 424w, https://substackcdn.com/image/fetch/$s_!Dl4A!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb478c34b-913b-4f06-af11-6efb9152b5e4_810x582.png 848w, https://substackcdn.com/image/fetch/$s_!Dl4A!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb478c34b-913b-4f06-af11-6efb9152b5e4_810x582.png 1272w, https://substackcdn.com/image/fetch/$s_!Dl4A!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb478c34b-913b-4f06-af11-6efb9152b5e4_810x582.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Dl4A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb478c34b-913b-4f06-af11-6efb9152b5e4_810x582.png" width="810" height="582" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b478c34b-913b-4f06-af11-6efb9152b5e4_810x582.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:582,&quot;width&quot;:810,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:73517,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/170278146?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb478c34b-913b-4f06-af11-6efb9152b5e4_810x582.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Dl4A!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb478c34b-913b-4f06-af11-6efb9152b5e4_810x582.png 424w, https://substackcdn.com/image/fetch/$s_!Dl4A!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb478c34b-913b-4f06-af11-6efb9152b5e4_810x582.png 848w, https://substackcdn.com/image/fetch/$s_!Dl4A!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb478c34b-913b-4f06-af11-6efb9152b5e4_810x582.png 1272w, https://substackcdn.com/image/fetch/$s_!Dl4A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb478c34b-913b-4f06-af11-6efb9152b5e4_810x582.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Pro tip</strong>: You can always double-check by trying to use the type across threads. The compiler will tell you if it's not <strong>Send</strong>/<strong>Sync</strong> with a clear error message!</p><h2>Key Takeaway</h2><p>Here's the mental model that makes <strong>Send</strong> and <strong>Sync</strong> predictable:</p><p><strong>They're Rust's way of encoding thread safety into the type system.</strong></p><ul><li><p><strong>Send</strong> asks: "Can I move this to another thread without creating hidden shared state that isn't thread-safe?"</p></li><li><p><strong>Sync</strong> asks: "Can multiple threads hold references to this without racing on mutations?"</p></li></ul><p>When you think about it this way, the traits become logical rather than arbitrary. <strong>Rc&lt;T&gt;</strong> isn't <strong>Send</strong> because moving it still leaves shared (non-atomic) state with the original thread. <strong>Cell&lt;T&gt;</strong> isn't <strong>Sync</strong> because it allows unsynchronized mutation through shared references.</p><p>Once you internalize this mental model, you'll find yourself correctly predicting a type's <strong>Send</strong>/<strong>Sync</strong> status just by understanding what the type does. And when you design your own types, you'll naturally think about thread safety from the ground up.</p><h2>What I didn't cover</h2><p>This post focused on the most common <strong>Send</strong>/<strong>Sync</strong> patterns. There are edge cases like <strong>MutexGuard&lt;T&gt;</strong> (which is <strong>!Send</strong> due to thread-local constraints, not shared state) and raw pointers, but the mental model here handles 95% of real-world cases.</p><p>If you made it this far, you're probably as obsessed with understanding how things really work as I am. I'm Cuong, and I write about Rust and programming. If you share the same passion, I'd love to connect with you&#8212;feel free to reach out on <a href="https://x.com/cuongleqq">X</a>, <a href="https://www.linkedin.com/in/cuong-le/">LinkedIn</a> , or subscribe to my blog (<a href="https://blog.cuongle.dev/">substack</a>, <a href="https://medium.com/@cuongleqq">medium</a>) to keep pushing the boundaries together!</p>]]></content:encoded></item><item><title><![CDATA[Unlock 100% Coverage - Mock Your Rust Unit Tests the Right Way]]></title><description><![CDATA[The essential mocking pattern every Rustacean should keep in their toolbox.]]></description><link>https://blog.cuongle.dev/p/unlock-100-coveragemock-your-rust</link><guid isPermaLink="false">https://blog.cuongle.dev/p/unlock-100-coveragemock-your-rust</guid><dc:creator><![CDATA[Cuong Le]]></dc:creator><pubDate>Sat, 26 Jul 2025 03:49:20 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/fd669175-c0a8-4d07-ae43-bd985d115a84_672x283.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Writing unit tests for pure, in-memory logic is easy. You feed it data, check the result, and you&#8217;re done. The trouble starts when your code has to reach outside itself: a database, an HTTP API, the Bitcoin network, or any third-party crate. Those dependencies can be slow or a pain to set up, so tests fail for the wrong reasons or need a mess of setup scripts. If you&#8217;re like me, this is when I skip the tests, and my coverage stays stuck under 70%.</p><p>The classic fix? Mock those dependencies.</p><p>In this post, you&#8217;ll learn how to mock external calls in Rust, and how to do it effectively.</p><p>First, let&#8217;s see why this problem shows up with a concrete example.</p><h2>The Need for Mocking</h2><p>Suppose you&#8217;re building an e-commerce backend: before restocking an item, you need to pay your supplier in Bitcoin.</p><p>Let's say the BitcoinWallet type comes from an external crate you can't edit:</p><pre><code>pub struct BitcoinWallet;
impl BitcoinWallet {
    pub fn send(&amp;mut self, to: &amp;str, amount: f64) -&gt; Result&lt;Txid&gt; {
        /* broadcasts a transaction */
    }
}</code></pre><p>(Notice the <strong>send</strong> function that reaches out to the network)</p><p>Your business logic call the <strong>send</strong> function from the BitcoinWallet like this:</p><pre><code>pub fn fill_inventory(wallet: &amp;mut BitcoinWallet, item_id: u64, qty: u32) -&gt; anyhow::Result&lt;()&gt; {
    let cost_btc = calculate_cost(item_id, qty); // calculate_cost is defined elsewhere
    wallet.send(SUPPLIER_ADDR, cost_btc)?; // interacts with network
    Ok(())
}</code></pre><p>And here&#8217;s a test:</p><pre><code>#[test]
fn test_fill_inventory() {
    let mut wallet = BitcoinWallet::new();
    let result = fill_inventory(&amp;mut wallet, 1000, 5);
    assert!(result.is_ok());
}</code></pre><p>But here&#8217;s the catch:</p><p>If you run this test, it might take forever, waiting for network confirmations, or it might fail because your test wallet is empty, or the testnet node is down, even though your logic is solid.</p><p>What you want is to <strong>simulate</strong> this call so your tests stay fast and reliable.</p><p>In this post, our mission is to test the <strong>fill_inventory</strong> function <em>without</em> a real Bitcoin wallet.</p><h2>Mocking in Rust</h2><p>Why can&#8217;t we just swap the wallet for a dummy object, like in some other languages?</p><ul><li><p>Rust doesn&#8217;t let you swap out objects at runtime (no reflection).</p></li><li><p>Types and lifetimes are fixed at compile time.</p></li></ul><p><strong>The solution:</strong> Introduce a trait&#8202;, &#8202;so you can inject either the real wallet or a mock as needed.</p><h4>The Indirection Layer</h4><p>Here&#8217;s the trick:</p><p>Instead of talking directly to the external wallet, your code will use a trait. Then you implement that trait for both the real wallet (for production) and your mock (for testing).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BC3R!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18954327-1fa2-4aa5-b2e8-a75ab3ad9ac6_672x283.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BC3R!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18954327-1fa2-4aa5-b2e8-a75ab3ad9ac6_672x283.png 424w, https://substackcdn.com/image/fetch/$s_!BC3R!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18954327-1fa2-4aa5-b2e8-a75ab3ad9ac6_672x283.png 848w, https://substackcdn.com/image/fetch/$s_!BC3R!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18954327-1fa2-4aa5-b2e8-a75ab3ad9ac6_672x283.png 1272w, https://substackcdn.com/image/fetch/$s_!BC3R!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18954327-1fa2-4aa5-b2e8-a75ab3ad9ac6_672x283.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BC3R!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18954327-1fa2-4aa5-b2e8-a75ab3ad9ac6_672x283.png" width="672" height="283" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/18954327-1fa2-4aa5-b2e8-a75ab3ad9ac6_672x283.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:283,&quot;width&quot;:672,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BC3R!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18954327-1fa2-4aa5-b2e8-a75ab3ad9ac6_672x283.png 424w, https://substackcdn.com/image/fetch/$s_!BC3R!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18954327-1fa2-4aa5-b2e8-a75ab3ad9ac6_672x283.png 848w, https://substackcdn.com/image/fetch/$s_!BC3R!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18954327-1fa2-4aa5-b2e8-a75ab3ad9ac6_672x283.png 1272w, https://substackcdn.com/image/fetch/$s_!BC3R!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18954327-1fa2-4aa5-b2e8-a75ab3ad9ac6_672x283.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>Is there other approach?</h4><p>You might see other patterns in the wild:</p><ul><li><p>Passing closures or function pointers (okay for very simple cases).</p></li><li><p>Compiling in different modules for tests with feature flags or `cfg(test)`.</p></li><li><p>HTTP record/replay tools (good for web APIs, but not for Bitcoin).</p></li></ul><p>In real-world Rust, traits are the most flexible and reliable way to swap dependencies for testing.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>How Do We Mock BitcoinWallet? (Step by Step)</h2><p><em>For this demo, the code for BitcoinWallet is simplified.</em></p><h4>Define the Trait and Use It for our code</h4><pre><code>pub trait BtcWallet {
    fn send(&amp;mut self, address: &amp;str, amount_btc: f64) -&gt; Result&lt;Txid&gt;;
}</code></pre><p>Note that we use the exact signature as the send function from the real BitcoinWallet type.</p><p>Next update your business logic to use the trait:</p><pre><code>pub const SUPPLIER_ADDR: &amp;str = "bc1q-supplier-addr";

pub fn fill_inventory&lt;W: BtcWallet&gt;(
    wallet: &amp;mut W,
    item_id: u64,
    qty: u32,
) -&gt; anyhow::Result&lt;()&gt; {
    let cost_btc = calculate_cost(item_id, qty);
    wallet.send(SUPPLIER_ADDR, cost_btc)?;
    update_inventory_db(item_id, qty)?;
    Ok(())
}</code></pre><p>Now, let&#8217;s extend our original BitcoinWallet so it implements our trait.</p><h4>Implement the Trait for the Real Wallet</h4><pre><code>use external_crate::BitcoinWallet as RealBitcoinWallet;
use anyhow::Context;

impl BtcWallet for RealBitcoinWallet {
    fn send(&amp;mut self, address: &amp;str, amount_btc: f64) -&gt; Result&lt;Txid&gt; {
        RealBitcoinWallet::send(self, address, amount_btc)
    }
}</code></pre><p>Look at this line: <strong>RealBitcoinWallet::send(self, address, amount_btc)</strong>, we specifically call <strong>send</strong> function defined on the <strong>RealBitcoinWallet</strong> type.</p><p>Now everything works just like before, let&#8217;s create our mock wallet for testing.</p><h4>Our Mock Object for Testing</h4><pre><code>#[derive(Default)]
pub struct MockBitcoinWallet {
    pub called: bool,
    pub last_addr: String,
    pub last_amt: f64,
}

impl BtcWallet for MockBitcoinWallet {
    fn send(&amp;mut self, address: &amp;str, amount_btc: f64) -&gt; Result&lt;Txid&gt; {
        self.called = true;
        self.last_addr = address.to_owned();
        self.last_amt = amount_btc;
        Ok("mock-tx-hash".into())
    }
}</code></pre><p>Because we use <strong>&amp;mut self</strong>, we can track calls using simple struct fields (bool, String, f64). If we don't have a <strong>&amp;mut self</strong>, a simple trick is to use iterior mutability types, such as: AtomicBool and Mutex.</p><h4>And finally, our test can run with the mock:</h4><pre><code>#[test]
fn test_fill_inventory_calls_send() {
    let mut wallet = MockBitcoinWallet::default();
    fill_inventory(&amp;mut wallet, 42, 3).unwrap();

    let expected = calculate_cost(42, 3);
    assert!(wallet.called);
    assert_eq!(wallet.last_addr, SUPPLIER_ADDR);
    assert!((wallet.last_amt - expected).abs() &lt; 1e-8);
}</code></pre><p><strong>Pro-tip:</strong> You can check not only <em>that</em> a method was called, with what arguments, but you can also return different outputs to verify if your code handles cases correctly, e.g: return an error if amount is negative.</p><p>If writing these mocks by hand feels tedious, there&#8217;s a better way.</p><h2>Using <strong>Mockall</strong> for Less Boilerplate</h2><p>As your codebase grows, you might want to avoid writing mocks by hand. Try <a href="https://docs.rs/mockall/">mockall</a>.</p><p>First, add this to your <em>Cargo.toml</em>:</p><pre><code>[dev-dependencies]
mockall = "0.13.1"</code></pre><p>Here&#8217;s how you use it:</p><pre><code>#[cfg_attr(test, mockall::automock)]
pub trait BtcWallet {
    fn send(&amp;mut self, address: &amp;str, amount_btc: f64) -&gt; Result&lt;Txid&gt;;
}

#[test]
fn test_fill_inventory() {
    let mut mock = MockBtcWallet::new();
    let expected = calculate_cost(42, 3);
    mock.expect_send()
        .withf(|addr, amt| addr == SUPPLIER_ADDR &amp;&amp; (*amt - expected).abs() &lt; 1e-8)
        .times(1);

    fill_inventory(&amp;mut mock, 42, 3).unwrap();
}</code></pre><p><strong>How does this work?</strong></p><p>Notice the line <strong>#[cfg_attr(test, mockall::automock)]</strong>. This tells Rust: <em>&#8220;When running in the test environment, use the mockall::automock macro to generate a mock implementation for this trait.&#8221;</em> The macro creates a new mock type&#8202;, &#8202;MockBtcWallet&#8202;, &#8202;that implements the BtcWallet trait for you. With just this one line, you get a fully functional mock (with all the trait methods) ready for your tests.</p><p><strong>automock</strong> is just a useful macro that mockall support to quickly create a mock type. There are plenty of useful things it exposes. Please checkout the documentation <a href="https://docs.rs/mockall/0.13.1/mockall/">here</a> if you need more powerful features.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>When Should You Mock?</h2><p>You might be wondering: Should I mock everything? The answer: <em>mock the pain, not the world.</em></p><ul><li><p>Use mocks for unit tests, especially when external calls would slow down or break your tests.</p></li><li><p>For end-to-end QA before release, use regtest/testnet or the real wallet to catch integration bugs.</p></li><li><p>For pure calculation functions, there&#8217;s no need to mock, &#8202;just test them directly.</p></li><li><p>If you need to check the real wallet RPC protocol, always test against the actual service at least once.</p></li></ul><p><strong>Pro-tip:</strong> If your tests are slow or flaky because of network calls, use mocks. But always keep at least one integration test that hits the real thing, just in case.</p><h2>Summary</h2><ul><li><p>Mocks let you test code that talks to the outside world&#8202;, &#8202;quickly and safely.</p></li><li><p>In Rust, a trait layer lets you swap between the real wallet and a test mock.</p></li><li><p>Hand-written mock is only for your understanding; use <strong>mockall</strong> to save time.</p></li><li><p>Always keep a few real integration tests to catch surprises.</p></li></ul><p>If you enjoyed this post or found it helpful, I'm Cuong, and I regularly write about Rust and other interesting programming topics. I'd love to connect with you, feel free to reach out on <a href="https://x.com/cuongleqq">X</a>, <a href="https://www.linkedin.com/in/cuong-le/">LinkedIn</a>, or subscribe to my blog for more insights!</p>]]></content:encoded></item><item><title><![CDATA[String vs str in Rust: The Only Guide You'll Ever Need]]></title><description><![CDATA[Never Be Confused by String and str Again]]></description><link>https://blog.cuongle.dev/p/string-vs-str-in-rust-the-only-guide</link><guid isPermaLink="false">https://blog.cuongle.dev/p/string-vs-str-in-rust-the-only-guide</guid><dc:creator><![CDATA[Cuong Le]]></dc:creator><pubDate>Sat, 19 Jul 2025 08:23:08 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!QPsf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F676a6838-7ede-48ed-8944-e74ec7503f15_655x445.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Rust strings confused the hell out of me.</h2><p>When I first started learning Rust, I kept seeing code that used <strong>String</strong>, <strong>str</strong>, <strong>&amp;String</strong>, and <strong>&amp;str</strong>, sometimes all in the same function. Sometimes I could pass a <strong>&amp;String</strong> to a function that wanted a <strong>&amp;str</strong>, and other times I had to use <strong>.to_string()</strong> just to get things to compile. Honestly, it felt pretty messy.</p><p>Let me show you what I mean:</p><pre><code>fn print_message(msg: &amp;str) {
    println!("{}", msg);
}

fn main() {
    let s1 = String::from("hello");
    let s2 = "world";

    print_message(&amp;s1); // works!
    print_message(s2);  // also works!
    // print_message(s1); // error: expected `&amp;str`, found `String`
    print_message(&amp;s1[0..3]); // works! (a slice of s1)
}</code></pre><p>Why does Rust let you pass some things, but not others? Why do we need so many string types? If you've ever been confused by this, you're not alone.</p><p>In this post, I'll explain why Rust strings work this way (and why it actually makes sense). Then we'll dive deeper to see what's really going on inside, right down to how these types are stored in memory.</p><h2>1. What Do We Actually Need from Strings?</h2><p>Let's step back and think about what we typically need strings to do:</p><ul><li><p><strong>Create and modify strings</strong>: Imagine building a dynamic welcome message. You have the text "Welcome," and you want to add different usernames depending on who logs in.</p></li><li><p><strong>Efficiently borrow existing strings</strong>: Suppose you want to read a user's name directly from a configuration file or from a JSON response without making extra copies.</p></li><li><p><strong>Use fixed text efficiently</strong>: Consider situations like logging simple messages such as "Operation completed successfully," which remain unchanged during the program's life.</p></li></ul><p>A good string type in any programming language should handle these tasks efficiently. But using just one type usually forces compromises in performance, simplicity, or safety.</p><p>Rust addresses these needs clearly by providing two separate types. But how exactly?</p><h2>2. What Exactly Are String and str?</h2><h4>String: Owned, Flexible, Heap-Allocated Text</h4><p>A String owns its data, meaning it stores text on the heap and can grow or shrink as needed.</p><pre><code>let mut message = String::new();
message.push_str("hello");
message.push('!'); // message is now "hello!"</code></pre><h4>str: Borrowed, Read-Only Views of Text</h4><p><strong>str</strong> is known as a "string slice", an immutable view into UTF-8 text. You can't directly create or store a bare str because Rust needs to know the size of variables at compile time. That's why it's always used as <strong>&amp;str</strong>, a borrowed reference.</p><pre><code>let full_message = String::from("hello world");
let first_word: &amp;str = &amp;full_message[0..5]; // "hello"</code></pre><p>A <strong>&amp;str</strong> can reference text from anywhere: the heap (like a <strong>String</strong>), stack memory, or static memory embedded in your program.</p><p>To help you understand the differences between them better and when to use each one, let's peek inside, what do they look like in memory?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>3. Diving Deeper: Memory Layout</h2><p>Here's how these types appear internally:</p><h4>Memory Layout of String:</h4><pre><code>let mut s1 = String::with_capacity(6);
s1.push_str("hello");</code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QPsf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F676a6838-7ede-48ed-8944-e74ec7503f15_655x445.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QPsf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F676a6838-7ede-48ed-8944-e74ec7503f15_655x445.png 424w, https://substackcdn.com/image/fetch/$s_!QPsf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F676a6838-7ede-48ed-8944-e74ec7503f15_655x445.png 848w, https://substackcdn.com/image/fetch/$s_!QPsf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F676a6838-7ede-48ed-8944-e74ec7503f15_655x445.png 1272w, https://substackcdn.com/image/fetch/$s_!QPsf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F676a6838-7ede-48ed-8944-e74ec7503f15_655x445.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QPsf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F676a6838-7ede-48ed-8944-e74ec7503f15_655x445.png" width="655" height="445" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/676a6838-7ede-48ed-8944-e74ec7503f15_655x445.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:445,&quot;width&quot;:655,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:24633,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/168300096?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F676a6838-7ede-48ed-8944-e74ec7503f15_655x445.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QPsf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F676a6838-7ede-48ed-8944-e74ec7503f15_655x445.png 424w, https://substackcdn.com/image/fetch/$s_!QPsf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F676a6838-7ede-48ed-8944-e74ec7503f15_655x445.png 848w, https://substackcdn.com/image/fetch/$s_!QPsf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F676a6838-7ede-48ed-8944-e74ec7503f15_655x445.png 1272w, https://substackcdn.com/image/fetch/$s_!QPsf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F676a6838-7ede-48ed-8944-e74ec7503f15_655x445.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>Memory Layout of &amp;str:</h4><pre><code>let mut s1 = String::with_capacity(6);
s1.push_str("hello");
let s2 = &amp;s1[..4];
let s3 = "world";</code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hf82!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76923e6-09f9-4c6b-91df-87f88f2c7125_804x633.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hf82!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76923e6-09f9-4c6b-91df-87f88f2c7125_804x633.png 424w, https://substackcdn.com/image/fetch/$s_!hf82!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76923e6-09f9-4c6b-91df-87f88f2c7125_804x633.png 848w, https://substackcdn.com/image/fetch/$s_!hf82!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76923e6-09f9-4c6b-91df-87f88f2c7125_804x633.png 1272w, https://substackcdn.com/image/fetch/$s_!hf82!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76923e6-09f9-4c6b-91df-87f88f2c7125_804x633.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hf82!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76923e6-09f9-4c6b-91df-87f88f2c7125_804x633.png" width="804" height="633" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e76923e6-09f9-4c6b-91df-87f88f2c7125_804x633.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:633,&quot;width&quot;:804,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:44356,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cuongle.dev/i/168300096?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76923e6-09f9-4c6b-91df-87f88f2c7125_804x633.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hf82!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76923e6-09f9-4c6b-91df-87f88f2c7125_804x633.png 424w, https://substackcdn.com/image/fetch/$s_!hf82!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76923e6-09f9-4c6b-91df-87f88f2c7125_804x633.png 848w, https://substackcdn.com/image/fetch/$s_!hf82!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76923e6-09f9-4c6b-91df-87f88f2c7125_804x633.png 1272w, https://substackcdn.com/image/fetch/$s_!hf82!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76923e6-09f9-4c6b-91df-87f88f2c7125_804x633.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Because of this straightforward layout, Rust efficiently uses <strong>&amp;str</strong> without extra copying or allocations.</p><p>But why exactly can you pass a <strong>&amp;String</strong> to a function expecting a <strong>&amp;str</strong>? Let's explore this next.</p><h2>4. Why Can We Pass &amp;String to Functions Expecting &amp;str?</h2><p>You can pass a <strong>&amp;String</strong> to any function expecting a <strong>&amp;str</strong> because <strong>String</strong> implements the <strong>Deref</strong> trait, targeting <strong>str</strong>. When Rust sees that you're using a <strong>&amp;String</strong> in a place where a <strong>&amp;str</strong> is required, it automatically and transparently calls <strong>deref</strong> to perform the conversion. Importantly, this is a zero-cost operation, no copying, no allocation, and no additional CPU instructions.</p><h4>How is Deref implemented for String?</h4><p>Here's the actual simplified Rust implementation:</p><pre><code>impl Deref for String {
    type Target = str;

    fn deref(&amp;self) -&gt; &amp;Self::Target {
        // SAFETY: String guarantees valid UTF-8 internally.
        unsafe { std::str::from_utf8_unchecked(&amp;self.as_bytes()) }
    }
}</code></pre><p>What this does is simply reinterpret the bytes inside a <strong>String</strong> as a <strong>&amp;str</strong>. The underlying data doesn't move, change, or get copied.</p><h4>Why is this truly zero-cost?</h4><ul><li><p><strong>String</strong> already stores a pointer to its data and its length. When you convert to <strong>&amp;str</strong>, Rust simply reuses this pointer and length directly.</p></li><li><p>No runtime overhead: Rust's compiler (and LLVM behind it) optimizes away this "conversion" entirely. The memory layout remains identical, so there's literally zero additional cost.</p></li></ul><p>You can verify this yourself by printing memory addresses:</p><pre><code>fn main() {
    let s = String::from("hello");
    let slice: &amp;str = &amp;s;

    println!("String data address: {:p}", s.as_ptr());
    println!("&amp;str data address: {:p}", slice.as_ptr());
    // Both addresses will match, confirming no copying occurred.
}</code></pre><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.cuongle.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Best practice: Using &amp;str in function signatures</h2><p>Even though you can use <strong>&amp;String</strong>, you generally shouldn't. Prefer <strong>&amp;str</strong> to ensure your functions are more versatile, handling both <strong>String</strong> and string literals seamlessly.</p><pre><code>// Recommended
fn greet(name: &amp;str) {
    println!("Hello, {}!", name);
}

// Less flexible (avoid)
fn greet_string(name: &amp;String) {
    println!("Hello, {}!", name);
}</code></pre><p>By consistently following this best practice, your Rust code becomes cleaner and more flexible.</p><ul><li><p>Rust's separation of <strong>String</strong> and <strong>str</strong> is carefully designed for speed, memory safety, and ease of use without hidden costs.</p></li></ul><p>If you enjoyed this post or found it helpful, I'm Cuong, and I regularly write about Rust and other interesting programming topics. I'd love to connect with you, feel free to reach out on <a href="https://x.com/cuongleqq">X</a>, <a href="https://www.linkedin.com/in/cuong-le/">LinkedIn</a>, or subscribe to my blog for more insights!</p>]]></content:encoded></item></channel></rss>