Rust入门教程(七).html 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <!DOCTYPE html>
  2. <html lang="en-US">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width,initial-scale=1">
  6. <title>Rust入门教程(七):生命周期 | Rust训练营教程文档</title>
  7. <meta name="generator" content="VuePress 1.9.10">
  8. <link rel="icon" href="/rust_camp_tutorial/logo.png">
  9. <meta name="description" content="DragonOS-Rust camp">
  10. <link rel="preload" href="/rust_camp_tutorial/assets/css/0.styles.7dd9be3e.css" as="style"><link rel="preload" href="/rust_camp_tutorial/assets/js/app.d7ab8f65.js" as="script"><link rel="preload" href="/rust_camp_tutorial/assets/js/2.3dc1b8de.js" as="script"><link rel="preload" href="/rust_camp_tutorial/assets/js/1.7f771cfb.js" as="script"><link rel="preload" href="/rust_camp_tutorial/assets/js/25.df99dd5f.js" as="script"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/10.23a1f579.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/11.c389195a.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/12.1d996921.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/13.4d4410c4.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/14.37ef2a72.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/15.5542c093.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/16.d48fd1ce.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/17.bd8d538c.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/18.6d3b94c1.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/19.eb35cfee.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/20.c11ec329.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/21.db1b5d88.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/22.7714be7b.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/23.7f3a9620.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/24.2f88b37d.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/26.606cfbc8.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/27.928f1e6b.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/28.f61a69ee.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/29.802642cf.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/3.5322f14a.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/30.72f41aed.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/31.e1aa8cbc.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/32.30c1ff3b.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/33.f21667a4.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/4.84e1e480.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/5.f0541060.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/6.dfb06aa0.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/7.7551a9fb.js"><link rel="prefetch" href="/rust_camp_tutorial/assets/js/vendors~docsearch.5e19b665.js">
  11. <link rel="stylesheet" href="/rust_camp_tutorial/assets/css/0.styles.7dd9be3e.css">
  12. </head>
  13. <body>
  14. <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/rust_camp_tutorial/" class="home-link router-link-active"><img src="logo.png" alt="Rust训练营教程文档" class="logo"> <span class="site-name can-hide">Rust训练营教程文档</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/rust_camp_tutorial/" class="nav-link">
  15. 首页
  16. </a></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/rust_camp_tutorial/" class="nav-link">
  17. 首页
  18. </a></div> <!----></nav> <ul class="sidebar-links"><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>Rust入门教程(七):生命周期</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/rust_camp_tutorial/Rust%E6%96%87%E6%A1%A3/Rust%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%83%EF%BC%89.html#生命周期" class="sidebar-link">生命周期</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/rust_camp_tutorial/Rust%E6%96%87%E6%A1%A3/Rust%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%83%EF%BC%89.html#借用检查器" class="sidebar-link">借用检查器</a></li><li class="sidebar-sub-header"><a href="/rust_camp_tutorial/Rust%E6%96%87%E6%A1%A3/Rust%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%83%EF%BC%89.html#函数中的泛型生命周期" class="sidebar-link">函数中的泛型生命周期</a></li><li class="sidebar-sub-header"><a href="/rust_camp_tutorial/Rust%E6%96%87%E6%A1%A3/Rust%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%83%EF%BC%89.html#生命周期标注语法" class="sidebar-link">生命周期标注语法</a></li></ul></li><li><a href="/rust_camp_tutorial/Rust%E6%96%87%E6%A1%A3/Rust%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%83%EF%BC%89.html#深入理解生命周期" class="sidebar-link">深入理解生命周期</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/rust_camp_tutorial/Rust%E6%96%87%E6%A1%A3/Rust%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%83%EF%BC%89.html#struct-定义中的生命周期标注" class="sidebar-link">Struct 定义中的生命周期标注</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/rust_camp_tutorial/Rust%E6%96%87%E6%A1%A3/Rust%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%83%EF%BC%89.html#生命周期的省略" class="sidebar-link">生命周期的省略</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/rust_camp_tutorial/Rust%E6%96%87%E6%A1%A3/Rust%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%83%EF%BC%89.html#输入、输出生命周期" class="sidebar-link">输入、输出生命周期</a></li><li class="sidebar-sub-header"><a href="/rust_camp_tutorial/Rust%E6%96%87%E6%A1%A3/Rust%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%83%EF%BC%89.html#生命周期省略的三个规则" class="sidebar-link">生命周期省略的三个规则</a></li><li class="sidebar-sub-header"><a href="/rust_camp_tutorial/Rust%E6%96%87%E6%A1%A3/Rust%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%83%EF%BC%89.html#方法定义中的生命周期标注" class="sidebar-link">方法定义中的生命周期标注</a></li></ul></li><li><a href="/rust_camp_tutorial/Rust%E6%96%87%E6%A1%A3/Rust%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%83%EF%BC%89.html#静态生命周期" class="sidebar-link">静态生命周期</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/rust_camp_tutorial/Rust%E6%96%87%E6%A1%A3/Rust%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%83%EF%BC%89.html#一个泛型参数类型-trait-bound-和生命周期的综合例子" class="sidebar-link">一个泛型参数类型,Trait Bound 和生命周期的综合例子</a></li></ul></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="rust入门教程-七-生命周期"><a href="#rust入门教程-七-生命周期" class="header-anchor">#</a> Rust入门教程(七):生命周期</h1> <blockquote><p>Rust 生命周期机制是与所有权机制同等重要的资源管理机制。生命周期,简而言之就是引用的有效作用域,之所以引入这个概念主要是应对复杂类型系统中资源管理的问题。引用是对待复杂类型时必不可少的机制,毕竟复杂类型的数据不能被处理器轻易地复制和计算,但引用往往导致极其复杂的资源管理问题。</p></blockquote> <h2 id="生命周期"><a href="#生命周期" class="header-anchor">#</a> 生命周期</h2> <ul><li>Rust 的每个引用都有自己的生命周期</li> <li>生命周期:引用保持有效的作用域</li> <li>大多数情况:生命周期是隐式的、可被推断的</li> <li>当引用的生命周期可能以不同的方式互相关联时:手动标注生命周期</li></ul> <p>生命周期的主要目标:避免悬垂引用(dangling reference)</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">test01</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  19. <span class="token punctuation">{</span>
  20. <span class="token keyword">let</span> r<span class="token punctuation">;</span>
  21. <span class="token punctuation">{</span>
  22. <span class="token keyword">let</span> x <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span>
  23. r <span class="token operator">=</span> <span class="token operator">&amp;</span>x<span class="token punctuation">;</span>
  24. <span class="token punctuation">}</span>
  25. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;{}&quot;</span><span class="token punctuation">,</span> r<span class="token punctuation">)</span><span class="token punctuation">;</span>
  26. <span class="token punctuation">}</span>
  27. <span class="token punctuation">}</span>
  28. </code></pre></div><p>上面这段代码会在 <code>r = &amp;x;</code> 处报错,因为当打印 <code>r</code> 的值的时候,<code>x</code> 已经离开了他的作用域,这时 <code>r</code> 指向的 <code>x</code> 的内存已经被释放,因此会报错。</p> <p>Rust 实际上是通过<strong>借用检查器</strong>来检查一些变量的生命周期。</p> <h3 id="借用检查器"><a href="#借用检查器" class="header-anchor">#</a> 借用检查器</h3> <p>Rust 编译器的借用检查器(borrow checker),用来比较作用域来判断所有的借用是否合法</p> <p>在上例中,借用检查器检测到 <code>r</code> 的生命周期大于 <code>x</code>,即被引用者的生命周期小于引用者的生命周期,因此编译会报错。</p> <h3 id="函数中的泛型生命周期"><a href="#函数中的泛型生命周期" class="header-anchor">#</a> 函数中的泛型生命周期</h3> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">test02</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  29. <span class="token keyword">let</span> string1 <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">&quot;Congratulations&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  30. <span class="token keyword">let</span> string2 <span class="token operator">=</span> <span class="token string">&quot;fantastic&quot;</span><span class="token punctuation">;</span>
  31. <span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token function">longest</span><span class="token punctuation">(</span>string1<span class="token punctuation">.</span><span class="token function">as_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> string2<span class="token punctuation">)</span><span class="token punctuation">;</span>
  32. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;The longest string is {}&quot;</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
  33. <span class="token punctuation">}</span>
  34. <span class="token keyword">fn</span> <span class="token function-definition function">longest</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token operator">&amp;</span><span class="token keyword">str</span> <span class="token punctuation">{</span>
  35. <span class="token keyword">if</span> x<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> y<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  36. x
  37. <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
  38. y
  39. <span class="token punctuation">}</span>
  40. <span class="token punctuation">}</span>
  41. </code></pre></div><p>编译报错:</p> <div class="language-rust extra-class"><pre class="language-rust"><code>➜ ~<span class="token operator">/</span><span class="token class-name">Code</span><span class="token operator">/</span>rust<span class="token operator">/</span>life_cycle git<span class="token punctuation">:</span><span class="token punctuation">(</span>master<span class="token punctuation">)</span> ✗ cargo run
  42. <span class="token class-name">Compiling</span> life_cycle v0<span class="token number">.1</span><span class="token punctuation">.</span><span class="token number">0</span> <span class="token punctuation">(</span><span class="token operator">/</span>home<span class="token operator">/</span>cherry<span class="token operator">/</span><span class="token class-name">Code</span><span class="token operator">/</span>rust<span class="token operator">/</span>life_cycle<span class="token punctuation">)</span>
  43. error<span class="token punctuation">[</span><span class="token constant">E0106</span><span class="token punctuation">]</span><span class="token punctuation">:</span> missing lifetime specifier
  44. <span class="token operator">-</span><span class="token punctuation">-&gt;</span> src<span class="token operator">/</span>main<span class="token punctuation">.</span>rs<span class="token punctuation">:</span><span class="token number">24</span><span class="token punctuation">:</span><span class="token number">33</span>
  45. <span class="token operator">|</span>
  46. <span class="token number">24</span> <span class="token operator">|</span> <span class="token keyword">fn</span> <span class="token function-definition function">longest</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token operator">&amp;</span><span class="token keyword">str</span> <span class="token punctuation">{</span>
  47. <span class="token operator">|</span> <span class="token operator">-</span><span class="token operator">-</span><span class="token operator">-</span><span class="token operator">-</span> <span class="token operator">-</span><span class="token operator">-</span><span class="token operator">-</span><span class="token operator">-</span> <span class="token operator">^</span> expected named lifetime parameter
  48. <span class="token operator">|</span>
  49. <span class="token operator">=</span> help<span class="token punctuation">:</span> this function<span class="token lifetime-annotation symbol">'s</span> <span class="token keyword">return</span> <span class="token keyword">type</span> <span class="token type-definition class-name">contains</span> a borrowed value<span class="token punctuation">,</span> but the signature does not say whether it is borrowed from `x` or `y`
  50. help<span class="token punctuation">:</span> consider introducing a named lifetime parameter
  51. <span class="token operator">|</span>
  52. <span class="token number">24</span> <span class="token operator">|</span> <span class="token keyword">fn</span> <span class="token function-definition function">longest</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span> <span class="token punctuation">{</span>
  53. <span class="token operator">|</span> <span class="token operator">+</span><span class="token operator">+</span><span class="token operator">+</span><span class="token operator">+</span> <span class="token operator">+</span><span class="token operator">+</span> <span class="token operator">+</span><span class="token operator">+</span> <span class="token operator">+</span><span class="token operator">+</span>
  54. <span class="token class-name">For</span> more information about this error<span class="token punctuation">,</span> <span class="token keyword">try</span> `rustc <span class="token operator">-</span><span class="token operator">-</span>explain <span class="token constant">E0106</span>`<span class="token punctuation">.</span>
  55. </code></pre></div><p>我们发现编译器会提示<strong>缺少一个命名的生命周期参数</strong>,这个函数返回一个借用的值,但是没有声明这个借用的值是来自 <code>x</code> 还是来自 <code>y</code>。值得说明的是,这个返回值的借用跟函数体的逻辑没有关系,要从函数签名就要看出返回值借用的值来自哪一个参数。</p> <p>根据编译器提示,我们声明一个泛型生命周期 <code>'a</code>,代码修改如下:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">longest</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span> <span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span> <span class="token punctuation">{</span>
  56. <span class="token keyword">if</span> x<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> y<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  57. x
  58. <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
  59. y
  60. <span class="token punctuation">}</span>
  61. <span class="token punctuation">}</span>
  62. </code></pre></div><h3 id="生命周期标注语法"><a href="#生命周期标注语法" class="header-anchor">#</a> 生命周期标注语法</h3> <ul><li>生命周期的标注不会改变引用的生命周期长度</li> <li>当指定了泛型生命周期参数,函数可以接收带有任何生命周期的引用</li> <li>生命周期的标注:描述了多个引用的生命周期间的关系,但不影响生命周期</li></ul> <p>生命周期参数名语法如下:</p> <ul><li>以 <code>'</code> 开头</li> <li>通常全小写且非常短</li> <li>习惯以 <code>'a</code> 表示</li></ul> <p>生命周期标注的位置:</p> <ul><li>在引用符号 <code>&amp;</code> 后面标注</li> <li>使用空格将标注和引用类型区分开</li></ul> <p>生命周期标注的例子:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token operator">&amp;</span><span class="token keyword">i32</span> <span class="token comment">// 一个引用</span>
  63. <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">i32</span> <span class="token comment">// 带有显式生命周期的引用</span>
  64. <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">mut</span> <span class="token keyword">i32</span> <span class="token comment">// 带有显式生命周期的可变引用</span>
  65. </code></pre></div><p>值得注意的是,单个生命周期标注本身没有意义,我们再看上面的 <code>longest</code> 函数:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">longest</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span> <span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span> <span class="token punctuation">{</span>
  66. <span class="token keyword">if</span> x<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> y<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  67. x
  68. <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
  69. y
  70. <span class="token punctuation">}</span>
  71. <span class="token punctuation">}</span>
  72. </code></pre></div><p>泛型的生命周期参数声明在函数名和参数列表之间的 <code>&lt;&gt;</code> 中。</p> <p>我们仔细分析这个函数:</p> <p><code>longest</code> 函数的两个参数都声明了生命周期,就要求这两个引用必须和泛型的生命周期存活相同的时间,而且函数所返回的字符串切片的存活时长也不能小于 <code>'a</code> 这个生命周期。为引用指明生命周期,是要确保当引用失去了所有权后而被移出内存。当在函数参数中指明生命周期时,我们并没有改变参数和返回值的生命周期,只是向调用检查器指出了一些可用于检查非法调用的约束。而 <code>longest</code> 函数本身并不需要知道参数 <code>x</code> 和 <code>y</code> 具体的存活时长,只需要某个可以代替 <code>'a</code> 的作用域,同时满足函数的签名约束。实际上,若函数引用其外部的代码或者被外部代码引用,只靠 rust 本身确定参数和返回值的生命周期时不可能的,这样的话,函数所使用的生命周期在每次调用中都会发生变化,正因为如此,我们才需要手动对生命周期进行标注。</p> <p>当我们将两个引用传入函数时,<code>x</code> 和 <code>y</code> 作用域重叠的部分将用来代替 <code>'a</code> 这个生命周期的作用域,换句话说,这个泛型生命周期得到的具体的生命周期就是 <code>x</code> 和 <code>y</code> 两者生命周期较短的那个,因为返回值也标注了相同的生命周期,因此返回值的引用在两者比较短的生命周期内都是有效的。</p> <p>那么生命周期标注是如何对 <code>longest</code> 函数进行限制的?我么修改一下代码:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">test02</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  73. <span class="token keyword">let</span> string1 <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">&quot;Congratulations&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  74. <span class="token punctuation">{</span>
  75. <span class="token keyword">let</span> string2 <span class="token operator">=</span> <span class="token string">&quot;fantastic&quot;</span><span class="token punctuation">;</span>
  76. <span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token function">longest</span><span class="token punctuation">(</span>string1<span class="token punctuation">.</span><span class="token function">as_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> string2<span class="token punctuation">)</span><span class="token punctuation">;</span>
  77. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;The longest string is {}&quot;</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
  78. <span class="token punctuation">}</span>
  79. <span class="token punctuation">}</span>
  80. <span class="token keyword">fn</span> <span class="token function-definition function">longest</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token operator">&amp;</span><span class="token keyword">str</span> <span class="token punctuation">{</span>
  81. <span class="token keyword">if</span> x<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> y<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  82. x
  83. <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
  84. y
  85. <span class="token punctuation">}</span>
  86. <span class="token punctuation">}</span>
  87. </code></pre></div><p>将 string1 下面三行代码放到一个单独的作用域里,string2 是一个字符串字面值(字符串切片),他的生命周期相当于是一个静态的生命周期,在整个程序运行期间都存活,而 result 引用也会在 Line 7 大括号结束之前保持有效,因此代码不会报错。</p> <p>【注】:<code>&amp;str</code> 是直接在可执行文件中加载的,即这块内存直接放到可执行文件里面的,所以整个程序运行期间,这块内存比较特殊,不会由于所有权而消失,所以指这块内存的引用,一定会一直指向一个合法内存,所以其引用的生命周期是 <code>'static</code>,也就是全局静态,也不可能出现什么悬垂引用。</p> <p>再改一下代码,将 result 声明放到外面,然后将 print 也放到外面,将 string2 改成 String 类型:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">test02</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  88. <span class="token keyword">let</span> string1 <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">&quot;Congratulations&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  89. <span class="token keyword">let</span> result<span class="token punctuation">;</span>
  90. <span class="token punctuation">{</span>
  91. <span class="token keyword">let</span> string2 <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">&quot;fantastic&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  92. result <span class="token operator">=</span> <span class="token function">longest</span><span class="token punctuation">(</span>string1<span class="token punctuation">.</span><span class="token function">as_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> string2<span class="token punctuation">.</span><span class="token function">as_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  93. <span class="token punctuation">}</span>
  94. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;The longest string is {}&quot;</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
  95. <span class="token punctuation">}</span>
  96. </code></pre></div><p>我们发现 Line 6 报错了。string1 的生命周期为 Line 2~9,string2 的生命周期为 Line 5~7,所以 <code>'a</code> 所表示的生命周期为 Line 5~7,而 result 的生命周期为 Line 3~9,不在 <code>'a</code> 的范围内,因此编译报错,我们来看一下编译具体的错误:</p> <div class="language-rust extra-class"><pre class="language-rust"><code>➜ ~<span class="token operator">/</span><span class="token class-name">Code</span><span class="token operator">/</span>rust<span class="token operator">/</span>life_cycle git<span class="token punctuation">:</span><span class="token punctuation">(</span>master<span class="token punctuation">)</span> ✗ cargo run
  97. <span class="token class-name">Compiling</span> life_cycle v0<span class="token number">.1</span><span class="token punctuation">.</span><span class="token number">0</span> <span class="token punctuation">(</span><span class="token operator">/</span>home<span class="token operator">/</span>cherry<span class="token operator">/</span><span class="token class-name">Code</span><span class="token operator">/</span>rust<span class="token operator">/</span>life_cycle<span class="token punctuation">)</span>
  98. error<span class="token punctuation">[</span><span class="token constant">E0597</span><span class="token punctuation">]</span><span class="token punctuation">:</span> `string2` does not live long enough
  99. <span class="token operator">-</span><span class="token punctuation">-&gt;</span> src<span class="token operator">/</span>main<span class="token punctuation">.</span>rs<span class="token punctuation">:</span><span class="token number">30</span><span class="token punctuation">:</span><span class="token number">44</span>
  100. <span class="token operator">|</span>
  101. <span class="token number">30</span> <span class="token operator">|</span> result <span class="token operator">=</span> <span class="token function">longest</span><span class="token punctuation">(</span>string1<span class="token punctuation">.</span><span class="token function">as_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> string2<span class="token punctuation">.</span><span class="token function">as_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  102. <span class="token operator">|</span> <span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span><span class="token operator">^</span> borrowed value does not live long enough
  103. <span class="token number">31</span> <span class="token operator">|</span> <span class="token punctuation">}</span>
  104. <span class="token operator">|</span> <span class="token operator">-</span> `string2` dropped here <span class="token keyword">while</span> still borrowed
  105. <span class="token number">32</span> <span class="token operator">|</span> <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;The longest string is {}&quot;</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
  106. <span class="token operator">|</span> <span class="token operator">-</span><span class="token operator">-</span><span class="token operator">-</span><span class="token operator">-</span><span class="token operator">-</span><span class="token operator">-</span> borrow later used here
  107. <span class="token class-name">For</span> more information about this error<span class="token punctuation">,</span> <span class="token keyword">try</span> `rustc <span class="token operator">-</span><span class="token operator">-</span>explain <span class="token constant">E0597</span>`<span class="token punctuation">.</span>
  108. error<span class="token punctuation">:</span> could not compile `life_cycle` due to previous error
  109. </code></pre></div><p>这个报错的含义是,为了让 result 这个变量在打印时是有效的,那么 string2 必须在外部作用域结束之前一直保持有效,因为在函数声明中参数和返回值都使用了相同的生命周期。</p> <p>在上例中,尽管 string1 的长度大于 string2 的长度,函数返回的是 string1 的引用,但是编译器并不知道这一点,编译器只知道 <code>longest</code> 函数返回引用的生命周期是 <code>x</code> 和 <code>y</code> 生命周期比较短的那个。</p> <h2 id="深入理解生命周期"><a href="#深入理解生命周期" class="header-anchor">#</a> 深入理解生命周期</h2> <ul><li>指定生命周期参数的方式依赖于函数所做的事情,在上面的例子中,若 <code>longest</code> 函数改为:</li></ul> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">longest</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token operator">&amp;</span><span class="token keyword">str</span> <span class="token punctuation">{</span>
  110. x
  111. <span class="token punctuation">}</span>
  112. </code></pre></div><p>这个时候,函数只返回变量 <code>x</code>,而与 <code>y</code> 无关,因此无需为 <code>y</code> 指定生命周期。</p> <ul><li>从函数返回引用时,返回类型的生命周期参数需要与其中一个参数的生命周期匹配</li> <li>如果返回的引用没有指向任何参数,那么他只能引用函数内创建的值
  113. <ul><li>这就是<strong>悬垂引用</strong>,该值在函数结束时就走出了作用域,见下面的例子</li></ul></li></ul> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">test02</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  114. <span class="token keyword">let</span> string1 <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">&quot;Congratulations&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  115. <span class="token keyword">let</span> string2 <span class="token operator">=</span> <span class="token string">&quot;fantastic&quot;</span><span class="token punctuation">;</span>
  116. <span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token function">longest</span><span class="token punctuation">(</span>string1<span class="token punctuation">.</span><span class="token function">as_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> string2<span class="token punctuation">)</span><span class="token punctuation">;</span>
  117. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;The longest string is {}&quot;</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
  118. <span class="token punctuation">}</span>
  119. <span class="token keyword">fn</span> <span class="token function-definition function">longest</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span> <span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span> <span class="token punctuation">{</span>
  120. <span class="token keyword">let</span> res <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">&quot;abc&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  121. res<span class="token punctuation">.</span><span class="token function">as_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  122. <span class="token punctuation">}</span>
  123. </code></pre></div><p>上面的代码中,<code>longest</code> 函数中返回了局部变量 <code>res</code>,当函数执行完毕时,局部变量 <code>res</code> 所指向的内存已经被释放掉,因此 <code>test02</code> 中的 <code>result</code> 变量指向的 <code>res</code> 内存已经被清理,这就造成了<strong>悬垂引用</strong>,非常类似于 <code>C/C++</code> 的野指针。</p> <p>那么我就是想返回函数中的局部变量,应该怎么办呢?解决办法也很简单,就是直接返回这个值而不是返回引用,这样就将变量的所有权移交出去了,如下所示:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">longest</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span> <span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">String</span> <span class="token punctuation">{</span>
  124. <span class="token keyword">let</span> res <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">&quot;abc&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  125. res
  126. <span class="token punctuation">}</span>
  127. </code></pre></div><p><strong>因此从根本上讲,生命周期这种语法规则,是用来关联函数的不同参数及返回值之间的生命周期,一旦他们取得了某种联系,rust 就会获得足够的信息来支持保证内存安全的操作,并且阻止那些可能会导致悬垂指针或者其他违反内存安全的行为。</strong></p> <h2 id="struct-定义中的生命周期标注"><a href="#struct-定义中的生命周期标注" class="header-anchor">#</a> Struct 定义中的生命周期标注</h2> <p>struct 里可以包括:</p> <ul><li>自持有类型(类似于 i32 等)</li> <li>引用:需要在每个引用上添加生命周期标注</li></ul> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">struct</span> <span class="token type-definition class-name">ImportantExcerpt</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
  128. part<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">,</span>
  129. <span class="token punctuation">}</span>
  130. <span class="token keyword">fn</span> <span class="token function-definition function">test04</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  131. <span class="token keyword">let</span> novel <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">&quot;Today is Tuesday. And I will take part in a meeting.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  132. <span class="token keyword">let</span> first_sentence <span class="token operator">=</span> novel<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">&quot;.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">expect</span><span class="token punctuation">(</span><span class="token string">&quot;Can't find a '.'&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  133. <span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token class-name">ImportantExcerpt</span> <span class="token punctuation">{</span>
  134. part<span class="token punctuation">:</span> first_sentence<span class="token punctuation">,</span>
  135. <span class="token punctuation">}</span><span class="token punctuation">;</span>
  136. <span class="token punctuation">}</span>
  137. </code></pre></div><h2 id="生命周期的省略"><a href="#生命周期的省略" class="header-anchor">#</a> 生命周期的省略</h2> <p>每个引用都有生命周期,需要为使用生命周期的函数或 struct 指定生命周期参数</p> <p>但是下面这个例子,没有任何生命周期的标注,仍然可以通过编译:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">first_word</span><span class="token punctuation">(</span>s<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token operator">&amp;</span><span class="token keyword">str</span> <span class="token punctuation">{</span>
  138. <span class="token keyword">let</span> byte <span class="token operator">=</span> s<span class="token punctuation">.</span><span class="token function">as_bytes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  139. <span class="token keyword">for</span> <span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token operator">&amp;</span>item<span class="token punctuation">)</span> <span class="token keyword">in</span> byte<span class="token punctuation">.</span><span class="token function">iter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">enumerate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  140. <span class="token keyword">if</span> item <span class="token operator">==</span> <span class="token char">b' '</span> <span class="token punctuation">{</span>
  141. <span class="token keyword">return</span> <span class="token operator">&amp;</span>s<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">..</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
  142. <span class="token punctuation">}</span>
  143. <span class="token punctuation">}</span>
  144. <span class="token operator">&amp;</span>s<span class="token punctuation">[</span><span class="token punctuation">..</span><span class="token punctuation">]</span>
  145. <span class="token punctuation">}</span>
  146. </code></pre></div><p>按照原来的 rust 规范,函数声明、参数和返回类型前都是要加上生命周期标注的,但是 rust 团队发现程序员总是一遍又一遍地标注同样的生命周期,而且这些场景是可以预测的,有着明确的模式,因此 rust 团队就将这些模式写入了编译器,使得借用检查器可以自动对这些模式进行推导而无需显式标注。</p> <p><strong>生命周期省略规则</strong></p> <ul><li>在 Rust 引用分析中所编入的模式称为<strong>生命周期省略规则</strong> <ul><li>这些规则无需开发者来遵守</li> <li>它们是一些特殊情况,由编译器来考虑</li> <li>如果你的代码符合这些情况,那么就无需显式标注生命周期</li></ul></li> <li>生命周期省略规则不会提供完整的推断:
  147. <ul><li>如果应用规则后,引用的生命周期仍然模糊不清→编译错误</li> <li>解决办法:添加生命周期标注,表明引用间的相互关系</li></ul></li></ul> <h3 id="输入、输出生命周期"><a href="#输入、输出生命周期" class="header-anchor">#</a> 输入、输出生命周期</h3> <p>生命周期在:</p> <ul><li>函数/方法的参数中,叫做输入生命周期</li> <li>函数/方法的返回值中,叫输出生命周期</li></ul> <h3 id="生命周期省略的三个规则"><a href="#生命周期省略的三个规则" class="header-anchor">#</a> 生命周期省略的三个规则</h3> <p>编译器使用三个规则在没有显式标注生命周期的情况下,来确定引用的生命周期</p> <ul><li>规则 1 应用于输入生命周期</li> <li>规则 2、3 应用于输出生命周期</li> <li>如果编译器应用完三个规则后,仍然无法确定有效的生命周期,则报错</li> <li>这些规则适用于 fn 和 impl 块</li></ul> <p><strong>规则 1:</strong> 每个引用类型都有自己的生命周期
  148. <strong>规则 2:</strong> 如果只有 1 个输入生命周期参数,那么该生命周期被赋给所有输出生命周期参数
  149. <strong>规则 3:</strong> 如果有多个输入生命周期参数,但其中一个是 <code>&amp;self</code> 或 <code>&amp;mut self</code>,那么 <code>self</code> 的生命周期会被赋给所有的输出生命周期参数</p> <p><strong>生命周期省略的三个规则-例子</strong></p> <p>假设我们是编译器:</p> <p><code>fn first_word(s: &amp;str) -&gt; &amp;str {}</code> <code>fn first_word&lt;'a&gt;(s: &amp;'a str) -&gt; &amp;str {}</code> <code>fn first_word&lt;'a&gt;(s: &amp;'a str) -&gt; &amp;'a str {}</code></p> <p><code>fn longest(x: &amp;str, y: &amp;str) -&gt; &amp;str {}</code> <code>fn longest&lt;'a, 'b&gt;(x: &amp;'a str, y: &amp;'b str) -&gt; &amp;str {}</code></p> <h3 id="方法定义中的生命周期标注"><a href="#方法定义中的生命周期标注" class="header-anchor">#</a> 方法定义中的生命周期标注</h3> <ul><li>在 struct 上使用生命周期实现方法,语法和泛型参数的语法一样</li> <li>在哪声明和使用生命周期参数,依赖于:
  150. <ul><li>生命周期参数是否和字段、方法的参数或返回值有关</li></ul></li> <li>struct 字段的生命周期名:
  151. <ul><li>在 impl 后声明</li> <li>在 struct 名后使用</li> <li>这些生命周期是 struct 类型的一部分</li></ul></li> <li>impl 块内的方法签名中
  152. <ul><li>引用必须绑定于 struct 字段引用的生命周期,或者引用是独立的也可以</li> <li>生命周期省略规则经常使得方法中的生命周期标注不是必须的</li></ul></li></ul> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">struct</span> <span class="token type-definition class-name">ImportantExcerpt</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
  153. part<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">,</span>
  154. <span class="token punctuation">}</span>
  155. <span class="token keyword">impl</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span> <span class="token class-name">ImportantExcerpt</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
  156. <span class="token keyword">fn</span> <span class="token function-definition function">level</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">u32</span> <span class="token punctuation">{</span>
  157. <span class="token number">3</span>
  158. <span class="token punctuation">}</span>
  159. <span class="token keyword">fn</span> <span class="token function-definition function">printSome</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">,</span> words<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token operator">&amp;</span><span class="token keyword">str</span> <span class="token punctuation">{</span>
  160. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;There are some words: {}&quot;</span><span class="token punctuation">,</span> <span class="token keyword">self</span><span class="token punctuation">.</span>part<span class="token punctuation">)</span><span class="token punctuation">;</span>
  161. <span class="token keyword">self</span><span class="token punctuation">.</span>part
  162. <span class="token punctuation">}</span>
  163. <span class="token punctuation">}</span>
  164. </code></pre></div><h2 id="静态生命周期"><a href="#静态生命周期" class="header-anchor">#</a> 静态生命周期</h2> <ul><li><code>'static</code> 是一个特殊的生命周期:整个程序的持续时间
  165. <ul><li>例如:所有的字符串字面值都拥有 <code>'static</code> 生命周期
  166. <ul><li><code>let s: &amp;'static str = &quot;I have a static lifetime.&quot;;</code></li> <li>字符串字面值是存在二进制程序中,总是可用</li></ul></li></ul></li> <li>为引用指定 <code>'static</code> 之前要三思
  167. <ul><li>是否需要引用在整个生命周期内都存活</li></ul></li></ul> <h3 id="一个泛型参数类型-trait-bound-和生命周期的综合例子"><a href="#一个泛型参数类型-trait-bound-和生命周期的综合例子" class="header-anchor">#</a> 一个泛型参数类型,Trait Bound 和生命周期的综合例子</h3> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>fmt<span class="token punctuation">::</span></span><span class="token class-name">Display</span><span class="token punctuation">;</span>
  168. <span class="token keyword">fn</span> <span class="token function-definition function">longest_with_an</span> announcement<span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token punctuation">,</span><span class="token class-name">T</span><span class="token operator">&gt;</span>
  169. <span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span><span class="token punctuation">,</span> ann<span class="token punctuation">:</span> <span class="token class-name">T</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token lifetime-annotation symbol">'a</span> <span class="token keyword">str</span>
  170. <span class="token keyword">where</span>
  171. <span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token class-name">Display</span><span class="token punctuation">,</span>
  172. <span class="token punctuation">{</span>
  173. <span class="token macro property">println!</span> <span class="token punctuation">(</span><span class="token string">&quot;Announcement! {}&quot;</span><span class="token punctuation">,</span> ann<span class="token punctuation">)</span><span class="token punctuation">;</span>
  174. <span class="token keyword">if</span> x<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> y<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  175. x
  176. <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
  177. y
  178. <span class="token punctuation">}</span>
  179. <span class="token punctuation">}</span>
  180. </code></pre></div><p><strong>要注意的是,生命周期也是泛型的一种。</strong></p></div> <footer class="page-edit"><!----> <!----></footer> <!----> </main></div><div class="global-ui"></div></div>
  181. <script src="/rust_camp_tutorial/assets/js/app.d7ab8f65.js" defer></script><script src="/rust_camp_tutorial/assets/js/2.3dc1b8de.js" defer></script><script src="/rust_camp_tutorial/assets/js/1.7f771cfb.js" defer></script><script src="/rust_camp_tutorial/assets/js/25.df99dd5f.js" defer></script>
  182. </body>
  183. </html>