浅谈 Rust 中如何把 Async Function 放在 HashMap 里
<img src="https://public.ptree.top/ShareX/2025/04/30/1745996947/DtZpswlzd6.png" alt="Featured image of post 浅谈 Rust 中如何把 Async Function 放在 HashMap 里" /><h1 id="需求">需求</h1>
<p>经常会有这样的需求,需要根据具体参数的不同调用不同的处理函数。</p>
<p>比如根据 URL 的不同,调用不同的路由 handler;根据 command 的不同,调用不同的处理 handler。</p>
<p>这些需求基本都可以抽象为一件事:把 function 放在 HashMap 里。</p>
<p>如果是异步编程的话,那么就是把 async function 放在 HashMap 里了。</p>
<p>这件事在 Rust 中做起来,要比想象中困难。</p>
<p>今天就来浅谈一下这个主题。</p>
<h1 id="框架">框架</h1>
<p>我们希望设计一个路由器结构体,里面放一个 HashMap。</p>
<p>HashMap 以 String 为 key,具体的处理函数为 value。</p>
<p>在初始化的时候把处理函数按不同的 key 放到 HashMap 里,调用时根据不同情况按 key 取出。</p>
<p>简化的话,处理函数就定为接受一个 String 并返回一个 String。</p>
<p>大概是这种感觉:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">pin</span>::<span class="n">Pin</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">sync</span>::<span class="n">Arc</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">time</span>::<span class="n">Duration</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">sync</span>::<span class="n">RwLock</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">time</span>::<span class="n">sleep</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">type</span> <span class="nc">HandlerFn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="c1">// TODO 需要写一个 Handler 的具体类型
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#[derive(Default, Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">table</span>: <span class="nc">Arc</span><span class="o"><</span><span class="n">RwLock</span><span class="o"><</span><span class="n">HashMap</span><span class="o"><</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="n">HandlerFn</span><span class="o">>>></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c1">// TODO 需要一个 add 函数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="c1">// async fn add
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[tokio::main]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">router</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Router</span>::<span class="n">default</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">,</span><span class="w"> </span><span class="n">handler1</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">,</span><span class="w"> </span><span class="n">handler2</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="s">"req1"</span><span class="p">.</span><span class="n">into</span><span class="p">()).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="s">"req2"</span><span class="p">.</span><span class="n">into</span><span class="p">()).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="fm">join!</span><span class="p">(</span><span class="n">handle1</span><span class="p">,</span><span class="w"> </span><span class="n">handle2</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handler1</span><span class="p">(</span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">sleep</span><span class="p">(</span><span class="n">Duration</span>::<span class="n">from_secs</span><span class="p">(</span><span class="mi">1</span><span class="p">)).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"handler1"</span><span class="p">.</span><span class="n">into</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handler2</span><span class="p">(</span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">sleep</span><span class="p">(</span><span class="n">Duration</span>::<span class="n">from_secs</span><span class="p">(</span><span class="mi">1</span><span class="p">)).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"handler2"</span><span class="p">.</span><span class="n">into</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h1 id="handlerfn-的类型">HandlerFn 的类型</h1>
<p>我们的 HandlerFn 应该是一个 async 函数。</p>
<p>在 Rust 里 async 函数实际上就是一个普通函数,只不过它需要返回 Future。</p>
<p>我们先来尝试一下这么做:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">type</span> <span class="nc">HandlerFn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[derive(Default, Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">table</span>: <span class="nc">Arc</span><span class="o"><</span><span class="n">RwLock</span><span class="o"><</span><span class="n">HashMap</span><span class="o"><</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="n">HandlerFn</span><span class="o">>>></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>输出的错误是:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="n">error</span><span class="p">[</span><span class="n">E0782</span><span class="p">]:</span><span class="w"> </span><span class="n">expected</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">type</span><span class="p">,</span><span class="w"> </span><span class="n">found</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">trait</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">--></span><span class="w"> </span><span class="n">src</span><span class="err">\</span><span class="n">bin</span><span class="err">\</span><span class="n">attempt1</span><span class="p">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">8</span><span class="p">:</span><span class="mi">18</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">8</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">HandlerFn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">Fn</span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">help</span><span class="p">:</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">can</span><span class="w"> </span><span class="k">add</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="o">`</span><span class="n">dyn</span><span class="o">`</span><span class="w"> </span><span class="n">keyword</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">trait</span><span class="w"> </span><span class="n">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">8</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">HandlerFn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">dyn</span><span class="w"> </span><span class="nf">Fn</span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">+++</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>Fn 和 Future 都是特征,而不是具体类型。</p>
<p>作为 HashMap 的 value 我们需要一个具体的类型。</p>
<p>直接加 dyn 显然是不行的,需要先把它进行装箱。</p>
<p>所以变成了这样子:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">type</span> <span class="nc">HandlerFn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">>>></span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[derive(Default, Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">table</span>: <span class="nc">Arc</span><span class="o"><</span><span class="n">RwLock</span><span class="o"><</span><span class="n">HashMap</span><span class="o"><</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="n">HandlerFn</span><span class="o">>>></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>这样编译姑且是没问题的。</p>
<p>但这不是最终的类型,之后会说明为什么。</p>
<h1 id="实现-add-函数">实现 add 函数</h1>
<p>接下来需要一个函数把 handler 放到 HashMap 里,供初始化的时候调用。</p>
<p>我们可能会写出这样的代码,这里直接把我们上面定义的 HandlerFn 作为参数:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">impl</span><span class="w"> </span><span class="n">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">key</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span>: <span class="nc">HandlerFn</span><span class="p">)</span><span class="w"> </span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="o">..</span><span class="p">.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">,</span><span class="w"> </span><span class="n">handler1</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">,</span><span class="w"> </span><span class="n">handler2</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>但是 router.add 调用的时候报错了:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">error[E0308]: mismatched types
</span></span><span class="line"><span class="cl"> --> src\bin\attempt1.rs:26:28
</span></span><span class="line"><span class="cl"> |
</span></span><span class="line"><span class="cl">26 | router.add("handler1", handler1).await;
</span></span><span class="line"><span class="cl"> | --- ^^^^^^^^ expected `Box<dyn Fn(String) -> Box<...>>`, found fn item
</span></span><span class="line"><span class="cl"> | |
</span></span><span class="line"><span class="cl"> | arguments to this method are incorrect
</span></span><span class="line"><span class="cl"> |
</span></span><span class="line"><span class="cl"> = note: expected struct `Box<(dyn Fn(String) -> Box<(dyn Future<Output = String> + 'static)> + 'static)>`
</span></span><span class="line"><span class="cl"> found fn item `fn(String) -> impl Future<Output = String> {handler1}`
</span></span></code></pre></td></tr></table>
</div>
</div><p>因为我们是直接把 async function 传到 add 里面的,async function 又没有装箱,当然不能直接传进去。</p>
<p>那我们应该为 add 函数的 handler 这个参数定一个类型,让它能直接接收 async function 的引用。</p>
<h2 id="参数类型">参数类型</h2>
<p>看编译的报错信息,似乎可以这样写:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">key</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span>: <span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">impl</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">)</span><span class="w"> </span><span class="p">{}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>很遗憾这样是不行的:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="n">error</span><span class="p">[</span><span class="n">E0562</span><span class="p">]:</span><span class="w"> </span><span class="o">`</span><span class="n">impl</span><span class="w"> </span><span class="n">Trait</span><span class="o">`</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="k">not</span><span class="w"> </span><span class="n">allowed</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="o">`</span><span class="n">Fn</span><span class="o">`</span><span class="w"> </span><span class="n">trait</span><span class="w"> </span><span class="n">bounds</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">--></span><span class="w"> </span><span class="n">src</span><span class="err">\</span><span class="n">bin</span><span class="err">\</span><span class="n">attempt1</span><span class="p">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">14</span><span class="p">:</span><span class="mi">63</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">14</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">async</span><span class="w"> </span><span class="n">fn</span><span class="w"> </span><span class="k">add</span><span class="p">(</span><span class="o">&</span><span class="n">mut</span><span class="w"> </span><span class="n">self</span><span class="p">,</span><span class="w"> </span><span class="k">key</span><span class="p">:</span><span class="w"> </span><span class="o">&</span><span class="n">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span><span class="p">:</span><span class="w"> </span><span class="nf">Fn</span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">impl</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="p">)</span><span class="w"> </span><span class="err">{}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">^^^^^^^^^^^^^^^^^^^^^^^^^^^^</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">note</span><span class="p">:</span><span class="w"> </span><span class="o">`</span><span class="n">impl</span><span class="w"> </span><span class="n">Trait</span><span class="o">`</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">only</span><span class="w"> </span><span class="n">allowed</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">arguments</span><span class="w"> </span><span class="k">and</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">types</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">functions</span><span class="w"> </span><span class="k">and</span><span class="w"> </span><span class="n">methods</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>这里的 <code>handler</code> 参数的类型被指定为 <code>Fn(String) -> impl Future<Output = String></code>。这是一个 Trait 约束,它要求 <code>handler</code> 参数的类型必须实现 <code>Fn</code> Trait,并且这个 <code>Fn</code> Trait 的调用签名是接受一个 <code>String</code> 参数,并返回一个实现了 <code>Future<Output = String></code> Trait 的<strong>某个具体但未指定类型</strong>。</p>
<p><code>impl Trait</code> 主要用于函数的<strong>参数</strong>位置(表示接受任何实现了该 Trait 的类型)和函数的<strong>返回类型</strong>位置(表示返回一个实现了该 Trait 的某个具体类型,但调用者不知道具体是哪个类型,这被称为“不透明返回类型”)。它是一种语法糖,用于避免写出复杂的具体类型名称,尤其是在处理闭包和异步函数返回的 Future 类型时非常方便。</p>
<p>当你在参数位置使用 <code>Fn(Args) -> Return</code> 时,你是在定义一个 Trait 约束,说明参数的类型必须实现 <code>Fn</code> Trait,并且其调用签名符合 <code>(Args) -> Return</code>。这里的 <code>Return</code> 部分实际上是在描述 <code>Fn</code> Trait 的关联类型 <code>Output</code>。</p>
<p><code>impl Future<Output = String></code> 表示一个<strong>不透明的、具体类型</strong>。而 <code>Fn</code> Trait 约束的 <code>Return</code> 位置需要的是一个<strong>具体的类型</strong>或者一个<strong>关联类型</strong>的定义。你不能在一个 Trait 定义(或者 Trait 约束,它本质上是基于 Trait 定义的)中使用 <code>impl Trait</code> 来表示关联类型,因为 <code>impl Trait</code> 本身不是一个具体的类型名称,它只是一个类型占位符,其具体类型只有实现 Trait 的那个类型才知道。</p>
<p>简单来说,<code>impl Trait</code> 是用来隐藏具体类型的,而 Trait 定义(或 Trait 约束)需要知道它操作的类型是什么(即使是通过关联类型)。你不能说一个 Trait 的关联类型是“某个实现了 Future 的东西”,你必须说它是“一个实现了 Future 的具体类型 <code>MyFuture</code>”或者使用一个泛型参数来代表这个具体类型。</p>
<h2 id="对-handler-本身和返回的-future-装箱">对 handler 本身和返回的 Future 装箱</h2>
<p>我们改成用泛型类型来实现:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">impl</span><span class="w"> </span><span class="n">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">key</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span>: <span class="nc">Fun</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nc">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">write</span><span class="p">().</span><span class="k">await</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">key</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w"> </span><span class="n">handler</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>这样可以了,但是有新的报错:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="n">error</span><span class="p">[</span><span class="n">E0308</span><span class="p">]:</span><span class="w"> </span><span class="n">mismatched</span><span class="w"> </span><span class="n">types</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">--></span><span class="w"> </span><span class="n">src</span><span class="err">\</span><span class="n">bin</span><span class="err">\</span><span class="n">attempt1</span><span class="p">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">58</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">14</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">async</span><span class="w"> </span><span class="n">fn</span><span class="w"> </span><span class="k">add</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="n">mut</span><span class="w"> </span><span class="n">self</span><span class="p">,</span><span class="w"> </span><span class="k">key</span><span class="p">:</span><span class="w"> </span><span class="o">&</span><span class="n">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span><span class="p">:</span><span class="w"> </span><span class="n">Fun</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">-</span><span class="c1">-- found this type parameter
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">19</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">self</span><span class="p">.</span><span class="k">table</span><span class="p">.</span><span class="k">write</span><span class="p">().</span><span class="n">await</span><span class="p">.</span><span class="k">insert</span><span class="p">(</span><span class="k">key</span><span class="p">.</span><span class="nf">to_string</span><span class="p">(),</span><span class="w"> </span><span class="n">handler</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">----</span><span class="c1">-- ^^^^^^^ expected `Box<dyn Fn(String) -> Box<...>>`, found type parameter `Fun`
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">arguments</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">method</span><span class="w"> </span><span class="n">are</span><span class="w"> </span><span class="n">incorrect</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">note</span><span class="p">:</span><span class="w"> </span><span class="n">expected</span><span class="w"> </span><span class="n">struct</span><span class="w"> </span><span class="o">`</span><span class="n">Box</span><span class="o"><</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="nf">Fn</span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">Box</span><span class="o"><</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static)> + '</span><span class="n">static</span><span class="p">)</span><span class="o">>`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">found</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">parameter</span><span class="w"> </span><span class="o">`</span><span class="n">Fun</span><span class="o">`</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>因为 HashMap 的 value 必须是一个 Box 装箱的 Fn,所以直接把 handler 作为 Fn 传进去不行。</p>
<p>那我们用 Box::new 装箱?</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">impl</span><span class="w"> </span><span class="n">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">key</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span>: <span class="nc">Fun</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nc">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">write</span><span class="p">().</span><span class="k">await</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">key</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="n">handler</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>还是不行:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="n">error</span><span class="p">[</span><span class="n">E0271</span><span class="p">]:</span><span class="w"> </span><span class="n">expected</span><span class="w"> </span><span class="o">`</span><span class="n">Fun</span><span class="o">`</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">parameter</span><span class="w"> </span><span class="n">that</span><span class="w"> </span><span class="n">returns</span><span class="w"> </span><span class="o">`</span><span class="n">Box</span><span class="o"><</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">>>`</span><span class="p">,</span><span class="w"> </span><span class="n">but</span><span class="w"> </span><span class="n">it</span><span class="w"> </span><span class="n">returns</span><span class="w"> </span><span class="o">`</span><span class="n">Fut</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">--></span><span class="w"> </span><span class="n">src</span><span class="err">\</span><span class="n">bin</span><span class="err">\</span><span class="n">attempt1</span><span class="p">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">58</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">14</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">async</span><span class="w"> </span><span class="n">fn</span><span class="w"> </span><span class="k">add</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="n">mut</span><span class="w"> </span><span class="n">self</span><span class="p">,</span><span class="w"> </span><span class="k">key</span><span class="p">:</span><span class="w"> </span><span class="o">&</span><span class="n">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span><span class="p">:</span><span class="w"> </span><span class="n">Fun</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">-</span><span class="c1">-- found this type parameter
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">19</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">self</span><span class="p">.</span><span class="k">table</span><span class="p">.</span><span class="k">write</span><span class="p">().</span><span class="n">await</span><span class="p">.</span><span class="k">insert</span><span class="p">(</span><span class="k">key</span><span class="p">.</span><span class="nf">to_string</span><span class="p">(),</span><span class="w"> </span><span class="n">Box</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">handler</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">^^^^^^^^^^^^^^^^^</span><span class="w"> </span><span class="n">expected</span><span class="w"> </span><span class="o">`</span><span class="n">Box</span><span class="o"><</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">>>`</span><span class="p">,</span><span class="w"> </span><span class="n">found</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">parameter</span><span class="w"> </span><span class="o">`</span><span class="n">Fut</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">note</span><span class="p">:</span><span class="w"> </span><span class="n">expected</span><span class="w"> </span><span class="n">struct</span><span class="w"> </span><span class="o">`</span><span class="n">Box</span><span class="o"><</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static)>`
</span></span></span><span class="line"><span class="cl"><span class="s1"> found type parameter `Fut`
</span></span></span><span class="line"><span class="cl"><span class="s1"> = note: required for the cast from `Box<Fun>` to `Box<(dyn Fn(String) -> Box<(dyn Future<Output = String> + '</span><span class="n">static</span><span class="p">)</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static)>`
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>为啥?因为我们 HandlerFn 要求的 Future 也是装箱的。只把 handler 本身装箱不行。</p>
<p>那我怎么可以改掉 handler 返回的 Future 类型?</p>
<p>答案是使用闭包:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">impl</span><span class="w"> </span><span class="n">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">key</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span>: <span class="nc">Fun</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nc">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">write</span><span class="p">().</span><span class="k">await</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">key</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">|</span><span class="n">s</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="n">s</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="n">fut</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>这里两个 Box::new,第一个是把 handler 函数装箱,第二个是把调用这个 handler 函数返回的 Future 装箱。</p>
<p>注意闭包的 move,因为我们要把 handler 的所有权移动到闭包里。</p>
<p>这样看起来行了吧?</p>
<h2 id="解决生命周期问题">解决生命周期问题</h2>
<p>下面是新的报错:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="n">error</span><span class="p">[</span><span class="n">E0310</span><span class="p">]:</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">parameter</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">`</span><span class="n">Fun</span><span class="o">`</span><span class="w"> </span><span class="n">may</span><span class="w"> </span><span class="k">not</span><span class="w"> </span><span class="n">live</span><span class="w"> </span><span class="k">long</span><span class="w"> </span><span class="n">enough</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">--></span><span class="w"> </span><span class="n">src</span><span class="err">\</span><span class="n">bin</span><span class="err">\</span><span class="n">attempt1</span><span class="p">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">21</span><span class="p">:</span><span class="mi">13</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">21</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">Box</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">move</span><span class="w"> </span><span class="o">|</span><span class="n">s</span><span class="o">|</span><span class="w"> </span><span class="err">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">22</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">handler</span><span class="p">(</span><span class="n">s</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">23</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Box</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">fut</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">24</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="err">}</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">^</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="n">______________the</span><span class="w"> </span><span class="n">parameter</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">`</span><span class="n">Fun</span><span class="o">`</span><span class="w"> </span><span class="n">must</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">valid</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">static</span><span class="w"> </span><span class="n">lifetime</span><span class="p">...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="p">...</span><span class="n">so</span><span class="w"> </span><span class="n">that</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">`</span><span class="n">Fun</span><span class="o">`</span><span class="w"> </span><span class="n">will</span><span class="w"> </span><span class="n">meet</span><span class="w"> </span><span class="n">its</span><span class="w"> </span><span class="n">required</span><span class="w"> </span><span class="n">lifetime</span><span class="w"> </span><span class="n">bounds</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">help</span><span class="p">:</span><span class="w"> </span><span class="n">consider</span><span class="w"> </span><span class="n">adding</span><span class="w"> </span><span class="n">an</span><span class="w"> </span><span class="n">explicit</span><span class="w"> </span><span class="n">lifetime</span><span class="w"> </span><span class="n">bound</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">16</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Fun</span><span class="p">:</span><span class="w"> </span><span class="nf">Fn</span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">Fut</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static,
</span></span></span><span class="line"><span class="cl"><span class="s1"> | +++++++++
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>我们既然要把 handler 函数装箱,那 Box 就必须拥有它的所有权。</p>
<p>而我们使用 Fun 类型约束传入的 handler 函数的,因此我们必须约束传入的 handler 是所有权的,而不是一个引用。</p>
<p>解决方法是给 Fun 加上’static 约束:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">impl</span><span class="w"> </span><span class="n">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">key</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span>: <span class="nc">Fun</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nc">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">write</span><span class="p">().</span><span class="k">await</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">key</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">|</span><span class="n">s</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="n">s</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="n">fut</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>关于’static 和所有权到底有啥关系,推荐看看这篇文章:<a class="link" href="https://github.com/pretzelhammer/rust-blog/blob/master/posts/translations/zh-hans/common-rust-lifetime-misconceptions.md" target="_blank" rel="noopener"
>Rust 中常见的有关生命周期的误解</a></p>
<p>好了,又有新的报错:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="n">error</span><span class="p">[</span><span class="n">E0310</span><span class="p">]:</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">parameter</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">`</span><span class="n">Fut</span><span class="o">`</span><span class="w"> </span><span class="n">may</span><span class="w"> </span><span class="k">not</span><span class="w"> </span><span class="n">live</span><span class="w"> </span><span class="k">long</span><span class="w"> </span><span class="n">enough</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">--></span><span class="w"> </span><span class="n">src</span><span class="err">\</span><span class="n">bin</span><span class="err">\</span><span class="n">attempt1</span><span class="p">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">23</span><span class="p">:</span><span class="mi">17</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">23</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Box</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">fut</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">^^^^^^^^^^^^^</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">parameter</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">`</span><span class="n">Fut</span><span class="o">`</span><span class="w"> </span><span class="n">must</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">valid</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">static</span><span class="w"> </span><span class="n">lifetime</span><span class="p">...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="p">...</span><span class="n">so</span><span class="w"> </span><span class="n">that</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">`</span><span class="n">Fut</span><span class="o">`</span><span class="w"> </span><span class="n">will</span><span class="w"> </span><span class="n">meet</span><span class="w"> </span><span class="n">its</span><span class="w"> </span><span class="n">required</span><span class="w"> </span><span class="n">lifetime</span><span class="w"> </span><span class="n">bounds</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">help</span><span class="p">:</span><span class="w"> </span><span class="n">consider</span><span class="w"> </span><span class="n">adding</span><span class="w"> </span><span class="n">an</span><span class="w"> </span><span class="n">explicit</span><span class="w"> </span><span class="n">lifetime</span><span class="w"> </span><span class="n">bound</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">17</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Fut</span><span class="p">:</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static,
</span></span></span><span class="line"><span class="cl"><span class="s1"> | +++++++++
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>由于我们也给 Future 装箱了,所以我们也要保证 Fut 类型拥有所有权。同样给它加上’static 约束:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">impl</span><span class="w"> </span><span class="n">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">key</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span>: <span class="nc">Fun</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">write</span><span class="p">().</span><span class="k">await</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">key</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">|</span><span class="n">s</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="n">s</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="n">fut</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>这样没问题了,但很可惜东窗事发,下面 tokio::spawn 那边出问题了。</p>
<h2 id="解决-pinsend-和-sync-问题">解决 Pin、Send 和 Sync 问题</h2>
<h3 id="future-必须是-unpin">Future 必须是 Unpin</h3>
<p>还记得我们的 main 函数是啥?</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="cp">#[tokio::main]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">router</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Router</span>::<span class="n">default</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">,</span><span class="w"> </span><span class="n">handler1</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">,</span><span class="w"> </span><span class="n">handler2</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="s">"req1"</span><span class="p">.</span><span class="n">into</span><span class="p">()).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="s">"req2"</span><span class="p">.</span><span class="n">into</span><span class="p">()).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="fm">join!</span><span class="p">(</span><span class="n">handle1</span><span class="p">,</span><span class="w"> </span><span class="n">handle2</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>报错:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="n">error</span><span class="p">[</span><span class="n">E0277</span><span class="p">]:</span><span class="w"> </span><span class="o">`</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">>`</span><span class="w"> </span><span class="n">cannot</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">unpinned</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">--></span><span class="w"> </span><span class="n">src</span><span class="err">\</span><span class="n">bin</span><span class="err">\</span><span class="n">attempt1</span><span class="p">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">38</span><span class="p">:</span><span class="mi">36</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">38</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="nf">handler</span><span class="p">(</span><span class="s2">"req1"</span><span class="p">.</span><span class="k">into</span><span class="p">()).</span><span class="n">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">-----------------------^^^^^</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">||</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="n">the</span><span class="w"> </span><span class="n">trait</span><span class="w"> </span><span class="o">`</span><span class="n">Unpin</span><span class="o">`</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="k">not</span><span class="w"> </span><span class="n">implemented</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="o">`</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">>`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">help</span><span class="p">:</span><span class="w"> </span><span class="n">remove</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="o">`</span><span class="p">.</span><span class="n">await</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="n">returns</span><span class="w"> </span><span class="o">`</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">>`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">note</span><span class="p">:</span><span class="w"> </span><span class="n">consider</span><span class="w"> </span><span class="k">using</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="o">`</span><span class="n">pin</span><span class="o">!`</span><span class="w"> </span><span class="n">macro</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">consider</span><span class="w"> </span><span class="k">using</span><span class="w"> </span><span class="o">`</span><span class="n">Box</span><span class="p">::</span><span class="n">pin</span><span class="o">`</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">need</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">access</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">pinned</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="n">outside</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">current</span><span class="w"> </span><span class="n">scope</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">note</span><span class="p">:</span><span class="w"> </span><span class="n">required</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="o">`</span><span class="n">Box</span><span class="o"><</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">>>`</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">implement</span><span class="w"> </span><span class="o">`</span><span class="n">Future</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">note</span><span class="p">:</span><span class="w"> </span><span class="n">required</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="o">`</span><span class="n">Box</span><span class="o"><</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">>>`</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">implement</span><span class="w"> </span><span class="o">`</span><span class="n">IntoFuture</span><span class="o">`</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>这是说 Future 必须要是 Unpin 的,因为我们在一个 tokio 协程中调用了 await,在这个 await 点上它会不断去 poll 这个 Future,在这个过程中它可能在线程中移动,导致其中的自引用指针不安全。所以必须把它 Pin 起来。用 Pin 包装一层之后,Pin<Box<dyn Future>> 本身是 Unpin 的,就可以安全地 await 它了。</p>
<p>好,那我们把它 Pin 一下。由于 Future 已经在 Box 里了,我们直接使用 Box::into_pin:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="s">"req1"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">pinned_fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span>::<span class="n">into_pin</span><span class="p">(</span><span class="n">fut</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">pinned_fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>注意哈,关于 Pin 常用的有三个函数的区别:</p>
<ul>
<li>Box::into_pin(x):x 本身是个 Box<Future>,把它装到 Pin 里,变成 Pin<Box<Future>></li>
<li>Box::pin(x):x 本身是个 Future,把它装到 Pin<Box>里,变成 Pin<Box<Future>>;相当于 Box::into_pin(Box::new(x))</li>
<li>Pin::new(x):x 是个&mut 指针;基本用不到这个函数</li>
</ul>
<h3 id="fn-必须是-send">Fn 必须是 Send</h3>
<p>下面来看新的报错:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="n">error</span><span class="p">[</span><span class="n">E0277</span><span class="p">]:</span><span class="w"> </span><span class="o">`</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="nf">Fn</span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">Box</span><span class="o"><</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static)> + '</span><span class="n">static</span><span class="p">)</span><span class="o">`</span><span class="w"> </span><span class="n">cannot</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">sent</span><span class="w"> </span><span class="k">between</span><span class="w"> </span><span class="n">threads</span><span class="w"> </span><span class="n">safely</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">--></span><span class="w"> </span><span class="n">src</span><span class="err">\</span><span class="n">bin</span><span class="err">\</span><span class="n">attempt1</span><span class="p">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">35</span><span class="p">:</span><span class="mi">35</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">35</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span><span class="p">::</span><span class="nf">spawn</span><span class="p">(</span><span class="n">async</span><span class="w"> </span><span class="n">move</span><span class="w"> </span><span class="err">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">______________________</span><span class="o">------------</span><span class="n">_</span><span class="o">^</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">required</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">bound</span><span class="w"> </span><span class="n">introduced</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="k">call</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">36</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="k">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="k">table</span><span class="p">.</span><span class="k">read</span><span class="p">().</span><span class="n">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">37</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">lock</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="s2">"handler1"</span><span class="p">).</span><span class="nf">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">38</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">handler</span><span class="p">(</span><span class="s2">"req1"</span><span class="p">.</span><span class="k">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">39</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">pinned_fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Box</span><span class="p">::</span><span class="nf">into_pin</span><span class="p">(</span><span class="n">fut</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">40</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">pinned_fut</span><span class="p">.</span><span class="n">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">41</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="err">}</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="n">_________</span><span class="o">^</span><span class="w"> </span><span class="o">`</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="nf">Fn</span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">Box</span><span class="o"><</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static)> + '</span><span class="n">static</span><span class="p">)</span><span class="o">`</span><span class="w"> </span><span class="n">cannot</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">sent</span><span class="w"> </span><span class="k">between</span><span class="w"> </span><span class="n">threads</span><span class="w"> </span><span class="n">safely</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">help</span><span class="p">:</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">trait</span><span class="w"> </span><span class="o">`</span><span class="n">Send</span><span class="o">`</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="k">not</span><span class="w"> </span><span class="n">implemented</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="o">`</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="nf">Fn</span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">Box</span><span class="o"><</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static)> + '</span><span class="n">static</span><span class="p">)</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">note</span><span class="p">:</span><span class="w"> </span><span class="n">required</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="o">`</span><span class="k">Unique</span><span class="o"><</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="nf">Fn</span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">Box</span><span class="o"><</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static)> + '</span><span class="n">static</span><span class="p">)</span><span class="o">>`</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">implement</span><span class="w"> </span><span class="o">`</span><span class="n">Send</span><span class="o">`</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p><code>tokio::spawn</code> 创建的任务可以在不同的线程上执行,Tokio 运行时可能会在 <code>.await</code> 点之间将任务从一个线程移动到另一个线程。当一个任务被移动时,它所拥有的所有数据(包括从 <code>Router</code> 中读取并正在使用的 <code>HandlerFn</code>)也必须能够安全地跨线程移动。<code>Fn</code> 特征对象(<code>dyn Fn(...)</code>)代表一个函数或闭包,它可能捕获了环境中的变量。如果这个函数或闭包捕获了非 <code>Send</code> 的数据(例如 <code>Rc</code> 或裸指针),那么将它移动到另一个线程是不安全的,会导致数据竞争或其他未定义行为。因此,为了保证在多线程环境中安全地从共享的 <code>HashMap</code> 中获取并调用 <code>Fn</code> 特征对象,该特征对象本身必须实现 <code>Send</code> 特征,表明它可以安全地在线程间转移所有权。</p>
<p>为什么要显式声明?因为 Box 里面的特征对象 Rust 是不会帮我们自动推导它的约束的,所以 Send、Sync 包括’static,如果要约束的话,都得我们自己写。</p>
<p>因此改一下 HandlerFn 的类型定义:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">type</span> <span class="nc">HandlerFn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">>></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="o">></span><span class="p">;</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h3 id="fn-必须是-sync">Fn 必须是 Sync</h3>
<p>解决之后,又来一个报错:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="n">error</span><span class="p">[</span><span class="n">E0277</span><span class="p">]:</span><span class="w"> </span><span class="o">`</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="nf">Fn</span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">Box</span><span class="o"><</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static)> + Send + '</span><span class="n">static</span><span class="p">)</span><span class="o">`</span><span class="w"> </span><span class="n">cannot</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">shared</span><span class="w"> </span><span class="k">between</span><span class="w"> </span><span class="n">threads</span><span class="w"> </span><span class="n">safely</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">--></span><span class="w"> </span><span class="n">src</span><span class="err">\</span><span class="n">bin</span><span class="err">\</span><span class="n">attempt1</span><span class="p">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">35</span><span class="p">:</span><span class="mi">35</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">35</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span><span class="p">::</span><span class="nf">spawn</span><span class="p">(</span><span class="n">async</span><span class="w"> </span><span class="n">move</span><span class="w"> </span><span class="err">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">______________________</span><span class="o">------------</span><span class="n">_</span><span class="o">^</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">required</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">bound</span><span class="w"> </span><span class="n">introduced</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="k">call</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">36</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="k">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="k">table</span><span class="p">.</span><span class="k">read</span><span class="p">().</span><span class="n">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">37</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">lock</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="s2">"handler1"</span><span class="p">).</span><span class="nf">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">38</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">handler</span><span class="p">(</span><span class="s2">"req1"</span><span class="p">.</span><span class="k">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">39</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">pinned_fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Box</span><span class="p">::</span><span class="nf">into_pin</span><span class="p">(</span><span class="n">fut</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">40</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">pinned_fut</span><span class="p">.</span><span class="n">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">41</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="err">}</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="n">_________</span><span class="o">^</span><span class="w"> </span><span class="o">`</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="nf">Fn</span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">Box</span><span class="o"><</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static)> + Send + '</span><span class="n">static</span><span class="p">)</span><span class="o">`</span><span class="w"> </span><span class="n">cannot</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">shared</span><span class="w"> </span><span class="k">between</span><span class="w"> </span><span class="n">threads</span><span class="w"> </span><span class="n">safely</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">help</span><span class="p">:</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">trait</span><span class="w"> </span><span class="o">`</span><span class="n">Sync</span><span class="o">`</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="k">not</span><span class="w"> </span><span class="n">implemented</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="o">`</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="nf">Fn</span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">Box</span><span class="o"><</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static)> + Send + '</span><span class="n">static</span><span class="p">)</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">note</span><span class="p">:</span><span class="w"> </span><span class="n">required</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="o">`</span><span class="k">Unique</span><span class="o"><</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="nf">Fn</span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">Box</span><span class="o"><</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static)> + Send + '</span><span class="n">static</span><span class="p">)</span><span class="o">>`</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">implement</span><span class="w"> </span><span class="o">`</span><span class="n">Sync</span><span class="o">`</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>这段代码中 <code>Fn</code> 需要是 <code>Sync</code> 的原因,是我们用了 RwLock,因为存储在 <code>RwLock</code> 内部的 <code>HandlerFn</code> 会在多个线程间通过共享引用(读锁)被并发访问和调用,而通过共享引用调用 <code>Fn</code> trait 的方法要求该类型是 <code>Sync</code>。</p>
<p>一个 <code>Fn</code> 闭包可能捕获了非 <code>Sync</code> 的环境数据(例如 <code>Rc</code> 或 <code>Cell</code>)。<code>Send</code> bound 只保证 trait 对象本身可以跨线程移动,但不能保证通过共享引用并发调用它是安全的。为了保证通过共享引用并发调用是安全的,需要 <code>Sync</code> bound。</p>
<p>如果我们把 RwLock 改成 Mutex,就不需要这个 Sync 了。因为 Mutex 是独占访问的。</p>
<p>因此:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">type</span> <span class="nc">HandlerFn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">>></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="o">></span><span class="p">;</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h3 id="future-必须是-send">Future 必须是 Send</h3>
<p>来看这部分最后一个报错:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="n">error</span><span class="p">:</span><span class="w"> </span><span class="n">future</span><span class="w"> </span><span class="n">cannot</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">sent</span><span class="w"> </span><span class="k">between</span><span class="w"> </span><span class="n">threads</span><span class="w"> </span><span class="n">safely</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">--></span><span class="w"> </span><span class="n">src</span><span class="err">\</span><span class="n">bin</span><span class="err">\</span><span class="n">attempt1</span><span class="p">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">35</span><span class="p">:</span><span class="mi">22</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">35</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span><span class="p">::</span><span class="nf">spawn</span><span class="p">(</span><span class="n">async</span><span class="w"> </span><span class="n">move</span><span class="w"> </span><span class="err">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">______________________</span><span class="o">^</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">36</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="k">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="k">table</span><span class="p">.</span><span class="k">read</span><span class="p">().</span><span class="n">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">37</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">lock</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="s2">"handler1"</span><span class="p">).</span><span class="nf">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">38</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">handler</span><span class="p">(</span><span class="s2">"req1"</span><span class="p">.</span><span class="k">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">39</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">pinned_fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Box</span><span class="p">::</span><span class="nf">into_pin</span><span class="p">(</span><span class="n">fut</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">40</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">pinned_fut</span><span class="p">.</span><span class="n">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">41</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="err">}</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="n">__________</span><span class="o">^</span><span class="w"> </span><span class="n">future</span><span class="w"> </span><span class="n">created</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">async</span><span class="w"> </span><span class="n">block</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="k">not</span><span class="w"> </span><span class="o">`</span><span class="n">Send</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">help</span><span class="p">:</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">trait</span><span class="w"> </span><span class="o">`</span><span class="n">Send</span><span class="o">`</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="k">not</span><span class="w"> </span><span class="n">implemented</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="o">`</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">>`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">note</span><span class="p">:</span><span class="w"> </span><span class="n">future</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="k">not</span><span class="w"> </span><span class="o">`</span><span class="n">Send</span><span class="o">`</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">it</span><span class="w"> </span><span class="n">awaits</span><span class="w"> </span><span class="n">another</span><span class="w"> </span><span class="n">future</span><span class="w"> </span><span class="n">which</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="k">not</span><span class="w"> </span><span class="o">`</span><span class="n">Send</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">--></span><span class="w"> </span><span class="n">src</span><span class="err">\</span><span class="n">bin</span><span class="err">\</span><span class="n">attempt1</span><span class="p">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">40</span><span class="p">:</span><span class="mi">13</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">40</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">pinned_fut</span><span class="p">.</span><span class="n">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">^^^^^^^^^^</span><span class="w"> </span><span class="n">await</span><span class="w"> </span><span class="n">occurs</span><span class="w"> </span><span class="n">here</span><span class="w"> </span><span class="k">on</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">`</span><span class="n">Pin</span><span class="o"><</span><span class="n">Box</span><span class="o"><</span><span class="n">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">String</span><span class="o">>>>`</span><span class="p">,</span><span class="w"> </span><span class="n">which</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="k">not</span><span class="w"> </span><span class="o">`</span><span class="n">Send</span><span class="o">`</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>前面说了,在任务执行过程中,特别是在 <code>.await</code> 点之间,Tokio 运行时可能会将这个任务从一个线程<strong>移动</strong>到另一个线程上继续执行。因此,传递给 <code>tokio::spawn</code> 的 <code>Future</code> 必须是 <code>Send</code> 的,因为 Tokio 运行时需要在其内部的线程池中安全地调度和执行这个 Future,这可能涉及将 Future 的状态在不同的线程之间移动。</p>
<p>所以我们来改一下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">type</span> <span class="nc">HandlerFn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="o">></span><span class="p">;</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>需要注意,我们改了 HandlerFn 之后,别忘了把 add 函数里面 Fun 和 Fut 的声明也给相应改了,不然对不上一样编译不通过:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">impl</span><span class="w"> </span><span class="n">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">key</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span>: <span class="nc">Fun</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">write</span><span class="p">().</span><span class="k">await</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">key</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">|</span><span class="n">s</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="n">s</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="n">fut</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>到目前为止的完整代码:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">pin</span>::<span class="n">Pin</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">sync</span>::<span class="n">Arc</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">time</span>::<span class="n">Duration</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">sync</span>::<span class="n">RwLock</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">time</span>::<span class="n">sleep</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">type</span> <span class="nc">HandlerFn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="o">></span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[derive(Default, Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">table</span>: <span class="nc">Arc</span><span class="o"><</span><span class="n">RwLock</span><span class="o"><</span><span class="n">HashMap</span><span class="o"><</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="n">HandlerFn</span><span class="o">>>></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">key</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span>: <span class="nc">Fun</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">write</span><span class="p">().</span><span class="k">await</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">key</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">|</span><span class="n">s</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="n">s</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="n">fut</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[tokio::main]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">router</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Router</span>::<span class="n">default</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">,</span><span class="w"> </span><span class="n">handler1</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">,</span><span class="w"> </span><span class="n">handler2</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="s">"req1"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">pinned_fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span>::<span class="n">into_pin</span><span class="p">(</span><span class="n">fut</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">pinned_fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="s">"req2"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">pinned_fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span>::<span class="n">into_pin</span><span class="p">(</span><span class="n">fut</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">pinned_fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="fm">join!</span><span class="p">(</span><span class="n">handle1</span><span class="p">,</span><span class="w"> </span><span class="n">handle2</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handler1</span><span class="p">(</span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">sleep</span><span class="p">(</span><span class="n">Duration</span>::<span class="n">from_secs</span><span class="p">(</span><span class="mi">1</span><span class="p">)).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"handler1"</span><span class="p">.</span><span class="n">into</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handler2</span><span class="p">(</span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">sleep</span><span class="p">(</span><span class="n">Duration</span>::<span class="n">from_secs</span><span class="p">(</span><span class="mi">1</span><span class="p">)).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"handler2"</span><span class="p">.</span><span class="n">into</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>终于没有编译错误了,运行试试:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="w"> </span><span class="n">Finished</span><span class="w"> </span><span class="o">`</span><span class="n">dev</span><span class="o">`</span><span class="w"> </span><span class="n">profile</span><span class="w"> </span><span class="p">[</span><span class="n">unoptimized</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">debuginfo</span><span class="p">]</span><span class="w"> </span><span class="nf">target</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="p">.</span><span class="mi">04</span><span class="n">s</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Running</span><span class="w"> </span><span class="o">`</span><span class="n">target</span><span class="err">\</span><span class="n">debug</span><span class="err">\</span><span class="n">attempt1</span><span class="p">.</span><span class="n">exe</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">handler2</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">handler1</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h1 id="把-pinbox包装的-future-放到-hashmap-里">把 Pin<Box>包装的 Future 放到 HashMap 里</h1>
<p>现在我们有这样的代码:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="s">"req1"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">pinned_fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span>::<span class="n">into_pin</span><span class="p">(</span><span class="n">fut</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">pinned_fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="s">"req2"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">pinned_fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span>::<span class="n">into_pin</span><span class="p">(</span><span class="n">fut</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">pinned_fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>我们每次调用 handler 的时候都要把 Future 给 Pin 一下,有点麻烦。所以我们最好把 Pin 的封装这个过程放到 add 函数里。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="c1">// 这里改了返回的 Future 类型
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">type</span> <span class="nc">HandlerFn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Pin</span><span class="o"><</span><span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="o">>></span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="o">></span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[derive(Default, Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">table</span>: <span class="nc">Arc</span><span class="o"><</span><span class="n">RwLock</span><span class="o"><</span><span class="n">HashMap</span><span class="o"><</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="n">HandlerFn</span><span class="o">>>></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">key</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span>: <span class="nc">Fun</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">write</span><span class="p">().</span><span class="k">await</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">key</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">|</span><span class="n">s</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="n">s</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Box</span>::<span class="n">pin</span><span class="p">(</span><span class="n">fut</span><span class="p">)</span><span class="w"> </span><span class="c1">// 这里从 into_pin 改成了 pin
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="p">}),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>这样,我们就可以直接对 HashMap 获取到的 Future 进行 await:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="s">"req1"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">(</span><span class="s">"req2"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h1 id="使用async_trait">使用#[async_trait]</h1>
<p>一直到目前为止我们都是自己封装的,感觉要写一大坨类型和约束,还要操作闭包,特别麻烦,有没有简单一点的办法?</p>
<p>有的,就是使用 async_trait 这个 crate。</p>
<p>Rust 一般是不允许在 trait 里面使用 async 函数的,如果硬要用的话可能会碰到这样的报错:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="n">error</span><span class="p">[</span><span class="n">E0038</span><span class="p">]:</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">trait</span><span class="w"> </span><span class="o">`</span><span class="n">HandlerFn</span><span class="o">`</span><span class="w"> </span><span class="n">cannot</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">made</span><span class="w"> </span><span class="k">into</span><span class="w"> </span><span class="n">an</span><span class="w"> </span><span class="n">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">--></span><span class="w"> </span><span class="n">src</span><span class="err">\</span><span class="n">bin</span><span class="err">\</span><span class="n">attempt2</span><span class="p">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">31</span><span class="p">:</span><span class="mi">9</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">31</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">self</span><span class="p">.</span><span class="k">table</span><span class="p">.</span><span class="k">write</span><span class="p">().</span><span class="n">await</span><span class="p">.</span><span class="k">insert</span><span class="p">(</span><span class="k">key</span><span class="p">.</span><span class="nf">to_string</span><span class="p">(),</span><span class="n">Box</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">handler</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">^^^^^^^^^^^^^^^^^^</span><span class="w"> </span><span class="o">`</span><span class="n">HandlerFn</span><span class="o">`</span><span class="w"> </span><span class="n">cannot</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">made</span><span class="w"> </span><span class="k">into</span><span class="w"> </span><span class="n">an</span><span class="w"> </span><span class="n">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">note</span><span class="p">:</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">trait</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="s2">"dyn-compatible"</span><span class="w"> </span><span class="n">it</span><span class="w"> </span><span class="n">needs</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">allow</span><span class="w"> </span><span class="n">building</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">vtable</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">allow</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">resolvable</span><span class="w"> </span><span class="n">dynamically</span><span class="p">;</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">more</span><span class="w"> </span><span class="n">information</span><span class="w"> </span><span class="n">visit</span><span class="w"> </span><span class="o"><</span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">doc</span><span class="p">.</span><span class="n">rust</span><span class="o">-</span><span class="n">lang</span><span class="p">.</span><span class="n">org</span><span class="o">/</span><span class="n">reference</span><span class="o">/</span><span class="n">items</span><span class="o">/</span><span class="n">traits</span><span class="p">.</span><span class="n">html</span><span class="c1">#object-safety>
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="o">--></span><span class="w"> </span><span class="n">src</span><span class="err">\</span><span class="n">bin</span><span class="err">\</span><span class="n">attempt2</span><span class="p">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">9</span><span class="p">:</span><span class="mi">14</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">8</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">trait</span><span class="w"> </span><span class="n">HandlerFn</span><span class="w"> </span><span class="err">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">-------</span><span class="c1">-- this trait cannot be made into an object...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="mi">9</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">async</span><span class="w"> </span><span class="n">fn</span><span class="w"> </span><span class="nf">handle</span><span class="p">(</span><span class="o">&</span><span class="n">self</span><span class="p">,</span><span class="w"> </span><span class="n">req</span><span class="p">:</span><span class="w"> </span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">String</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">^^^^^^</span><span class="w"> </span><span class="p">...</span><span class="n">because</span><span class="w"> </span><span class="n">method</span><span class="w"> </span><span class="o">`</span><span class="n">handle</span><span class="o">`</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="o">`</span><span class="n">async</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">help</span><span class="p">:</span><span class="w"> </span><span class="n">consider</span><span class="w"> </span><span class="n">moving</span><span class="w"> </span><span class="o">`</span><span class="n">handle</span><span class="o">`</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">another</span><span class="w"> </span><span class="n">trait</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>看这里:<code>this trait cannot be made into an object... because method handle is async</code>。</p>
<p>但这个 crate 可以帮助我们实现这一点。</p>
<p>实际上还是一种语法糖,它帮我们解决了繁琐的封装工作。</p>
<p>请看改过的代码:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="cp">#[async_trait]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">trait</span><span class="w"> </span><span class="n">HandlerFn</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handle</span><span class="p">(</span><span class="o">&</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[async_trait]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">impl</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="w"> </span><span class="n">HandlerFn</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">Fun</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handle</span><span class="p">(</span><span class="o">&</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">(</span><span class="n">req</span><span class="p">).</span><span class="k">await</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[derive(Default, Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">table</span>: <span class="nc">Arc</span><span class="o"><</span><span class="n">RwLock</span><span class="o"><</span><span class="n">HashMap</span><span class="o"><</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="n">HandlerFn</span><span class="o">>>>></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">key</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span>: <span class="nc">Fun</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">table</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="n">write</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="k">await</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">key</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="n">handler</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[tokio::main]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">router</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Router</span>::<span class="n">default</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">,</span><span class="w"> </span><span class="n">handler1</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">,</span><span class="w"> </span><span class="n">handler2</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">.</span><span class="n">handle</span><span class="p">(</span><span class="s">"req1"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">.</span><span class="n">handle</span><span class="p">(</span><span class="s">"req2"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="fm">join!</span><span class="p">(</span><span class="n">handle1</span><span class="p">,</span><span class="w"> </span><span class="n">handle2</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>我们把 HandlerFn 声明为了 async trait,其中有一个 handle 方法</li>
<li>我们为 Fun 函数类型实现了 HandlerFn 这个 trait,里面用 self(req).await 调用了函数自身</li>
<li>现在往 HashMap 里面放的 value 变成了 Box 包装的 HandlerFn 这个特征对象</li>
<li>add 方法改成直接把 Box 包装的 handler 函数 insert 到 HashMap 里</li>
<li>tokio::spawn 里改成了调用拿出来 HandlerFn 特征对象的 handle 函数</li>
</ul>
<p>看看现在的报错:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="n">error</span><span class="p">[</span><span class="n">E0277</span><span class="p">]:</span><span class="w"> </span><span class="o">`</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="n">HandlerFn</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static)` cannot be sent between threads safely
</span></span></span><span class="line"><span class="cl"><span class="s1"> --> src\bin\attempt2.rs:47:35
</span></span></span><span class="line"><span class="cl"><span class="s1"> |
</span></span></span><span class="line"><span class="cl"><span class="s1">47 | let handle = tokio::spawn(async move {
</span></span></span><span class="line"><span class="cl"><span class="s1"> | ______________________------------_^
</span></span></span><span class="line"><span class="cl"><span class="s1"> | | |
</span></span></span><span class="line"><span class="cl"><span class="s1"> | | required by a bound introduced by this call
</span></span></span><span class="line"><span class="cl"><span class="s1">48 | | let lock = router_clone.table.read().await;
</span></span></span><span class="line"><span class="cl"><span class="s1">49 | | let handler = lock.get("handler1").unwrap();
</span></span></span><span class="line"><span class="cl"><span class="s1">50 | | let fut = handler.handle("req1".into());
</span></span></span><span class="line"><span class="cl"><span class="s1">51 | | fut.await;
</span></span></span><span class="line"><span class="cl"><span class="s1">52 | | });
</span></span></span><span class="line"><span class="cl"><span class="s1"> | |_________^ `(dyn HandlerFn + '</span><span class="n">static</span><span class="p">)</span><span class="o">`</span><span class="w"> </span><span class="n">cannot</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">sent</span><span class="w"> </span><span class="k">between</span><span class="w"> </span><span class="n">threads</span><span class="w"> </span><span class="n">safely</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">help</span><span class="p">:</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">trait</span><span class="w"> </span><span class="o">`</span><span class="n">Send</span><span class="o">`</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="k">not</span><span class="w"> </span><span class="n">implemented</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="o">`</span><span class="p">(</span><span class="n">dyn</span><span class="w"> </span><span class="n">HandlerFn</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">'static)`
</span></span></span><span class="line"><span class="cl"><span class="s1"> = note: required for `Unique<(dyn HandlerFn + '</span><span class="n">static</span><span class="p">)</span><span class="o">>`</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">implement</span><span class="w"> </span><span class="o">`</span><span class="n">Send</span><span class="o">`</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>似曾相识吧,原因是现在我们把 Box<dyn xx>给写到 table 这个 HashMap 的类型上面了,然后忘记加 Send 和 Sync 约束了。</p>
<p>改一下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">table</span>: <span class="nc">Arc</span><span class="o"><</span><span class="n">RwLock</span><span class="o"><</span><span class="n">HashMap</span><span class="o"><</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="n">HandlerFn</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="o">>>>></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>现在编译通过了,运行也没问题,这次的完整代码:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span><span class="lnt">75
</span><span class="lnt">76
</span><span class="lnt">77
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">async_trait</span>::<span class="n">async_trait</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">pin</span>::<span class="n">Pin</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">sync</span>::<span class="n">Arc</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">time</span>::<span class="n">Duration</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">sync</span>::<span class="n">RwLock</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">time</span>::<span class="n">sleep</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[async_trait]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">trait</span><span class="w"> </span><span class="n">HandlerFn</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handle</span><span class="p">(</span><span class="o">&</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[async_trait]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">impl</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="w"> </span><span class="n">HandlerFn</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">Fun</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handle</span><span class="p">(</span><span class="o">&</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">(</span><span class="n">req</span><span class="p">).</span><span class="k">await</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[derive(Default, Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">table</span>: <span class="nc">Arc</span><span class="o"><</span><span class="n">RwLock</span><span class="o"><</span><span class="n">HashMap</span><span class="o"><</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="n">HandlerFn</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="o">>>>></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">key</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span>: <span class="nc">Fun</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">table</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="n">write</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="k">await</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">key</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="n">handler</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[tokio::main]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">router</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Router</span>::<span class="n">default</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">,</span><span class="w"> </span><span class="n">handler1</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">,</span><span class="w"> </span><span class="n">handler2</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">.</span><span class="n">handle</span><span class="p">(</span><span class="s">"req1"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">.</span><span class="n">handle</span><span class="p">(</span><span class="s">"req2"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="fm">join!</span><span class="p">(</span><span class="n">handle1</span><span class="p">,</span><span class="w"> </span><span class="n">handle2</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handler1</span><span class="p">(</span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">sleep</span><span class="p">(</span><span class="n">Duration</span>::<span class="n">from_secs</span><span class="p">(</span><span class="mi">1</span><span class="p">)).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"handler1"</span><span class="p">.</span><span class="n">into</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handler2</span><span class="p">(</span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">sleep</span><span class="p">(</span><span class="n">Duration</span>::<span class="n">from_secs</span><span class="p">(</span><span class="mi">1</span><span class="p">)).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"handler2"</span><span class="p">.</span><span class="n">into</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>为啥现在不需要把 Future 给 Pin 起来了?</p>
<p>因为我们用了<code>async_trait</code> 宏,会转换我们的代码,使得 <code>async fn</code> 方法在编译后实际上返回一个<strong>堆分配的、已 Pin 的特征对象</strong>,通常是 <code>Pin<Box<dyn Future + Send + 'life>></code> 这样的类型。非常方便。</p>
<h1 id="提前释放读锁">提前释放读锁</h1>
<p>看下面的代码:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">.</span><span class="n">handle</span><span class="p">(</span><span class="s">"req1"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>lock 会一直持有,直到 fut 的 await 结束,持有时间太长了感觉。</p>
<p>虽然在我们的例子里,HashMap 写入只有在初始化时进行,之后就都是读了。RwLock 支持并发读,所以这样没什么性能问题。</p>
<p>但能修还是修一下吧。</p>
<p>下面看完整代码,其中包含注释:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span><span class="lnt">75
</span><span class="lnt">76
</span><span class="lnt">77
</span><span class="lnt">78
</span><span class="lnt">79
</span><span class="lnt">80
</span><span class="lnt">81
</span><span class="lnt">82
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">async_trait</span>::<span class="n">async_trait</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">pin</span>::<span class="n">Pin</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">sync</span>::<span class="n">Arc</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">time</span>::<span class="n">Duration</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">sync</span>::<span class="n">RwLock</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">time</span>::<span class="n">sleep</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[async_trait]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">trait</span><span class="w"> </span><span class="n">HandlerFn</span>: <span class="nb">Send</span> <span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">'static</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handle</span><span class="p">(</span><span class="o">&</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[async_trait]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">impl</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="w"> </span><span class="n">HandlerFn</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">Fun</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handle</span><span class="p">(</span><span class="o">&</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">(</span><span class="n">req</span><span class="p">).</span><span class="k">await</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// HashMap 的 value 把 Arc 换成了 Box
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">type</span> <span class="nc">RouterTableValue</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Arc</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="n">HandlerFn</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="o">></span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[derive(Default, Clone)]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">table</span>: <span class="nc">Arc</span><span class="o"><</span><span class="n">RwLock</span><span class="o"><</span><span class="n">HashMap</span><span class="o"><</span><span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="n">RouterTableValue</span><span class="o">>>></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Router</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">add</span><span class="o"><</span><span class="n">Fun</span><span class="p">,</span><span class="w"> </span><span class="n">Fut</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">key</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">handler</span>: <span class="nc">Fun</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">where</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fun</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Sync</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">Fn</span><span class="p">(</span><span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Fut</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">Fut</span>: <span class="nb">'static</span> <span class="o">+</span><span class="w"> </span><span class="nb">Send</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Future</span><span class="o"><</span><span class="n">Output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span><span class="o">></span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">table</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="n">write</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="k">await</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">key</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w"> </span><span class="n">Arc</span>::<span class="n">new</span><span class="p">(</span><span class="n">handler</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[tokio::main]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">router</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Router</span>::<span class="n">default</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">,</span><span class="w"> </span><span class="n">handler1</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">,</span><span class="w"> </span><span class="n">handler2</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w"> </span><span class="c1">// clone 一份
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="nb">drop</span><span class="p">(</span><span class="n">lock</span><span class="p">);</span><span class="w"> </span><span class="c1">// 这里释放锁
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler_clone</span><span class="p">.</span><span class="n">handle</span><span class="p">(</span><span class="s">"req1"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">router_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">async</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">lock</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">router_clone</span><span class="p">.</span><span class="n">table</span><span class="p">.</span><span class="n">read</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lock</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">handler_clone</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">drop</span><span class="p">(</span><span class="n">lock</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">fut</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler_clone</span><span class="p">.</span><span class="n">handle</span><span class="p">(</span><span class="s">"req2"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">fut</span><span class="p">.</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">handle</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tokio</span>::<span class="fm">join!</span><span class="p">(</span><span class="n">handle1</span><span class="p">,</span><span class="w"> </span><span class="n">handle2</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handler1</span><span class="p">(</span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">sleep</span><span class="p">(</span><span class="n">Duration</span>::<span class="n">from_secs</span><span class="p">(</span><span class="mi">1</span><span class="p">)).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"handler1"</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"handler1"</span><span class="p">.</span><span class="n">into</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">handler2</span><span class="p">(</span><span class="n">req</span>: <span class="nb">String</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">sleep</span><span class="p">(</span><span class="n">Duration</span>::<span class="n">from_secs</span><span class="p">(</span><span class="mi">1</span><span class="p">)).</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"handler2"</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"handler2"</span><span class="p">.</span><span class="n">into</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>为啥把装 HandlerFn 的 Box 换成 Arc 就行了?</p>
<p>Box 和 Arc 都是智能指针,其中 Box 单纯是为了把数据分配在堆上,而 Arc 还有一个功能就是引用计数。</p>
<p>Arc 在 clone 的时候会给内部 HandlerFn 的引用计数增加 1,然后返回一个完整的拥有所有权的 Arc 对象。</p>
<p>使用<code>lock.get("handler1").unwrap()</code>获取到的东西是<code>&RouterTableValue</code>这个不可变引用。</p>
<p>如果调用在这上面调用<code>handler.clone()</code>的话,当<code>RouterTableValue</code>是不同的东西,效果也不同:</p>
<ul>
<li>如果是 Box,实际上只是把这个不可变引用给 clone 了一份,得到的仍然是和原来一样的<code>&RouterTableValue</code>,仍然持有对 lock 的借用</li>
<li>如果是 Arc,调用的会是 Arc 实现的 clone 方法,获取到的是一个全新的<code>Arc<dyn HandlerFn+Send+Sync></code>,就不持有对 lock 的借用了,所以之后可以安全地 drop 掉 lock</li>
</ul>
<h1 id="总结">总结</h1>
<p>这样一个小小的需求,在 Rust 里实现起来还是挺麻烦的。</p>
<p>还涉及到了很多比较进阶的知识,不太了解的话可能会有点晕。</p>
<p>所以可以和 AI 多多交流,这篇文章写作的过程中,一些解释部分也用了 AI 生成。(Gemini 2.5 Flash 思考模式,目前感觉很强)</p>
<p>如果在 Go 里实现的话,一般也就是写个函数类型,完事,然后读取写入的时候记得加个锁。</p>
<p>不过 Rust 大概正是麻烦,才保证了运行时的安全吧。</p>
<p>这一套编译错误解决下来也感觉学到了不少东西。</p>