summaryrefslogtreecommitdiff
path: root/2023/05
diff options
context:
space:
mode:
Diffstat (limited to '2023/05')
-rw-r--r--2023/05/01/Rust-虚表布局规则介绍/index.html21
-rw-r--r--2023/05/02/Rust-Partial-语义/index.html11
-rw-r--r--2023/05/03/Rust-NewType-模式/index.html11
-rw-r--r--2023/05/24/Rust-闭包-lifetime-may-not-live-long-enough-问题/index.html5
4 files changed, 24 insertions, 24 deletions
diff --git a/2023/05/01/Rust-虚表布局规则介绍/index.html b/2023/05/01/Rust-虚表布局规则介绍/index.html
index f4502594..84a18b0c 100644
--- a/2023/05/01/Rust-虚表布局规则介绍/index.html
+++ b/2023/05/01/Rust-虚表布局规则介绍/index.html
@@ -196,39 +196,38 @@
<blockquote>
<p>注意:Rust 虚表及其结构属于 Rust 语言的内部实现细节,不保证稳定性。本文所介绍的虚表布局仅反映本文创作时最新的 Rust 虚表结构[1],在将来 Rust 虚表结构可能会发生变化。一个 Rust 程序的正确性不应该以任何方式依赖于 Rust 虚表的结构。</p>
</blockquote>
-<h2 id="基本结构"><a href="#基本结构" class="headerlink" title="基本结构"></a>基本结构</h2><p>Rust 程序中的所有虚表均以一个固定结构的 header 开头。Header 中按顺序包含三个usize 大小的字段:drop_in_place ,size 和 align 。在 header 之后是一系列的 usize 大小字段,其数量以及含义在每个虚表中可能都不同。</p>
+<h2 id="基本结构"><a class="header-anchor" href="#基本结构">¶</a>基本结构</h2>
+<p>Rust 程序中的所有虚表均以一个固定结构的 header 开头。Header 中按顺序包含三个usize 大小的字段:drop_in_place ,size 和 align 。在 header 之后是一系列的 usize 大小字段,其数量以及含义在每个虚表中可能都不同。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">+---------------+</span><br><span class="line">| drop_in_place |</span><br><span class="line">+---------------+</span><br><span class="line">| size |</span><br><span class="line">+---------------+</span><br><span class="line">| align |</span><br><span class="line">+---------------+</span><br><span class="line">| entry1 |</span><br><span class="line">+---------------+</span><br><span class="line">| entry2 |</span><br><span class="line">+---------------+</span><br><span class="line">| entry3 |</span><br><span class="line">+---------------+</span><br></pre></td></tr></table></figure>
<p>虚表 header 中的drop_in_place 是一个函数指针,其指向的函数能够原地 drop 当前胖指针所引用的对象。size 和 align 两个域分别给出对象的大小和内存对齐,这两个域共同构成一个 std::alloc::Layout 结构,可用于释放当前胖指针所引用的对象所占据的内存。虚表 header 的存在使得 trait object 总是能被销毁和释放。例如当销毁一个 <code>Box&lt;dyn Trait&gt;</code> 时,<code>Box::&lt;dyn Trait&gt;::drop</code> 会首先调用虚表中的 drop_in_place 函数原地销毁 Box 所引用的对象,然后再调用 dealloc 函数并传递虚表中的 size 和 align 释放堆空间。</p>
<p>在虚表 header 之后是一系列的字段。在最普遍的情况下,每个字段代表一个指向 trait 所定义的函数的指针。例如,对于下列 object safe 的 trait:</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">pub</span> <span class="keyword">trait</span> <span class="title class_">Trait</span> &#123;</span><br><span class="line"> <span class="keyword">fn</span> <span class="title function_">fun1</span>(&amp;<span class="keyword">self</span>);</span><br><span class="line"> <span class="keyword">fn</span> <span class="title function_">fun2</span>(&amp;<span class="keyword">self</span>);</span><br><span class="line"> <span class="keyword">fn</span> <span class="title function_">fun3</span>(&amp;<span class="keyword">self</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
-
<p>如果类型T 实现了 Trait,那么为 T 生成的 Trait 虚表的结构为:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">+--------------------------+</span><br><span class="line">| fn drop_in_place(*mut T) |</span><br><span class="line">+--------------------------+</span><br><span class="line">| size of T |</span><br><span class="line">+--------------------------+</span><br><span class="line">| align of T |</span><br><span class="line">+--------------------------+</span><br><span class="line">| fn &lt;T as Trait&gt;::fun1 |</span><br><span class="line">+--------------------------+</span><br><span class="line">| fn &lt;T as Trait&gt;::fun2 |</span><br><span class="line">+--------------------------+</span><br><span class="line">| fn &lt;T as Trait&gt;::fun3 |</span><br><span class="line">+--------------------------+</span><br></pre></td></tr></table></figure>
-
<p>Trait 中的函数按照声明顺序依次排列在虚表 header 之后。当通过一个指向 T 对象的 &amp;dyn Trait 调用 fun2 函数时,程序会先从虚表的第 5 个域中得到为 T 实现的 Trait::fun2 函数的地址,然后再调用之。</p>
-<h2 id="Super-Trait"><a href="#Super-Trait" class="headerlink" title="Super Trait"></a>Super Trait</h2><p>Object safe 的 trait 可以有 super trait。例如:</p>
+<h2 id="Super-Trait"><a class="header-anchor" href="#Super-Trait">¶</a>Super Trait</h2>
+<p>Object safe 的 trait 可以有 super trait。例如:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">pub trait Grand &#123;</span><br><span class="line"> fn grand_fun1(&amp;self);</span><br><span class="line"> fn grand_fun2(&amp;self);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">pub trait Parent : Grand &#123;</span><br><span class="line"> fn parent_fun1(&amp;self);</span><br><span class="line"> fn parent_fun2(&amp;self);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">pub trait Trait : Parent &#123;</span><br><span class="line"> fn fun(&amp;self);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
-
<p>如果类型T 实现了 Trait,那么此时为 T 生成的 Trait 虚表的结构为:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">+-------------------------------+</span><br><span class="line">| fn drop_in_place(*mut T) |</span><br><span class="line">+-------------------------------+</span><br><span class="line">| size of T |</span><br><span class="line">+-------------------------------+</span><br><span class="line">| align of T |</span><br><span class="line">+-------------------------------+</span><br><span class="line">| fn &lt;T as Grand&gt;::grand_fun1 |</span><br><span class="line">+-------------------------------+</span><br><span class="line">| fn &lt;T as Grand&gt;::grand_fun2 |</span><br><span class="line">+-------------------------------+</span><br><span class="line">| fn &lt;T as Parent&gt;::parent_fun1 |</span><br><span class="line">+-------------------------------+</span><br><span class="line">| fn &lt;T as Parent&gt;::parent_fun2 |</span><br><span class="line">+-------------------------------+</span><br><span class="line">| fn &lt;T as Trait&gt;::fun |</span><br><span class="line">+-------------------------------+</span><br></pre></td></tr></table></figure>
-
<p>可以看到,此时Trait 以及 Trait 的所有直接或间接父 trait 所定义的所有函数均包含在虚表 header 之后,且顺序为后序(即先排布 Trait 的父 trait 所定义的所有函数,最后再排布 Trait 所定义的所有函数)。这样的排布方式使得在得到 T 类型的 Trait 虚表的同时也同时得到了 T 类型的 Parent 虚表和 Grand 虚表。T 类型的 Grand 虚表恰好由 Trait 虚表的前五个域构成,T 类型的 Parent 虚表恰好由 Trait 虚表的前七项构成。这使得向上转换变得非常简单。</p>
<p>所谓向上转换,即 Rust 允许将&amp;dyn Trait 转换为 &amp;dyn Parent 或 &amp;dyn Grand 。在向上转换的过程中,胖指针的对象地址域保持不变,但 metadata 域可能需要进行调整,因为不同的 trait 可能具有不同的虚表地址。但在当前示例中,向上转换不需要调整 metadata 域,因为一个指向 Trait 虚表的指针同时也指向 Parent 虚表和 Grand 虚表。在后文中我们会进一步介绍需要调整 metadata 域的向上转换的情况。</p>
<blockquote>
<p>注意:目前 stable Rust 暂不支持向上转换。要使用向上转换特性,必须使用 nightly 工具链,并向源文件中添加 #![feature(trait_upcasting)] 特性开关。</p>
</blockquote>
-<h2 id="多重继承"><a href="#多重继承" class="headerlink" title="多重继承"></a>多重继承</h2><p>Trait 可以有多个 super trait。例如:</p>
+<h2 id="多重继承"><a class="header-anchor" href="#多重继承">¶</a>多重继承</h2>
+<p>Trait 可以有多个 super trait。例如:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">pub trait Base &#123;</span><br><span class="line"> fn base_fun1(&amp;self);</span><br><span class="line"> fn base_fun2(&amp;self);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">pub trait Left : Base &#123;</span><br><span class="line"> fn left_fun1(&amp;self);</span><br><span class="line"> fn left_fun2(&amp;self);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">pub trait Right : Base &#123;</span><br><span class="line"> fn right_fun1(&amp;self);</span><br><span class="line"> fn right_fun2(&amp;self);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">pub trait Trait : Left + Right &#123;</span><br><span class="line"> fn fun(&amp;self);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
-
<p>如果类型T 实现了 Trait,那么此时为 T 生成的 Trait 虚表的结构为:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">+-----------------------------+</span><br><span class="line">| fn drop_in_place(*mut T) |</span><br><span class="line">+-----------------------------+</span><br><span class="line">| size of T |</span><br><span class="line">+-----------------------------+</span><br><span class="line">| align of T |</span><br><span class="line">+-----------------------------+</span><br><span class="line">| fn &lt;T as Base&gt;::base_fun1 |</span><br><span class="line">+-----------------------------+</span><br><span class="line">| fn &lt;T as Base&gt;::base_fun2 |</span><br><span class="line">+-----------------------------+</span><br><span class="line">| fn &lt;T as Left&gt;::left_fun1 |</span><br><span class="line">+-----------------------------+</span><br><span class="line">| fn &lt;T as Left&gt;::left_fun2 |</span><br><span class="line">+-----------------------------+</span><br><span class="line">| fn &lt;T as Right&gt;::right_fun1 |</span><br><span class="line">+-----------------------------+</span><br><span class="line">| fn &lt;T as Right&gt;::right_fun2 |</span><br><span class="line">+-----------------------------+</span><br><span class="line">| ptr to &lt;T as Right&gt;::vtable |</span><br><span class="line">+-----------------------------+</span><br><span class="line">| fn &lt;T as Trait&gt;::fun |</span><br><span class="line">+-----------------------------+</span><br></pre></td></tr></table></figure>
-
<p>可以看到,此时Trait 及其所有直接或间接父 trait 所定义的所有函数仍然包含在虚表内,因此通过 &amp;dyn Trait 调用的函数仍然可以直接从虚表内得到其实际目标函数的地址。另外,Trait 虚表内仍然包含有效的 Base 虚表和 Left 虚表。因此,将 &amp;dyn Trait 向上转换为 &amp;dyn Left 或 &amp;dyn Base 仍然是极其简单的,不需要调整胖指针的 metadata 域。但是,将 &amp;dyn Trait 向上转换为 &amp;dyn Right 就需要调整 metadata 域了,因为 Trait 虚表内并不包含一个有效的 Right 虚表。这也是 Trait 虚表中 ptr to <code>&lt;T as Right&gt;::vtable</code> 域的作用:在执行向上转换时,程序会读取 Trait 虚表的这个域作为得到的 &amp;dyn Right 胖指针的 metadata 。这也是 <em>Rust 向上转换与 C++ 向上转换的一个很大不同:在 C++ 中的向上转换通常并不需要访问虚表(除非需要执行跨虚继承边界的转换),但在 Rust 中向上转换可能需要访问虚表。</em></p>
<p>更加一般地,对于一个 object safe 的 traitTr,将其第一个父 trait、第一个父 trait 的第一个父 trait、…… 这一系列直接或间接父 trait 记为这个 trait 的 PrefixTrait 集合。在将 &amp;dyn Tr 向上转换时,如果转换到的目标 trait 包含在 PrefixTrait 集合内,那么这个向上转换是平凡的:不需要调整胖指针的 metadata 域。否则,这个向上转换需要在 Tr 的虚表内读取目标 trait 的虚表指针作为转换结果的 metadata 。在 Tr 的虚表结构中,位于 PrefixTrait 集合中的父 trait 只需要排布他们所定义的函数即可;对于其他父 trait 还需要额外在虚表内排布一个指向其虚表的指针用于向上转换。</p>
-<h2 id="向下转换"><a href="#向下转换" class="headerlink" title="向下转换"></a>向下转换</h2><p>Rust 提供了一个特殊的 trait:std::any::Any 。该 trait 支持向下转换,即可以将 &amp;dyn Any 转换为 T 。转换过程中会对胖指针所指向的对象的实际类型进行检查,确认其确实是一个 T 类型的对象。Any trait 的虚表结构有一些特殊;在虚表 header 之后,Any 虚表仅包含一个域,这个域直接给出胖指针指向的对象的类型标识(由一个 std::any::TypeId 类型的值表示)。例如,对于任意的 T: ‘static,编译器为其生成的 Any 虚表为:</p>
+<h2 id="向下转换"><a class="header-anchor" href="#向下转换">¶</a>向下转换</h2>
+<p>Rust 提供了一个特殊的 trait:std::any::Any 。该 trait 支持向下转换,即可以将 &amp;dyn Any 转换为 T 。转换过程中会对胖指针所指向的对象的实际类型进行检查,确认其确实是一个 T 类型的对象。Any trait 的虚表结构有一些特殊;在虚表 header 之后,Any 虚表仅包含一个域,这个域直接给出胖指针指向的对象的类型标识(由一个 std::any::TypeId 类型的值表示)。例如,对于任意的 T: 'static,编译器为其生成的 Any 虚表为:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">+--------------------------+</span><br><span class="line">| fn drop_in_place(*mut T) |</span><br><span class="line">+--------------------------+</span><br><span class="line">| size of T |</span><br><span class="line">+--------------------------+</span><br><span class="line">| align of T |</span><br><span class="line">+--------------------------+</span><br><span class="line">| TypeId of T |</span><br><span class="line">+--------------------------+</span><br></pre></td></tr></table></figure>
<p>在执行向下转换时,程序首先检查转换到的类型是否与虚表中给出的TypeId 所标识的类型一致。若类型检查通过,向下转换操作可以直接返回胖指针中的指针域作为转换结果。</p>
-<h3 id="REFERENCE"><a href="#REFERENCE" class="headerlink" title="REFERENCE"></a>REFERENCE</h3><ol>
+<h3 id="REFERENCE"><a class="header-anchor" href="#REFERENCE">¶</a>REFERENCE</h3>
+<ol>
<li>Vtable format to support dyn upcasting coercion <a target="_blank" rel="noopener" href="https://rust-lang.github.io/dyn-upcasting-coercion-initiative/design-discussions/vtable-layout.*html">https://rust-lang.github.io/dyn-upcasting-coercion-initiative/design-discussions/vtable-layout.*html</a>*</li>
</ol>
diff --git a/2023/05/02/Rust-Partial-语义/index.html b/2023/05/02/Rust-Partial-语义/index.html
index b2745990..d56cbb23 100644
--- a/2023/05/02/Rust-Partial-语义/index.html
+++ b/2023/05/02/Rust-Partial-语义/index.html
@@ -195,15 +195,16 @@
<blockquote>
<p>在Rust中,PartialEq和PartialOrd trait处理了不是所有值都可以相互比较的情况。</p>
</blockquote>
-<h2 id="PartialEq-Trait"><a href="#PartialEq-Trait" class="headerlink" title="PartialEq Trait"></a>PartialEq Trait</h2><p>PartialEq trait用于定义值相等性的比较。它的设计允许类型的值之间进行相等(<code>==</code>)和不等(<code>!=</code>)的比较。与其对应的 Eq trait 确保一个类型的所有值都是可以可靠比较的,即满足等价关系的特性,如自反性、对称性和传递性。</p>
+<h2 id="PartialEq-Trait"><a class="header-anchor" href="#PartialEq-Trait">¶</a>PartialEq Trait</h2>
+<p>PartialEq trait用于定义值相等性的比较。它的设计允许类型的值之间进行相等(<code>==</code>)和不等(<code>!=</code>)的比较。与其对应的 Eq trait 确保一个类型的所有值都是可以可靠比较的,即满足等价关系的特性,如自反性、对称性和传递性。</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">fn</span> <span class="title function_">eq</span>(&amp;<span class="keyword">self</span>, other: &amp;<span class="keyword">Self</span>) <span class="punctuation">-&gt;</span> <span class="type">bool</span>;</span><br><span class="line"><span class="keyword">fn</span> <span class="title function_">ne</span>(&amp;<span class="keyword">self</span>, other: &amp;<span class="keyword">Self</span>) <span class="punctuation">-&gt;</span> <span class="type">bool</span>;</span><br></pre></td></tr></table></figure>
-
<p>在大多数情况下,类型的值都能够完全比较相等性,这时可以实现Eq。然而,对于一些特殊类型的值,如浮点数,由于存在无穷大的正负值和NaN值,导致它们的比较更加复杂。例如,根据IEEE浮点数的标准,NaN与任何值(包括它自己)比较都不相等。</p>
-<h2 id="PartialOrd-Trait"><a href="#PartialOrd-Trait" class="headerlink" title="PartialOrd Trait"></a>PartialOrd Trait</h2><p>PartialOrd trait用于定义值之间的大小比较。类似于PartialEq,它允许部分比较大小,返回一个Option,表示比较结果可能存在,也可能不存在(即比较无法进行时返回None):</p>
+<h2 id="PartialOrd-Trait"><a class="header-anchor" href="#PartialOrd-Trait">¶</a>PartialOrd Trait</h2>
+<p>PartialOrd trait用于定义值之间的大小比较。类似于PartialEq,它允许部分比较大小,返回一个Option,表示比较结果可能存在,也可能不存在(即比较无法进行时返回None):</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">fn</span> <span class="title function_">partial_cmp</span>(&amp;<span class="keyword">self</span>, other: &amp;<span class="keyword">Self</span>) <span class="punctuation">-&gt;</span> <span class="type">Option</span>&lt;Ordering&gt;;</span><br></pre></td></tr></table></figure>
-
<p>在全部比较可能的场景,我们会使用Ord trait,它要求实现cmp方法,总是返回一个Ordering,表示两个值之间的确切比较关系。Ord是在所有值都能够比较时使用的,例如整数和字符串。</p>
-<h2 id="设计用意和解决的问题"><a href="#设计用意和解决的问题" class="headerlink" title="设计用意和解决的问题"></a>设计用意和解决的问题</h2><p>Rust 设计 PartialEq 和 PartialOrd trait 主要出于以下几个理由:</p>
+<h2 id="设计用意和解决的问题"><a class="header-anchor" href="#设计用意和解决的问题">¶</a>设计用意和解决的问题</h2>
+<p>Rust 设计 PartialEq 和 PartialOrd trait 主要出于以下几个理由:</p>
<ul>
<li>非总序理念:并不是所有类型都有一个全局的排序方法。例如,复数之间就没有一个自然的大小顺序。为了避免为这些类型人为地赋予一个排序方法,Rust 提供了一个只需部分实现序列操作的选择。</li>
<li>IEEE 浮点数标准:由于浮点数标准定义了特殊值(NaN, 正负无穷),以及NaN不等于自身的规则,浮点数在一些情况下不能进行相等性或大小比较。</li>
diff --git a/2023/05/03/Rust-NewType-模式/index.html b/2023/05/03/Rust-NewType-模式/index.html
index b14dadc3..24f2a78a 100644
--- a/2023/05/03/Rust-NewType-模式/index.html
+++ b/2023/05/03/Rust-NewType-模式/index.html
@@ -193,14 +193,15 @@
</div>
<div class="post-content">
<p>New Type模式是一种软件设计模式,用于在已有类型的基础上创建一个新的类型。在Rust中,这通常是通过定义一个结构体,其中只包含一个单一成员。这个结构体(New Type)对外提供了一个新的、独立的类型,用于对原始类型增加额外的语义或限制。</p>
-<h2 id="加强类型安全"><a href="#加强类型安全" class="headerlink" title="加强类型安全"></a>加强类型安全</h2><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">Meters</span>(<span class="type">f64</span>);</span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Feet</span>(<span class="type">f64</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> <span class="variable">length_in_meters</span> = <span class="title function_ invoke__">Meters</span>(<span class="number">100.0</span>);</span><br><span class="line"><span class="keyword">let</span> <span class="variable">length_in_feet</span> = <span class="title function_ invoke__">Feet</span>(<span class="number">328.084</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 编译器会防止以下代码执行,因为类型不匹配</span></span><br><span class="line"><span class="comment">// let wrong_length = Meters(length_in_feet); // 编译错误</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 正确的构造</span></span><br><span class="line"><span class="keyword">fn</span> <span class="title function_">add_lengths</span>(length1: Meters, length2: Meters) <span class="punctuation">-&gt;</span> Meters &#123;</span><br><span class="line"> <span class="title function_ invoke__">Meters</span>(length1.<span class="number">0</span> + length2.<span class="number">0</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
-
+<h2 id="加强类型安全"><a class="header-anchor" href="#加强类型安全">¶</a>加强类型安全</h2>
+<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">Meters</span>(<span class="type">f64</span>);</span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Feet</span>(<span class="type">f64</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> <span class="variable">length_in_meters</span> = <span class="title function_ invoke__">Meters</span>(<span class="number">100.0</span>);</span><br><span class="line"><span class="keyword">let</span> <span class="variable">length_in_feet</span> = <span class="title function_ invoke__">Feet</span>(<span class="number">328.084</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 编译器会防止以下代码执行,因为类型不匹配</span></span><br><span class="line"><span class="comment">// let wrong_length = Meters(length_in_feet); // 编译错误</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 正确的构造</span></span><br><span class="line"><span class="keyword">fn</span> <span class="title function_">add_lengths</span>(length1: Meters, length2: Meters) <span class="punctuation">-&gt;</span> Meters &#123;</span><br><span class="line"> <span class="title function_ invoke__">Meters</span>(length1.<span class="number">0</span> + length2.<span class="number">0</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这个例子使用 newtype 模式避免将原始类型f64用于不同的量度,从而增强了类型的安全性。</p>
-<h2 id="实现特定-trait"><a href="#实现特定-trait" class="headerlink" title="实现特定 trait"></a>实现特定 trait</h2><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">Kilometers</span>(<span class="type">f64</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span> <span class="title class_">Kilometers</span> &#123;</span><br><span class="line"> <span class="keyword">fn</span> <span class="title function_">to_miles</span>(&amp;<span class="keyword">self</span>) <span class="punctuation">-&gt;</span> <span class="type">f64</span> &#123;</span><br><span class="line"> <span class="keyword">self</span>.<span class="number">0</span> * <span class="number">0.621371</span></span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> <span class="variable">distance</span> = <span class="title function_ invoke__">Kilometers</span>(<span class="number">10.0</span>);</span><br><span class="line"><span class="built_in">println!</span>(<span class="string">&quot;The distance in miles is &#123;&#125;&quot;</span>, distance.<span class="title function_ invoke__">to_miles</span>());</span><br></pre></td></tr></table></figure>
-
+<h2 id="实现特定-trait"><a class="header-anchor" href="#实现特定-trait">¶</a>实现特定 trait</h2>
+<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">Kilometers</span>(<span class="type">f64</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span> <span class="title class_">Kilometers</span> &#123;</span><br><span class="line"> <span class="keyword">fn</span> <span class="title function_">to_miles</span>(&amp;<span class="keyword">self</span>) <span class="punctuation">-&gt;</span> <span class="type">f64</span> &#123;</span><br><span class="line"> <span class="keyword">self</span>.<span class="number">0</span> * <span class="number">0.621371</span></span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> <span class="variable">distance</span> = <span class="title function_ invoke__">Kilometers</span>(<span class="number">10.0</span>);</span><br><span class="line"><span class="built_in">println!</span>(<span class="string">&quot;The distance in miles is &#123;&#125;&quot;</span>, distance.<span class="title function_ invoke__">to_miles</span>());</span><br></pre></td></tr></table></figure>
<p>这里,Kilometers有一个方法to_miles,该方法是不会影响其他f64数据的。如果我们有另一个表示温度的f64类型,就不会意外调用到与距离相关的方法。</p>
<p>New Type模式同样适用于对<code>Box&lt;dyn SomeTrait&gt;</code>类型的包装,这可以在需要动态分派(动态调用实现了某个接口的不同类型的对象的方法)的时候提供便利。通过创建一个New Type来包装这样的<code>Box&lt;dyn SomeTrait&gt;</code>类型,可以提供自定义的方法或实现更多的trait,同时也可以让API更加清晰和易于使用。</p>
-<h2 id="零成本抽象"><a href="#零成本抽象" class="headerlink" title="零成本抽象"></a>零成本抽象</h2><p>在Rust中,New Type模式不仅是类型安全的,还是一种零成本抽象。这是因为Rust编译器在编译时期会进行足够的优化,以确保New Type的使用没有运行时开销。 Rust的零成本抽象原则确保了抽象不会引入额外的运行时成本。例如,当你使用Meters这样的New Type时,Rust确保:</p>
+<h2 id="零成本抽象"><a class="header-anchor" href="#零成本抽象">¶</a>零成本抽象</h2>
+<p>在Rust中,New Type模式不仅是类型安全的,还是一种零成本抽象。这是因为Rust编译器在编译时期会进行足够的优化,以确保New Type的使用没有运行时开销。 Rust的零成本抽象原则确保了抽象不会引入额外的运行时成本。例如,当你使用Meters这样的New Type时,Rust确保:</p>
<ol>
<li>无额外内存开销:Meters只包含一个f64,在内存中的表现和单独的f64是一样的。</li>
<li>无额外运行时开销:使用Meters时,性能和直接使用f64完全相同。编译器会移除任何关于New Type的包装和解包的代码。</li>
diff --git a/2023/05/24/Rust-闭包-lifetime-may-not-live-long-enough-问题/index.html b/2023/05/24/Rust-闭包-lifetime-may-not-live-long-enough-问题/index.html
index e208733c..a44f767e 100644
--- a/2023/05/24/Rust-闭包-lifetime-may-not-live-long-enough-问题/index.html
+++ b/2023/05/24/Rust-闭包-lifetime-may-not-live-long-enough-问题/index.html
@@ -194,13 +194,12 @@
<div class="post-content">
<p>代码:</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"> <span class="keyword">fn</span> <span class="title function_">handlers</span>(<span class="keyword">self</span>) <span class="punctuation">-&gt;</span> crate::server::request::Handlers &#123;</span><br><span class="line"> <span class="built_in">vec!</span>[(</span><br><span class="line"> <span class="string">&quot;/tree&quot;</span>,</span><br><span class="line"> routing::<span class="title function_ invoke__">get</span>(<span class="keyword">move</span> || <span class="keyword">async</span> &#123;</span><br><span class="line"> (</span><br><span class="line"> StatusCode::OK,</span><br><span class="line"> <span class="title function_ invoke__">Json</span>(json!(<span class="keyword">self</span>.<span class="title function_ invoke__">clone</span>().<span class="title function_ invoke__">tree</span>(<span class="keyword">self</span>.<span class="title function_ invoke__">clone</span>().root))),</span><br><span class="line"> )</span><br><span class="line"> &#125;),</span><br><span class="line"> )]</span><br><span class="line"> &#125;</span><br><span class="line">...</span><br></pre></td></tr></table></figure>
-
<p>编译错误:</p>
<figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">error: lifetime may not live long enough</span><br><span class="line"> --&gt; src/storage/filesystem/mod.rs:45:34</span><br><span class="line"> |</span><br><span class="line">45 | routing::get(move || async &#123;</span><br><span class="line"> | __________________________-------_^</span><br><span class="line"> | | | |</span><br><span class="line"> | | | return type of closure `&#123;async block@src/storage/filesystem/mod.rs:45:34: 50:14&#125;` contains a lifetime `&#x27;2`</span><br><span class="line"> | | lifetime `&#x27;1` represents this closure&#x27;s body</span><br><span class="line">46 | | (</span><br><span class="line">47 | | StatusCode::OK,</span><br><span class="line">48 | | Json(json!(self.clone().tree(self.clone().root))),</span><br><span class="line">49 | | )</span><br><span class="line">50 | | &#125;),</span><br><span class="line"> | |_____________^ returning this value requires that `&#x27;1` must outlive `&#x27;2`</span><br><span class="line"> |</span><br><span class="line"> = note: closure implements `Fn`, so references to captured variables can&#x27;t escape the closure</span><br></pre></td></tr></table></figure>
-
<p>这是因为 <code>handlers</code> 里面的闭包捕获了一个引用,并且尝试返回一个包含该引用的值导致的。</p>
<p>细说就是:闭包内部使用了 <code>self.clone()</code> 来获取一个新的实例,然后在异步块中返回一个 JSON 对象,这个 JSON 对象依赖于 <code>self.tree()</code> 的结果。因为闭包捕获了 <code>self</code> 的引用,所以它必须保证 <code>self</code> 在闭包执行完毕后仍然有效。</p>
-<p>解决这个问题的思路是:确保闭包中的所有引用都在闭包执行完毕之前就不再被使用。<br>就是说,要将闭包的作用域限制在一个更短的生命周期内,或者使用其他方式来避免闭包捕获长期存在的引用:</p>
+<p>解决这个问题的思路是:确保闭包中的所有引用都在闭包执行完毕之前就不再被使用。<br>
+就是说,要将闭包的作用域限制在一个更短的生命周期内,或者使用其他方式来避免闭包捕获长期存在的引用:</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">...</span><br><span class="line"> <span class="keyword">fn</span> <span class="title function_">handlers</span>(<span class="keyword">self</span>) <span class="punctuation">-&gt;</span> crate::server::request::Handlers &#123;</span><br><span class="line"> <span class="keyword">let</span> <span class="variable">tree</span> = json!(<span class="keyword">self</span>.<span class="title function_ invoke__">clone</span>().<span class="title function_ invoke__">tree</span>(<span class="keyword">self</span>.<span class="title function_ invoke__">clone</span>().root));</span><br><span class="line"> <span class="built_in">vec!</span>[(</span><br><span class="line"> <span class="string">&quot;/tree&quot;</span>,</span><br><span class="line"> routing::<span class="title function_ invoke__">get</span>(<span class="keyword">move</span> || <span class="keyword">async</span> &#123; (StatusCode::OK, <span class="title function_ invoke__">Json</span>(tree)) &#125;),</span><br><span class="line"> )]</span><br><span class="line"> &#125;</span><br><span class="line">...</span><br></pre></td></tr></table></figure>
</div>