Rust入门教程(二).html 76 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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/28.f61a69ee.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/25.df99dd5f.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/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%BA%8C%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%BA%8C%EF%BC%89.html#_1-定义和实例化-struct" class="sidebar-link">1. 定义和实例化 struct</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%BA%8C%EF%BC%89.html#_2-struct-例子" class="sidebar-link">2. struct 例子</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%BA%8C%EF%BC%89.html#_3-struct-方法" class="sidebar-link">3. struct 方法</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%BA%8C%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%BA%8C%EF%BC%89.html#_1-枚举的定义" class="sidebar-link">1. 枚举的定义</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%BA%8C%EF%BC%89.html#_2-option-枚举" class="sidebar-link">2. Option 枚举</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%BA%8C%EF%BC%89.html#_3-match" class="sidebar-link">3. match</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%BA%8C%EF%BC%89.html#_4-if-let" class="sidebar-link">4. if let</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> <h2 id="一、结构体的使用"><a href="#一、结构体的使用" class="header-anchor">#</a> 一、结构体的使用</h2> <h3 id="_1-定义和实例化-struct"><a href="#_1-定义和实例化-struct" class="header-anchor">#</a> 1. 定义和实例化 struct</h3> <p>例子:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">struct</span> <span class="token type-definition class-name">User</span> <span class="token punctuation">{</span>
  19. username<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span>
  20. email<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span>
  21. sign_in_count<span class="token punctuation">:</span> <span class="token keyword">usize</span><span class="token punctuation">,</span>
  22. active<span class="token punctuation">:</span> <span class="token keyword">bool</span><span class="token punctuation">,</span>
  23. <span class="token punctuation">}</span>
  24. </code></pre></div><p>需要注意的是,每个字段后面用逗号隔开,最后一个字段后面可以没有逗号。</p> <p>实例化例子:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> user1 <span class="token operator">=</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>
  25. email<span class="token punctuation">:</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;[email protected]&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  26. username<span class="token punctuation">:</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;cherry&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  27. active<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  28. sign_in_count<span class="token punctuation">:</span> <span class="token number">244</span><span class="token punctuation">,</span>
  29. <span class="token punctuation">}</span><span class="token punctuation">;</span>
  30. </code></pre></div><p>先创建 struct 实例,然后为每个字段指定值,无需按照声明的顺序指定。</p> <p>但是注意不能少指定字段。</p> <p>用点标记法取得结构体中的字段值,一旦 struct 的实例是可变的,那么实例中的所有字段都是可变的,不会同时既存在可变的字段又存在不可变的字段。</p> <p><strong>结构体作为函数的返回值</strong></p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">struct_build</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>
  31. <span class="token class-name">User</span> <span class="token punctuation">{</span>
  32. email<span class="token punctuation">:</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;[email protected]&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  33. username<span class="token punctuation">:</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;cherry&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  34. active<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  35. sign_in_count<span class="token punctuation">:</span> <span class="token number">244</span><span class="token punctuation">,</span>
  36. <span class="token punctuation">}</span>
  37. <span class="token punctuation">}</span>
  38. </code></pre></div><p><strong>字段初始化简写</strong></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">struct_build</span><span class="token punctuation">(</span>email<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> username<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>
  39. <span class="token class-name">User</span> <span class="token punctuation">{</span>
  40. email<span class="token punctuation">,</span>
  41. username<span class="token punctuation">,</span>
  42. active<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  43. sign_in_count<span class="token punctuation">:</span> <span class="token number">244</span><span class="token punctuation">,</span>
  44. <span class="token punctuation">}</span>
  45. <span class="token punctuation">}</span>
  46. </code></pre></div><p><strong>struct 更新语法</strong></p> <p>当想基于某个 struct 实例创建一个新的实例时(新的实例中某些字段可能和原先相同,某些不同),若不使用 struct 更新语法,则是这样写:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> user2 <span class="token operator">=</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>
  47. email<span class="token punctuation">:</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;[email protected]&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  48. username<span class="token punctuation">:</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;Chris Paul&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  49. active<span class="token punctuation">:</span> user1<span class="token punctuation">.</span>active<span class="token punctuation">,</span>
  50. sign_in_count<span class="token punctuation">:</span> user1<span class="token punctuation">.</span>sign_in_count<span class="token punctuation">,</span>
  51. <span class="token punctuation">}</span><span class="token punctuation">;</span>
  52. </code></pre></div><p>而使用 struct 更新语法,则是这样写:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">let</span> user3 <span class="token operator">=</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>
  53. email<span class="token punctuation">:</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;[email protected]&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  54. username<span class="token punctuation">:</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;Chris Paul&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  55. <span class="token punctuation">..</span>user1
  56. <span class="token punctuation">}</span><span class="token punctuation">;</span>
  57. </code></pre></div><p>用 <code>..user1</code> 表示该实例中未赋值的其他字段和实例 <code>user1</code> 中的值一致。</p> <p><strong>Tuple Struct</strong></p> <p>可以定义类似 Tuple 的 Struct,叫做 Tuple Struct。Tuple struct 整体有个名,但里面的元素没有名</p> <p>适用:想给整个 tuple 起名,并让它不同于其它 tuple,而且又不需要给每个元素起名</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">struct</span> <span class="token type-definition class-name">Color</span><span class="token punctuation">(</span><span class="token keyword">i32</span><span class="token punctuation">,</span> <span class="token keyword">i32</span><span class="token punctuation">,</span> <span class="token keyword">i32</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  58. <span class="token keyword">struct</span> <span class="token type-definition class-name">Point</span><span class="token punctuation">(</span><span class="token keyword">i32</span><span class="token punctuation">,</span> <span class="token keyword">i32</span><span class="token punctuation">,</span> <span class="token keyword">i32</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  59. <span class="token keyword">let</span> <span class="token function">black</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  60. <span class="token keyword">let</span> origin <span class="token operator">=</span> <span class="token class-name">Point</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  61. </code></pre></div><p>black 和 origin 是不同的类型,是不同 tuple struct 的实例</p> <p><strong>Unit-Like Struct(没有任何字段)</strong></p> <p>可以定义没有任何字段的 struct,叫做 <code>Unit-Like struct</code>,因为与 <code>()</code> 和单元类型类似,适用于需要在某个类型上实现某个trait,但是在里面又没有想要存储的数据</p> <p><strong>struct 数据所有权</strong></p> <p>再来看这个例子:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">struct</span> <span class="token type-definition class-name">User</span> <span class="token punctuation">{</span>
  62. username<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span>
  63. email<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span>
  64. sign_in_count<span class="token punctuation">:</span> <span class="token keyword">usize</span><span class="token punctuation">,</span>
  65. active<span class="token punctuation">:</span> <span class="token keyword">bool</span><span class="token punctuation">,</span>
  66. <span class="token punctuation">}</span>
  67. </code></pre></div><p>这里的字段使用了 <code>String</code> 而不是 <code>&amp;str</code>,原因如下:</p> <ul><li>该 struct 实例拥有其所有的数据</li> <li>只要 struct 实例是有效的,那么里面的字段数据也是有效的 struct 里也可以存放引用,但这需要使用生命周期(以后讲)</li> <li>若字段为 <code>&amp;str</code>,当其有效作用域小于该实例的作用域,该字段被清理时,实例未清理,访问该字段属于悬垂引用(类似野指针)</li> <li>生命周期保证只要 struct 实例是有效的,那么里面的引用也是有效的</li> <li>如果 struct 里面存储引用,而不使用生命周期,就会报错</li></ul> <h3 id="_2-struct-例子"><a href="#_2-struct-例子" class="header-anchor">#</a> 2. struct 例子</h3> <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">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  68. <span class="token keyword">let</span> width <span class="token operator">=</span> <span class="token number">25</span><span class="token punctuation">;</span>
  69. <span class="token keyword">let</span> length <span class="token operator">=</span> <span class="token number">12</span><span class="token punctuation">;</span>
  70. <span class="token keyword">let</span> area <span class="token operator">=</span> <span class="token function">area_of_rectangle</span><span class="token punctuation">(</span>width<span class="token punctuation">,</span> length<span class="token punctuation">)</span><span class="token punctuation">;</span>
  71. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;The Area of Rectangle is {}.&quot;</span><span class="token punctuation">,</span> area<span class="token punctuation">)</span><span class="token punctuation">;</span>
  72. <span class="token punctuation">}</span>
  73. <span class="token keyword">fn</span> <span class="token function-definition function">area_of_rectangle</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token keyword">usize</span><span class="token punctuation">,</span> length<span class="token punctuation">:</span> <span class="token keyword">usize</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">usize</span> <span class="token punctuation">{</span>
  74. width <span class="token operator">*</span> length
  75. <span class="token punctuation">}</span>
  76. </code></pre></div><p>上面这个例子很简单,但是长方形的长和宽没有联系起来,width 和 length 是两个分离的没有逻辑联系的变量,我们考虑用元组将其联系起来:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  77. <span class="token keyword">let</span> rect <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  78. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;The Area of Rectangle is {}.&quot;</span><span class="token punctuation">,</span> <span class="token function">area_of_rectangle</span><span class="token punctuation">(</span>rect<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  79. <span class="token punctuation">}</span>
  80. <span class="token keyword">fn</span> <span class="token function-definition function">area_of_rectangle</span><span class="token punctuation">(</span>rect<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token keyword">u32</span><span class="token punctuation">,</span> <span class="token keyword">u32</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">u32</span> <span class="token punctuation">{</span>
  81. rect<span class="token number">.0</span> <span class="token operator">*</span> rect<span class="token number">.1</span>
  82. <span class="token punctuation">}</span>
  83. </code></pre></div><p>但是这样仿佛可读性变差了,我们再用结构体实现:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">struct</span> <span class="token type-definition class-name">Rectangle</span> <span class="token punctuation">{</span>
  84. width<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
  85. length<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
  86. <span class="token punctuation">}</span>
  87. <span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  88. <span class="token keyword">let</span> rect <span class="token operator">=</span> <span class="token class-name">Rectangle</span> <span class="token punctuation">{</span>
  89. width<span class="token punctuation">:</span> <span class="token number">35</span><span class="token punctuation">,</span>
  90. length<span class="token punctuation">:</span> <span class="token number">12</span><span class="token punctuation">,</span>
  91. <span class="token punctuation">}</span><span class="token punctuation">;</span>
  92. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;The Area of Rectangle is {}.&quot;</span><span class="token punctuation">,</span> <span class="token function">area_of_rectangle</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>rect<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 keyword">fn</span> <span class="token function-definition function">area_of_rectangle</span><span class="token punctuation">(</span>rect<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">Rectangle</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">u32</span> <span class="token punctuation">{</span>
  95. rect<span class="token punctuation">.</span>length <span class="token operator">*</span> rect<span class="token punctuation">.</span>width
  96. <span class="token punctuation">}</span>
  97. </code></pre></div><p>函数的参数使用结构体的借用,是为了不获得该实例的所有权,主函数在函数调用之后还可以继续使用该实例。</p> <p>此时我们输出实例 <code>rect</code>,会报这样的错误:<code>Rectangle doesn't implement std::fmt::Display</code>,即该结构体未实现 <code>Display</code> 这个 trait,而 Rust 中很多类型都是实现了这个 trait,才能将其在终端打印出来。因为结构体这种比标量类型更加复杂,打印的类型的可能性很多,因此需要用户自定义实现 <code>Display</code>。</p> <p>在报错的提示信息里,有个 note 提示我们可以使用 <code>{:?}</code> (或 <code>{:#?}</code>)来打印信息:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;{:?}&quot;</span><span class="token punctuation">,</span> rect<span class="token punctuation">)</span><span class="token punctuation">;</span>
  98. </code></pre></div><p>然而又出现了错误,这次的报错信息是:<code>Rectangle doesn't implement Debug</code>,显然 <code>Debug</code> 也是一种格式化方法,再看提示的 note:<code>add #[derive(Debug)] to Rectangle or manually impl Debug for Rectangle</code>,我们在结构体前添加 <code>#[derive(Debug)]</code>,使得该结构体派生与 <code>Debug</code> 这个 trait。</p> <p>最终完整的程序如下:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token attribute attr-name">#[derive(Debug)]</span>
  99. <span class="token keyword">struct</span> <span class="token type-definition class-name">Rectangle</span> <span class="token punctuation">{</span>
  100. width<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
  101. length<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
  102. <span class="token punctuation">}</span>
  103. <span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  104. <span class="token keyword">let</span> rect <span class="token operator">=</span> <span class="token class-name">Rectangle</span> <span class="token punctuation">{</span>
  105. width<span class="token punctuation">:</span> <span class="token number">35</span><span class="token punctuation">,</span>
  106. length<span class="token punctuation">:</span> <span class="token number">12</span><span class="token punctuation">,</span>
  107. <span class="token punctuation">}</span><span class="token punctuation">;</span>
  108. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;The Area of Rectangle is {}.&quot;</span><span class="token punctuation">,</span> <span class="token function">area_of_rectangle</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>rect<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  109. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;{:?}&quot;</span><span class="token punctuation">,</span> rect<span class="token punctuation">)</span><span class="token punctuation">;</span>
  110. <span class="token punctuation">}</span>
  111. <span class="token keyword">fn</span> <span class="token function-definition function">area_of_rectangle</span><span class="token punctuation">(</span>rect<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">Rectangle</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">u32</span> <span class="token punctuation">{</span>
  112. rect<span class="token punctuation">.</span>length <span class="token operator">*</span> rect<span class="token punctuation">.</span>width
  113. <span class="token punctuation">}</span>
  114. </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>area_of_rectangle git<span class="token punctuation">:</span><span class="token punctuation">(</span>master<span class="token punctuation">)</span> ✗ cargo run
  115. <span class="token class-name">Compiling</span> area_of_rectangle 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>area_of_rectangle<span class="token punctuation">)</span>
  116. <span class="token class-name">Finished</span> dev <span class="token punctuation">[</span>unoptimized <span class="token operator">+</span> debuginfo<span class="token punctuation">]</span> <span class="token function">target</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span> <span class="token keyword">in</span> <span class="token number">0</span><span class="token punctuation">.</span>25s
  117. <span class="token class-name">Running</span> `target<span class="token operator">/</span>debug<span class="token operator">/</span>area_of_rectangle`
  118. <span class="token class-name">The</span> <span class="token class-name">Area</span> of <span class="token class-name">Rectangle</span> is <span class="token number">420</span><span class="token punctuation">.</span>
  119. <span class="token class-name">Rectangle</span> <span class="token punctuation">{</span> width<span class="token punctuation">:</span> <span class="token number">35</span><span class="token punctuation">,</span> length<span class="token punctuation">:</span> <span class="token number">12</span> <span class="token punctuation">}</span>
  120. </code></pre></div><p>若在输出格式中间加入一个 <code>#</code>,结构体输出将更加清晰:<code>println!(&quot;{:?}&quot;, rect);</code>,输出结果为:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token class-name">Rectangle</span> <span class="token punctuation">{</span>
  121. width<span class="token punctuation">:</span> <span class="token number">35</span><span class="token punctuation">,</span>
  122. length<span class="token punctuation">:</span> <span class="token number">12</span><span class="token punctuation">,</span>
  123. <span class="token punctuation">}</span>
  124. </code></pre></div><h3 id="_3-struct-方法"><a href="#_3-struct-方法" class="header-anchor">#</a> 3. struct 方法</h3> <p>方法和函数类似: fn关键字、名称、参数、返回值</p> <p>方法与函数不同之处:</p> <ul><li>方法是在 struct(或 enum、trait 对象)的上下文中定义</li> <li>第一个参数是 self,表示方法被调用的 struct 实例</li></ul> <p>上一节我们定义了计算长方形面积的函数,但是该函数只能计算长方形的函数,无法计算其他形状的面积,因此我们希望将函数与长方形这一结构体关联起来,例子如下:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">struct</span> <span class="token type-definition class-name">Rectangle</span> <span class="token punctuation">{</span>
  125. width<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
  126. length<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
  127. <span class="token punctuation">}</span>
  128. <span class="token keyword">impl</span> <span class="token class-name">Rectangle</span> <span class="token punctuation">{</span>
  129. <span class="token keyword">fn</span> <span class="token function-definition function">area_of_rectangle</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>
  130. <span class="token keyword">self</span><span class="token punctuation">.</span>length <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>width
  131. <span class="token punctuation">}</span>
  132. <span class="token punctuation">}</span>
  133. <span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  134. <span class="token keyword">let</span> rect <span class="token operator">=</span> <span class="token class-name">Rectangle</span> <span class="token punctuation">{</span>
  135. width<span class="token punctuation">:</span> <span class="token number">35</span><span class="token punctuation">,</span>
  136. length<span class="token punctuation">:</span> <span class="token number">12</span><span class="token punctuation">,</span>
  137. <span class="token punctuation">}</span><span class="token punctuation">;</span>
  138. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;The Area of Rectangle is {}.&quot;</span><span class="token punctuation">,</span> rect<span class="token punctuation">.</span><span class="token function">area_of_rectangle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  139. <span class="token punctuation">}</span>
  140. </code></pre></div><p>在impl块里定义方法,方法的第一个参数可以是 <code>&amp;self</code>,也可以<strong>获得其所有权</strong>或<strong>可变借用</strong>,和其他参数一样。这样写可以有更良好的代码组织。</p> <p><strong>方法调用的运算符</strong></p> <ul><li>C/C++ 中 <code>object-&gt;something()</code> 和 <code>(*object).something()</code> 一样,但是 Rust 没有 <code>→</code> 运算符</li> <li>Rust 会自动引用或解引用一在调用方法时就会发生这种行为</li> <li>在调用方法时,Rust 根据情况自动添加 <code>&amp;</code>、<code>&amp;mut</code> 或 <code>*</code>,以便 object 可以匹配方法的签名</li> <li>下面这两种写法效果相同
  141. <ul><li><code>p1.distance(&amp;p2);</code></li> <li><code>(&amp;p1).distance(&amp;p2);</code></li></ul></li></ul> <p><strong>方法参数</strong></p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">impl</span> <span class="token class-name">Rectangle</span> <span class="token punctuation">{</span>
  142. <span class="token keyword">fn</span> <span class="token function-definition function">area_of_rectangle</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>
  143. <span class="token keyword">self</span><span class="token punctuation">.</span>length <span class="token operator">*</span> <span class="token keyword">self</span><span class="token punctuation">.</span>width
  144. <span class="token punctuation">}</span>
  145. <span class="token keyword">fn</span> <span class="token function-definition function">can_hold</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">self</span><span class="token punctuation">,</span> other<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">Rectangle</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">bool</span> <span class="token punctuation">{</span>
  146. <span class="token keyword">self</span><span class="token punctuation">.</span>length <span class="token operator">&gt;</span> other<span class="token punctuation">.</span>length <span class="token operator">&amp;&amp;</span> <span class="token keyword">self</span><span class="token punctuation">.</span>width <span class="token operator">&gt;</span> other<span class="token punctuation">.</span>width
  147. <span class="token punctuation">}</span>
  148. <span class="token punctuation">}</span>
  149. </code></pre></div><p><strong>关联函数</strong></p> <p>可以在 impl 块里定义不把 self 作为第一个参数的函数,它们叫关联函数(不叫方法)</p> <p>例如:<code>String::from()</code></p> <p>关联函数通常用于构造器,例子如下:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">struct</span> <span class="token type-definition class-name">Rectangle</span> <span class="token punctuation">{</span>
  150. width<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
  151. length<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span>
  152. <span class="token punctuation">}</span>
  153. <span class="token keyword">impl</span> <span class="token class-name">Rectangle</span> <span class="token punctuation">{</span>
  154. <span class="token keyword">fn</span> <span class="token function-definition function">square</span><span class="token punctuation">(</span>size<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Rectangle</span> <span class="token punctuation">{</span>
  155. <span class="token class-name">Rectangle</span> <span class="token punctuation">{</span>
  156. width<span class="token punctuation">:</span> size<span class="token punctuation">,</span>
  157. length<span class="token punctuation">:</span> size<span class="token punctuation">,</span>
  158. <span class="token punctuation">}</span>
  159. <span class="token punctuation">}</span>
  160. <span class="token punctuation">}</span>
  161. <span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  162. <span class="token keyword">let</span> s <span class="token operator">=</span> <span class="token class-name">Rectangle</span><span class="token punctuation">::</span><span class="token function">square</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  163. <span class="token punctuation">}</span>
  164. </code></pre></div><p><code>::</code> 符号</p> <ul><li>关联函数</li> <li>模块创建的命名空间</li></ul> <h2 id="二、枚举与模式匹配"><a href="#二、枚举与模式匹配" class="header-anchor">#</a> 二、枚举与模式匹配</h2> <h3 id="_1-枚举的定义"><a href="#_1-枚举的定义" class="header-anchor">#</a> 1. 枚举的定义</h3> <p>枚举允许我们列举所有可能的类型来定义一个类型</p> <p>例如 IP 地址,目前只有 IPv4 和 IPv6 两种类型,我们可以定义这样的枚举类型并使用:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">enum</span> <span class="token type-definition class-name">IpAddrKind</span> <span class="token punctuation">{</span>
  165. <span class="token constant">V4</span><span class="token punctuation">,</span>
  166. <span class="token constant">V6</span><span class="token punctuation">,</span>
  167. <span class="token punctuation">}</span>
  168. <span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  169. <span class="token keyword">let</span> four <span class="token operator">=</span> <span class="token class-name">IpAddrKind</span><span class="token punctuation">::</span><span class="token constant">V4</span><span class="token punctuation">;</span>
  170. <span class="token keyword">let</span> six <span class="token operator">=</span> <span class="token class-name">IpAddrKind</span><span class="token punctuation">::</span><span class="token constant">V6</span><span class="token punctuation">;</span>
  171. <span class="token function">route</span><span class="token punctuation">(</span>four<span class="token punctuation">)</span><span class="token punctuation">;</span>
  172. <span class="token function">route</span><span class="token punctuation">(</span>six<span class="token punctuation">)</span><span class="token punctuation">;</span>
  173. <span class="token function">route</span><span class="token punctuation">(</span><span class="token class-name">IpAddrKind</span><span class="token punctuation">::</span><span class="token constant">V6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  174. <span class="token punctuation">}</span>
  175. <span class="token keyword">fn</span> <span class="token function-definition function">route</span><span class="token punctuation">(</span>ip_kind<span class="token punctuation">:</span> <span class="token class-name">IpAddrKind</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  176. </code></pre></div><p>枚举的变体都位于标识符的命名空间下,使用两个冒号 <code>::</code> 进行分隔</p> <p>枚举类型是一种自定义的类型,因此它可以作为结构体里字段的类型,例子如下:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">enum</span> <span class="token type-definition class-name">IpAddrKind</span> <span class="token punctuation">{</span>
  177. <span class="token constant">V4</span><span class="token punctuation">,</span>
  178. <span class="token constant">V6</span><span class="token punctuation">,</span>
  179. <span class="token punctuation">}</span>
  180. <span class="token keyword">struct</span> <span class="token type-definition class-name">IpAddr</span> <span class="token punctuation">{</span>
  181. kind<span class="token punctuation">:</span> <span class="token class-name">IpAddrKind</span><span class="token punctuation">,</span>
  182. address<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span>
  183. <span class="token punctuation">}</span>
  184. <span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  185. <span class="token keyword">let</span> home <span class="token operator">=</span> <span class="token class-name">IpAddr</span> <span class="token punctuation">{</span>
  186. kind<span class="token punctuation">:</span> <span class="token class-name">IpAddrKind</span><span class="token punctuation">::</span><span class="token constant">V4</span><span class="token punctuation">,</span>
  187. address<span class="token punctuation">:</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;192.168.3.1&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  188. <span class="token punctuation">}</span><span class="token punctuation">;</span>
  189. <span class="token punctuation">}</span>
  190. </code></pre></div><p><strong>将数据附加到枚举的变体中</strong></p> <p>上述的枚举类型我们可以改为:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">enum</span> <span class="token type-definition class-name">IpAddr</span> <span class="token punctuation">{</span>
  191. <span class="token constant">V4</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  192. <span class="token constant">V6</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  193. <span class="token punctuation">}</span>
  194. </code></pre></div><p>优点是:不需要使用 struct,<strong>每个变体可以拥有不同的类型以及相关联的数据量</strong>,例如</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">enum</span> <span class="token type-definition class-name">IpAddr</span> <span class="token punctuation">{</span>
  195. <span class="token constant">V4</span><span class="token punctuation">(</span><span class="token keyword">u8</span><span class="token punctuation">,</span> <span class="token keyword">u8</span><span class="token punctuation">,</span> <span class="token keyword">u8</span><span class="token punctuation">,</span> <span class="token keyword">u8</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  196. <span class="token constant">V6</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  197. <span class="token punctuation">}</span>
  198. <span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  199. <span class="token keyword">let</span> home <span class="token operator">=</span> <span class="token class-name">IpAddrKind</span><span class="token punctuation">::</span><span class="token constant">V4</span><span class="token punctuation">(</span><span class="token number">192</span><span class="token punctuation">,</span> <span class="token number">168</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  200. <span class="token keyword">let</span> loopback <span class="token operator">=</span> <span class="token class-name">IpAddrKind</span><span class="token punctuation">::</span><span class="token constant">V6</span><span class="token punctuation">(</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;::1&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  201. <span class="token punctuation">}</span>
  202. </code></pre></div><p><strong>标准库中的 IpAddr</strong></p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">struct</span> <span class="token type-definition class-name">lpv4Addr</span> <span class="token punctuation">{</span>
  203. <span class="token comment">// --snip--</span>
  204. <span class="token punctuation">}</span>
  205. <span class="token keyword">struct</span> <span class="token type-definition class-name">lpv6Addr</span> <span class="token punctuation">{</span>
  206. <span class="token comment">// --snip--</span>
  207. <span class="token punctuation">}</span>
  208. <span class="token keyword">enum</span> <span class="token type-definition class-name">lpAddr</span> <span class="token punctuation">{</span>
  209. <span class="token constant">V4</span><span class="token punctuation">(</span>lpv4Addr<span class="token punctuation">)</span><span class="token punctuation">,</span>
  210. <span class="token constant">V6</span><span class="token punctuation">(</span>lpv6Addr<span class="token punctuation">)</span><span class="token punctuation">,</span>
  211. <span class="token punctuation">}</span>
  212. </code></pre></div><p><strong>为枚举定义方法</strong></p> <p>也使用 <code>impl</code> 这个关键字</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">enum</span> <span class="token type-definition class-name">Message</span> <span class="token punctuation">{</span>
  213. <span class="token class-name">Quit</span><span class="token punctuation">,</span>
  214. <span class="token class-name">Move</span> <span class="token punctuation">{</span>x<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token keyword">u32</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
  215. <span class="token class-name">Write</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  216. <span class="token class-name">ChangeColor</span><span class="token punctuation">(</span><span class="token keyword">i32</span><span class="token punctuation">,</span> <span class="token keyword">i32</span><span class="token punctuation">,</span> <span class="token keyword">i32</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  217. <span class="token punctuation">}</span>
  218. <span class="token keyword">impl</span> <span class="token class-name">Message</span> <span class="token punctuation">{</span>
  219. <span class="token keyword">fn</span> <span class="token function-definition function">call</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">{</span><span class="token punctuation">}</span>
  220. <span class="token punctuation">}</span>
  221. <span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  222. <span class="token keyword">let</span> q <span class="token operator">=</span> <span class="token class-name">Message</span><span class="token punctuation">::</span><span class="token class-name">Quit</span><span class="token punctuation">;</span>
  223. <span class="token keyword">let</span> m <span class="token operator">=</span> <span class="token class-name">Message</span><span class="token punctuation">::</span><span class="token class-name">Move</span><span class="token punctuation">{</span>x<span class="token punctuation">:</span> <span class="token number">10</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token number">12</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
  224. <span class="token keyword">let</span> w <span class="token operator">=</span> <span class="token class-name">Message</span><span class="token punctuation">::</span><span class="token class-name">Write</span><span class="token punctuation">(</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;Hello&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  225. <span class="token keyword">let</span> c <span class="token operator">=</span> <span class="token class-name">Message</span><span class="token punctuation">::</span><span class="token class-name">ChangeColor</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  226. <span class="token punctuation">}</span>
  227. </code></pre></div><h3 id="_2-option-枚举"><a href="#_2-option-枚举" class="header-anchor">#</a> 2. Option 枚举</h3> <ul><li>定义于标准库中</li> <li>在 Prelude(预导入模块)中</li> <li>描述了某个值可能存在(某种类型)或不存在的情况</li></ul> <p><strong>Rust 中没有 NULL</strong></p> <p>其它语言中:</p> <ul><li>Null是一个值,它表示“没有值”</li> <li>一个变量可以处于两种状态:空值(null)、非空</li> <li>Null 引用:Billion Dollar Mistake</li></ul> <p>Null 的问题在于:当你尝试像使用非Null值那样使用Null值的时候,就会引起某种错误,但是 Null 的概念还是有用的:<strong>因某种原因而变为无效或缺失的值</strong></p> <p>Rust 中类似与 NULL 的概念的枚举:<code>Option&lt;T&gt;</code></p> <p>标准库中的定义:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">enum</span> <span class="token type-definition class-name">Option</span><span class="token operator">&lt;</span><span class="token class-name">T</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
  228. <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token class-name">T</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  229. <span class="token class-name">None</span><span class="token punctuation">,</span>
  230. <span class="token punctuation">}</span>
  231. </code></pre></div><p>它包含在预导入模块(Prelude)中,可以直接使用 <code>Option&lt;T&gt;</code>, <code>Some(T)</code>, <code>None</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">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  232. <span class="token keyword">let</span> some_num <span class="token operator">=</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  233. <span class="token keyword">let</span> some_string <span class="token operator">=</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token string">&quot;The String&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  234. <span class="token keyword">let</span> absent_num<span class="token punctuation">:</span> <span class="token class-name">Option</span><span class="token operator">&lt;</span><span class="token keyword">i32</span><span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token class-name">None</span><span class="token punctuation">;</span>
  235. <span class="token punctuation">}</span>
  236. </code></pre></div><p>其中 <code>Some(3)</code> 编译器可以推断出来 <code>T</code> 类型为 <code>usize</code>,而 <code>None</code> 的话编译器无法推断出来,因此需要显式指定 <code>Option&lt;i32&gt;</code></p> <p>这种设计比 NULL 好在哪?</p> <p>因为 <code>Option&lt;T&gt;</code> 和 <code>T</code> 是不同的类型,不能将 <code>Option&lt;T&gt;</code> 当成 <code>T</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>
  237. <span class="token keyword">let</span> x<span class="token punctuation">:</span> <span class="token keyword">i8</span> <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span>
  238. <span class="token keyword">let</span> y<span class="token punctuation">:</span> <span class="token class-name">Option</span><span class="token operator">&lt;</span><span class="token keyword">i8</span><span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  239. <span class="token keyword">let</span> sum <span class="token operator">=</span> x <span class="token operator">+</span> y<span class="token punctuation">;</span>
  240. <span class="token punctuation">}</span>
  241. </code></pre></div><p>这样会报错,提示 <code>cannot add Option&lt;i8&gt; to i8</code>,表示两者不是同一个类型,若想使用 <code>Option&lt;T&gt;</code> 中的 <code>T</code>,则必须将其手动转换为 <code>T</code>,这种设计方式可以避免代码中 NULL 值泛滥的情况。</p> <h3 id="_3-match"><a href="#_3-match" class="header-anchor">#</a> 3. match</h3> <p><strong>强大的控制流运算符 match</strong></p> <p>允许一个值与一系列模式进行匹配,并执行匹配的模式对应的代码。模式可以是字面值、变量名、通配符...</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">enum</span> <span class="token type-definition class-name">Coin</span> <span class="token punctuation">{</span>
  242. <span class="token class-name">Penny</span><span class="token punctuation">,</span>
  243. <span class="token class-name">Nickel</span><span class="token punctuation">,</span>
  244. <span class="token class-name">Dime</span><span class="token punctuation">,</span>
  245. <span class="token class-name">Quarter</span><span class="token punctuation">,</span>
  246. <span class="token punctuation">}</span>
  247. <span class="token keyword">fn</span> <span class="token function-definition function">value_in_cents</span><span class="token punctuation">(</span>coin<span class="token punctuation">:</span> <span class="token class-name">Coin</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">u8</span> <span class="token punctuation">{</span>
  248. <span class="token keyword">match</span> coin <span class="token punctuation">{</span>
  249. <span class="token class-name">Coin</span><span class="token punctuation">::</span><span class="token class-name">Penny</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  250. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;Penny!&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  251. <span class="token number">1</span>
  252. <span class="token punctuation">}</span><span class="token punctuation">,</span>
  253. <span class="token class-name">Coin</span><span class="token punctuation">::</span><span class="token class-name">Nickel</span> <span class="token operator">=&gt;</span> <span class="token number">5</span><span class="token punctuation">,</span>
  254. <span class="token class-name">Coin</span><span class="token punctuation">::</span><span class="token class-name">Dime</span> <span class="token operator">=&gt;</span> <span class="token number">10</span><span class="token punctuation">,</span>
  255. <span class="token class-name">Coin</span><span class="token punctuation">::</span><span class="token class-name">Quarter</span> <span class="token operator">=&gt;</span> <span class="token number">25</span><span class="token punctuation">,</span>
  256. <span class="token punctuation">}</span>
  257. <span class="token punctuation">}</span>
  258. </code></pre></div><p><strong>绑定值的模式</strong></p> <p>匹配的分支可以绑定到被匹配对象的部分值,因此可以从 enum 变体中提取值,例子如下:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token attribute attr-name">#[derive(Debug)]</span>
  259. <span class="token keyword">enum</span> <span class="token type-definition class-name">USState</span> <span class="token punctuation">{</span>
  260. <span class="token class-name">California</span><span class="token punctuation">,</span>
  261. <span class="token class-name">Texas</span><span class="token punctuation">,</span>
  262. <span class="token punctuation">}</span>
  263. <span class="token keyword">enum</span> <span class="token type-definition class-name">Coin</span> <span class="token punctuation">{</span>
  264. <span class="token class-name">Penny</span><span class="token punctuation">,</span>
  265. <span class="token class-name">Nickel</span><span class="token punctuation">,</span>
  266. <span class="token class-name">Dime</span><span class="token punctuation">,</span>
  267. <span class="token class-name">Quarter</span><span class="token punctuation">(</span><span class="token class-name">USState</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  268. <span class="token punctuation">}</span>
  269. <span class="token keyword">fn</span> <span class="token function-definition function">value_in_cents</span><span class="token punctuation">(</span>coin<span class="token punctuation">:</span> <span class="token class-name">Coin</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token keyword">u8</span> <span class="token punctuation">{</span>
  270. <span class="token keyword">match</span> coin <span class="token punctuation">{</span>
  271. <span class="token class-name">Coin</span><span class="token punctuation">::</span><span class="token class-name">Penny</span> <span class="token operator">=&gt;</span> <span class="token number">1</span><span class="token punctuation">,</span>
  272. <span class="token class-name">Coin</span><span class="token punctuation">::</span><span class="token class-name">Nickel</span> <span class="token operator">=&gt;</span> <span class="token number">5</span><span class="token punctuation">,</span>
  273. <span class="token class-name">Coin</span><span class="token punctuation">::</span><span class="token class-name">Dime</span> <span class="token operator">=&gt;</span> <span class="token number">10</span><span class="token punctuation">,</span>
  274. <span class="token class-name">Coin</span><span class="token punctuation">::</span><span class="token class-name">Quarter</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  275. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;State quarter from {:?}&quot;</span><span class="token punctuation">,</span> state<span class="token punctuation">)</span><span class="token punctuation">;</span>
  276. <span class="token number">25</span>
  277. <span class="token punctuation">}</span><span class="token punctuation">,</span>
  278. <span class="token comment">/* Coin::Quarter(state) 也可以这样展开写 */</span>
  279. <span class="token class-name">Coin</span><span class="token punctuation">::</span><span class="token class-name">Quarter</span><span class="token punctuation">(</span><span class="token class-name">USState</span><span class="token punctuation">::</span><span class="token class-name">Texas</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  280. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;State quarter from {:?}&quot;</span><span class="token punctuation">,</span> <span class="token class-name">USState</span><span class="token punctuation">::</span><span class="token class-name">Texas</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  281. <span class="token number">25</span>
  282. <span class="token punctuation">}</span><span class="token punctuation">,</span>
  283. <span class="token class-name">Coin</span><span class="token punctuation">::</span><span class="token class-name">Quarter</span><span class="token punctuation">(</span><span class="token class-name">USState</span><span class="token punctuation">::</span><span class="token class-name">California</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  284. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;State quarter from {:?}&quot;</span><span class="token punctuation">,</span> <span class="token class-name">USState</span><span class="token punctuation">::</span><span class="token class-name">California</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  285. <span class="token number">25</span>
  286. <span class="token punctuation">}</span>
  287. <span class="token punctuation">}</span>
  288. <span class="token punctuation">}</span>
  289. <span class="token keyword">fn</span> <span class="token function-definition function">test03</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  290. <span class="token keyword">let</span> c <span class="token operator">=</span> <span class="token class-name">Coin</span><span class="token punctuation">::</span><span class="token class-name">Quarter</span><span class="token punctuation">(</span><span class="token class-name">USState</span><span class="token punctuation">::</span><span class="token class-name">California</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  291. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;{}&quot;</span><span class="token punctuation">,</span> <span class="token function">value_in_cents</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  292. <span class="token punctuation">}</span>
  293. </code></pre></div><p><strong>匹配 Option<T></T></strong></p> <div class="language-rust extra-class"><pre class="language-rust"><code><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>
  294. <span class="token keyword">let</span> five <span class="token operator">=</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  295. <span class="token keyword">let</span> six <span class="token operator">=</span> <span class="token function">plus_one</span><span class="token punctuation">(</span>five<span class="token punctuation">)</span><span class="token punctuation">;</span>
  296. <span class="token keyword">let</span> none <span class="token operator">=</span> <span class="token function">plus_one</span><span class="token punctuation">(</span><span class="token class-name">None</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  297. <span class="token punctuation">}</span>
  298. <span class="token keyword">fn</span> <span class="token function-definition function">plus_one</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token class-name">Option</span><span class="token operator">&lt;</span><span class="token keyword">i32</span><span class="token operator">&gt;</span><span class="token punctuation">)</span> <span class="token punctuation">-&gt;</span> <span class="token class-name">Option</span><span class="token operator">&lt;</span><span class="token keyword">i32</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
  299. <span class="token keyword">match</span> x <span class="token punctuation">{</span>
  300. <span class="token class-name">None</span> <span class="token operator">=&gt;</span> <span class="token class-name">None</span><span class="token punctuation">,</span>
  301. <span class="token class-name">Some</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token class-name">Some</span><span class="token punctuation">(</span>i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span>
  302. <span class="token punctuation">}</span>
  303. <span class="token punctuation">}</span>
  304. </code></pre></div><p>注意:match 匹配必须穷举所有的可能,可以使用 <code>_</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">test05</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  305. <span class="token keyword">let</span> x <span class="token operator">=</span> <span class="token number">0u8</span><span class="token punctuation">;</span>
  306. <span class="token keyword">match</span> x <span class="token punctuation">{</span>
  307. <span class="token number">1</span> <span class="token operator">=&gt;</span> <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;one&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  308. <span class="token number">3</span> <span class="token operator">=&gt;</span> <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;three&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  309. <span class="token number">5</span> <span class="token operator">=&gt;</span> <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;five&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  310. _ <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">)</span>
  311. <span class="token punctuation">}</span>
  312. <span class="token punctuation">}</span>
  313. </code></pre></div><h3 id="_4-if-let"><a href="#_4-if-let" class="header-anchor">#</a> 4. if let</h3> <p><code>if let</code> 是一种比 <code>match</code> 简单的控制流,他处理只关心一种匹配而忽略其他匹配的情况,它有更少的代码,更少的缩进,更少的模板代码,但是放弃了穷举的可能,可以把 <code>if let</code> 看作是 <code>match</code> 的语法糖。</p> <p><code>if let</code> 的格式如下:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">if</span> <span class="token keyword">let</span> pattern <span class="token operator">=</span> value <span class="token punctuation">{</span>
  314. <span class="token comment">//TODO</span>
  315. <span class="token punctuation">}</span>
  316. </code></pre></div><p>他也可以搭配 <code>else</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">test06</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  317. <span class="token keyword">let</span> v <span class="token operator">=</span> <span class="token number">8u8</span><span class="token punctuation">;</span>
  318. <span class="token keyword">match</span> v <span class="token punctuation">{</span>
  319. <span class="token number">3</span> <span class="token operator">=&gt;</span> <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;Three!&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  320. _ <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">)</span>
  321. <span class="token punctuation">}</span>
  322. <span class="token keyword">if</span> <span class="token keyword">let</span> <span class="token number">3</span> <span class="token operator">=</span> v <span class="token punctuation">{</span>
  323. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;Three&quot;</span><span class="token punctuation">)</span>
  324. <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token keyword">let</span> <span class="token number">5</span> <span class="token operator">=</span> v <span class="token punctuation">{</span>
  325. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;Five!&quot;</span><span class="token punctuation">)</span>
  326. <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
  327. <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">&quot;Others!&quot;</span><span class="token punctuation">)</span>
  328. <span class="token punctuation">}</span>
  329. <span class="token punctuation">}</span>
  330. </code></pre></div></div> <footer class="page-edit"><!----> <!----></footer> <!----> </main></div><div class="global-ui"></div></div>
  331. <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/28.f61a69ee.js" defer></script>
  332. </body>
  333. </html>