<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>ccnuu</title>
  
  
  <link href="https://ccnuu.github.io/atom.xml" rel="self"/>
  
  <link href="https://ccnuu.github.io/"/>
  <updated>2026-04-09T02:26:43.057Z</updated>
  <id>https://ccnuu.github.io/</id>
  
  <author>
    <name>ccnuu</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>编译C3C源码</title>
    <link href="https://ccnuu.github.io/2025/03/20/%E7%BC%96%E8%AF%91C3C%E6%BA%90%E7%A0%81/"/>
    <id>https://ccnuu.github.io/2025/03/20/%E7%BC%96%E8%AF%91C3C%E6%BA%90%E7%A0%81/</id>
    <published>2025-03-20T13:28:02.000Z</published>
    <updated>2026-04-09T02:26:43.057Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>关于 c3c 从源码构建, 遇到的一些坑: 当前 (<code>2025-03-21</code>) 根据 c3c 文档中介绍的从源码构建, 简单的几行命令就可以 build 出来编译器了, 但我在实际的操作中, 一直卡在 <code>Loading Windows LLVM libraries, this may take a while...</code>, 重试几次无果, 于是乎翻构建脚本看看</p><h2 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h2><p>目标平台是 <code>windows</code>, 其他平台不在此笔记中记载</p><blockquote><p>因为我主力机是 <code>windows</code>, 所以 <code>Unix</code> 系列没去 build, 听群友说是无痛编译</p></blockquote><p>开始之前列举一下相关文档:</p><ul><li><a href="https://c3-lang.org/getting-started/">c3官方文档</a>, 安装, 使用的详情都在这了</li><li><a href="https://github.com/c3lang/win-llvm/releases/tag/llvm_19_1_5">c3文档指向的 llvm 版本</a>, 我是直接到 <a href="https://github.com/llvm/llvm-project/releases">llvm仓库自己安装的</a></li><li><a href="git@github.com:c3lang/c3c.git">c3源码</a>, <code>git clone git@github.com:c3lang/c3c.git</code></li></ul><p>build前需要准备的环境如下:</p><ul><li>msvc, <strong>「visual studio installer」</strong> 中勾选上 <strong>「使用 C++ 的桌面开发」</strong> 安装即可 (这里如果不适用 msvc, 改用 mingw 应该也可以, 但是我没有实践)</li><li>cmake</li></ul><h2 id="构建"><a href="#构建" class="headerlink" title="构建"></a>构建</h2><blockquote><p>直接跳到 <a href="./%E7%BC%96%E8%AF%91C3C%E6%BA%90%E7%A0%81.md/#%E8%A1%A5%E5%85%85">补充</a> 段落修改编译脚本(简单省事), 然后再根据下面的命令执行步骤跑一遍就可以了</p></blockquote><ul><li>git clone <a href="mailto:&#x67;&#105;&#116;&#64;&#x67;&#105;&#x74;&#104;&#117;&#98;&#x2e;&#x63;&#111;&#x6d;">&#x67;&#105;&#116;&#64;&#x67;&#105;&#x74;&#104;&#117;&#98;&#x2e;&#x63;&#111;&#x6d;</a>:c3lang&#x2F;c3c.git</li><li>cd c3c</li><li>修改 <code>CMakeLists.txt</code><ul><li>line: 121 ~ 152  <pre class="line-numbers language-cmake" data-language="cmake"><code class="language-cmake"><span class="token comment"># if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")</span><span class="token comment">#     if (C3_LLVM_VERSION STREQUAL "auto")</span><span class="token comment">#         set(C3_LLVM_VERSION "19")</span><span class="token comment">#     endif()</span><span class="token comment">#     FetchContent_Declare(</span><span class="token comment">#             LLVM_Windows</span><span class="token comment">#             URL https://github.com/c3lang/win-llvm/releases/download/llvm_19_1_5/llvm-19.1.5-windows-amd64-msvc17-libcmt.7z</span><span class="token comment">#     )</span><span class="token comment">#     FetchContent_Declare(</span><span class="token comment">#             LLVM_Windows_debug</span><span class="token comment">#             URL https://github.com/c3lang/win-llvm/releases/download/llvm_19_1_5/llvm-19.1.5-windows-amd64-msvc17-libcmt-dbg.7z</span><span class="token comment">#     )</span><span class="token comment">#     if(CMAKE_BUILD_TYPE STREQUAL "Debug")</span><span class="token comment">#         message("Loading Windows LLVM debug libraries, this may take a while...")</span><span class="token comment">#         FetchContent_MakeAvailable(LLVM_Windows_debug)</span><span class="token comment">#         set(llvm_dir $&#123;llvm_windows_debug_SOURCE_DIR&#125;)</span><span class="token comment">#     else()</span><span class="token comment">#         message("Loading Windows LLVM libraries, this may take a while...")</span><span class="token comment">#         FetchContent_MakeAvailable(LLVM_Windows)</span><span class="token comment">#         set(llvm_dir $&#123;llvm_windows_SOURCE_DIR&#125;)</span><span class="token comment">#     endif()</span><span class="token comment">#     set(CMAKE_SYSTEM_PREFIX_PATH $&#123;llvm_dir&#125; $&#123;CMAKE_SYSTEM_PREFIX_PATH&#125;)</span><span class="token comment">#     find_package(LLVM REQUIRED CONFIG)</span><span class="token comment">#     find_package(LLD REQUIRED CONFIG)</span><span class="token comment"># else()</span><span class="token comment">#     if (NOT C3_LLVM_VERSION STREQUAL "auto")</span><span class="token comment">#         find_package(LLVM $&#123;C3_LLVM_VERSION&#125; REQUIRED CONFIG)</span><span class="token comment">#     else()</span><span class="token comment">#         find_package(LLVM REQUIRED CONFIG)</span><span class="token comment">#     endif()</span><span class="token comment"># endif()</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li>上面部分 cmake 脚本是默认 msvc 环境下就会去远端拉取 llvm 环境, 注释掉或者直接删除, 替换成下面的脚本. 其中 <code>LLVM_DIR</code> 设置成自己 llvm 实际的安装路径即可  <pre class="line-numbers language-cmake" data-language="cmake"><code class="language-cmake"><span class="token keyword">if</span><span class="token punctuation">(</span><span class="token variable">CMAKE_C_COMPILER_ID</span> <span class="token operator">STREQUAL</span> <span class="token string">"MSVC"</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">C3_LLVM_VERSION</span> <span class="token operator">STREQUAL</span> <span class="token string">"auto"</span><span class="token punctuation">)</span>        <span class="token keyword">set</span><span class="token punctuation">(</span><span class="token variable">C3_LLVM_VERSION</span> <span class="token string">"19.1.5"</span><span class="token punctuation">)</span>    <span class="token keyword">endif</span><span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token comment"># 手动设置本地 LLVM</span>    <span class="token keyword">set</span><span class="token punctuation">(</span>LLVM_DIR <span class="token string">"D:/LLVM"</span> <span class="token variable">CACHE</span> PATH <span class="token string">"Path to LLVM cmake directory"</span><span class="token punctuation">)</span>    <span class="token keyword">find_package</span><span class="token punctuation">(</span>LLVM <span class="token punctuation">$&#123;</span><span class="token variable">C3_LLVM_VERSION</span><span class="token punctuation">&#125;</span> REQUIRED CONFIG<span class="token punctuation">)</span>    <span class="token keyword">find_package</span><span class="token punctuation">(</span>LLD REQUIRED CONFIG<span class="token punctuation">)</span><span class="token keyword">else</span><span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">NOT</span> <span class="token variable">C3_LLVM_VERSION</span> <span class="token operator">STREQUAL</span> <span class="token string">"auto"</span><span class="token punctuation">)</span>        <span class="token keyword">find_package</span><span class="token punctuation">(</span>LLVM <span class="token punctuation">$&#123;</span><span class="token variable">C3_LLVM_VERSION</span><span class="token punctuation">&#125;</span> REQUIRED CONFIG<span class="token punctuation">)</span>    <span class="token keyword">else</span><span class="token punctuation">(</span><span class="token punctuation">)</span>        <span class="token keyword">find_package</span><span class="token punctuation">(</span>LLVM REQUIRED CONFIG<span class="token punctuation">)</span>    <span class="token keyword">endif</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">endif</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul></li><li>mkdir build</li><li>cd build</li><li>cmake ..</li><li>cmake –build .</li></ul><p>构建完毕, <code>build</code> 目录下生成 <code>c3c.exe</code></p><h3 id="补充"><a href="#补充" class="headerlink" title="补充"></a>补充</h3><p>莫名奇妙的, 第二天到公司电脑编源码, 还是一样的配置 环境, 硬是不行 (找不到问题, 后面把 <code>CMakeLists.txt</code> 一通乱改测试编译), 后面发现没必要改这么一大段, 简单替换一下 fetch 部分就好了:</p><blockquote><p>我就只下载了一个 debug 的 llvm, 所以替换成一样的了</p></blockquote><pre class="line-numbers language-cmake" data-language="cmake"><code class="language-cmake"><span class="token keyword">if</span><span class="token punctuation">(</span><span class="token variable">CMAKE_BUILD_TYPE</span> <span class="token operator">STREQUAL</span> <span class="token string">"Debug"</span><span class="token punctuation">)</span>    <span class="token keyword">message</span><span class="token punctuation">(</span><span class="token string">"Loading Windows LLVM debug libraries, this may take a while..."</span><span class="token punctuation">)</span>    <span class="token comment"># FetchContent_MakeAvailable(LLVM_Windows_debug)</span>    <span class="token keyword">set</span><span class="token punctuation">(</span>llvm_dir <span class="token string">"D:/llvm-19.1.5-windows-amd64-msvc17-libcmt-dbg"</span> <span class="token variable">CACHE</span> PATH <span class="token string">"Path to LLVM cmake directory"</span><span class="token punctuation">)</span>    <span class="token keyword">set</span><span class="token punctuation">(</span>llvm_dir <span class="token punctuation">$&#123;</span><span class="token variable">llvm_windows_debug_SOURCE_DIR</span><span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token keyword">else</span><span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token keyword">message</span><span class="token punctuation">(</span><span class="token string">"Loading Windows LLVM libraries, this may take a while..."</span><span class="token punctuation">)</span>    <span class="token comment"># FetchContent_MakeAvailable(LLVM_Windows)</span>    <span class="token keyword">set</span><span class="token punctuation">(</span>llvm_dir <span class="token string">"D:/llvm-19.1.5-windows-amd64-msvc17-libcmt-dbg"</span> <span class="token variable">CACHE</span> PATH <span class="token string">"Path to LLVM cmake directory"</span><span class="token punctuation">)</span>    <span class="token keyword">set</span><span class="token punctuation">(</span>llvm_dir <span class="token punctuation">$&#123;</span><span class="token variable">llvm_windows_SOURCE_DIR</span><span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token keyword">endif</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h2><p>还是在 <code>build</code> 目录中</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">c3c compile-run  <span class="token punctuation">..</span>/resources/testfragments/helloworld.c3<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>打印输出如下, 即 <code>c3c</code> 环境搭建完成</p><pre class="line-numbers language-txt" data-language="txt"><code class="language-txt">E:\Code\c3c\build>c3c compile-run  ../resources/testfragments/helloworld.c3Launching helloworld.exeHello, World!Program completed with exit code 0.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot; title=&quot;前言&quot;&gt;&lt;/a&gt;前言&lt;/h2&gt;&lt;p&gt;关于 c3c 从源码构建, 遇到的一些坑: 当前 (&lt;code&gt;2025-03-21&lt;/code&gt;) 根据 c3c 文档中介绍的从源码构建,</summary>
      
    
    
    
    <category term="笔记" scheme="https://ccnuu.github.io/categories/%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="C3C" scheme="https://ccnuu.github.io/tags/C3C/"/>
    
    <category term="C3" scheme="https://ccnuu.github.io/tags/C3/"/>
    
  </entry>
  
  <entry>
    <title>Rust学习笔记</title>
    <link href="https://ccnuu.github.io/2023/08/24/Rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    <id>https://ccnuu.github.io/2023/08/24/Rust%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</id>
    <published>2023-08-24T06:05:39.000Z</published>
    <updated>2026-04-09T02:26:43.057Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Rust网页版ide"><a href="#Rust网页版ide" class="headerlink" title="Rust网页版ide"></a>Rust网页版ide</h2><p><code>https://play.rust-lang.org/</code></p><h2 id="安装配置"><a href="#安装配置" class="headerlink" title="安装配置"></a>安装配置</h2><h3 id="RustUp相关"><a href="#RustUp相关" class="headerlink" title="RustUp相关"></a>RustUp相关</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 显示当前安装的工具链信息</span>rustup show<span class="token comment"># 检查安装更新</span>rustup update<span class="token comment"># 卸载</span>rustup self uninstall<span class="token comment"># 设置当前默认工具链</span>rustup default stable-x86_64-pc-windows-gnu<span class="token comment"># 查看帮助</span>rustup <span class="token parameter variable">-h</span><span class="token comment"># -------------------------->配置工具链</span><span class="token comment"># 查看工具链</span>rustup toolchain list<span class="token comment"># 安装工具链</span>rustup toolchain <span class="token function">install</span> stable-x86_64-pc-windows-gnu<span class="token comment"># 卸载工具链</span>rustup toolchain uninstall stable-x86_64-pc-windows-gnu<span class="token comment"># 设置自定义工具链</span>rustup toolchain <span class="token function">link</span> <span class="token operator">&lt;</span>toolchain-name<span class="token operator">></span> <span class="token string">"&lt;toolchain-path>"</span><span class="token comment"># -------------------------->配置一个目录以及其子目录的默认工具链</span><span class="token comment"># 查看已设置的默认工具链</span>rustup override list<span class="token comment"># 设置该目录以及其子目录的默认工具链</span>rustup override <span class="token builtin class-name">set</span> <span class="token operator">&lt;</span>toolchain<span class="token operator">></span> <span class="token parameter variable">--path</span> <span class="token operator">&lt;</span>path<span class="token operator">></span><span class="token comment"># 取消目录以及其子目录的默认工具链</span>rustup override <span class="token builtin class-name">unset</span> <span class="token parameter variable">--path</span> <span class="token operator">&lt;</span>path<span class="token operator">></span><span class="token comment"># -------------------------->配置工具链的可用目标</span><span class="token comment"># 查看目标列表</span>rustup target list<span class="token comment"># 安装目标</span>rustup target <span class="token function">add</span> <span class="token operator">&lt;</span>target<span class="token operator">></span><span class="token comment"># 卸载目标</span>rustup target remove <span class="token operator">&lt;</span>target<span class="token operator">></span><span class="token comment"># 为特定工具链安装目标</span>rustup target <span class="token function">add</span> <span class="token parameter variable">--toolchain</span> <span class="token operator">&lt;</span>toolchain<span class="token operator">></span> <span class="token operator">&lt;</span>target<span class="token operator">></span><span class="token comment"># -------------------------->配置 rustup 安装的组件</span><span class="token comment"># 查看可用组件</span>rustup component list<span class="token comment"># 安装组件</span>rustup component <span class="token function">add</span> <span class="token operator">&lt;</span>component<span class="token operator">></span><span class="token comment"># 卸载组件</span>rustup component remove <span class="token operator">&lt;</span>component<span class="token operator">></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="配置工具链安装位置"><a href="#配置工具链安装位置" class="headerlink" title="配置工具链安装位置"></a>配置工具链安装位置</h3><p>在系统环境变量中添加如下变量：</p><ul><li>CARGO_HOME - 指定cargo的安装目录</li><li>RUSTUP_HOME - 指定rustup的安装目录</li></ul><p>默认分别安装到用户目录下的<code>.cargo</code> 和<code>.rustup</code> 目录</p><h3 id="配置-rustup-国内镜像"><a href="#配置-rustup-国内镜像" class="headerlink" title="配置 rustup 国内镜像"></a>配置 rustup 国内镜像</h3><p>在系统环境变量中添加如下变量(选一个就可以，可以组合): </p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 清华大学</span>RUSTUP_DIST_SERVER：https://mirrors.tuna.tsinghua.edu.cn/rustupRUSTUP_UPDATE_ROOT：https://mirrors.tuna.tsinghua.edu.cn/rustup/rustup<span class="token comment"># 中国科学技术大学</span>RUSTUP_DIST_SERVER：https://mirrors.ustc.edu.cn/rust-staticRUSTUP_UPDATE_ROOT：https://mirrors.ustc.edu.cn/rust-static/rustup<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="配置-cargo-国内镜像"><a href="#配置-cargo-国内镜像" class="headerlink" title="配置 cargo 国内镜像"></a>配置 cargo 国内镜像</h3><p>在 cargo 安装目录下新建<code>config</code> 文件(注意 config 没有任何后缀)，文件内容如下: </p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">[</span>source.crates-io<span class="token punctuation">]</span>registry <span class="token operator">=</span> <span class="token string">"https://github.com/rust-lang/crates.io-index"</span>replace-with <span class="token operator">=</span> <span class="token string">'tuna'</span><span class="token comment"># 清华大学</span><span class="token punctuation">[</span>source.tuna<span class="token punctuation">]</span>registry <span class="token operator">=</span> <span class="token string">"https://mirrors.tuna.tsinghua.edu.cn/crates.io-index"</span><span class="token comment"># 中国科学技术大学</span><span class="token punctuation">[</span>source.ustc<span class="token punctuation">]</span>registry <span class="token operator">=</span> <span class="token string">"git://mirrors.ustc.edu.cn/crates.io-index"</span><span class="token comment"># 设置代理</span><span class="token comment"># [http]</span><span class="token comment"># proxy = "127.0.0.1:8889"</span><span class="token comment"># [https]</span><span class="token comment"># proxy = "127.0.0.1:8889"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="使用Rust模块系统管理代码"><a href="#使用Rust模块系统管理代码" class="headerlink" title="使用Rust模块系统管理代码"></a>使用Rust模块系统管理代码</h2><p>Rust 提供了一系列功能，可帮助你管理和组织代码。 这些功能称为“Rust 模块系统”。 系统由 Crate、模块、路径和工具组成，以与那些项结合使用</p><ul><li>箱：Rust 箱是一个编译单元。 它是 Rust 编译器可以运行的最小代码段。 箱中的代码一起编译以创建二进制可执行文件或库。 在 Rust 中，仅将箱编译为可重复使用的单元。 箱包含具有隐式未命名顶级模块的 Rust 模块的层次结构</li><li>模块：Rust 模块通过让你管理箱内单个代码项的范围来帮助你组织程序。 结合使用的相关代码项或项可以分组到相同模块中。 递归代码定义可以跨越其他模块</li><li>路径：在 Rust 中，可以使用路径来命名代码中的项。 例如，路径可以是一个数据定义（例如，矢量、代码函数，甚至是模块）。 模块功能还可帮助你控制路径的隐私。 可以指定可公开访问的代码部分和私有部分。 通过该功能可以隐藏实现详细信息</li></ul><h2 id="使用Rust箱和库"><a href="#使用Rust箱和库" class="headerlink" title="使用Rust箱和库"></a>使用Rust箱和库</h2><ul><li>Rust 标准库。 在 Rust 练习中，你将会注意到以下模块：<ul><li>std::collections - 集合类型的定义，如 HashMap</li><li>std::env - 用于处理环境的函数</li><li>std::fmt - 控制输出格式的功能</li><li>std::fs - 用于处理文件系统的功能</li><li>std::io - 用于处理输入&#x2F;输出的定义和功能</li><li>std::path - 支持处理文件系统路径数据的定义和功能</li></ul></li><li>structopt - 用于轻松分析命令行参数的第三方箱</li><li>chrono - 用于处理日期和时间数据的第三方箱</li><li>regex - 用于处理正则表达式的第三方箱</li><li>serde - 适用于 Rust 数据结构的序列化和反序列化操作的第三方箱</li></ul><h2 id="使用Cargo创建和管理项目"><a href="#使用Cargo创建和管理项目" class="headerlink" title="使用Cargo创建和管理项目"></a>使用Cargo创建和管理项目</h2><ul><li>使用 cargo new 命令创建新的项目模板</li><li>使用 cargo build 编译项目</li><li>使用 cargo run 命令编译并运行项目</li><li>使用 cargo test 命令测试项目</li><li>使用 cargo check 命令检查项目类型</li><li>使用 cargo doc 命令编译项目的文档</li><li>使用 cargo publish 命令将库发布到 crates.io</li><li>通过将箱的名称添加到 Cargo.toml 文件来将依赖箱添加到项目</li></ul><h2 id="结构"><a href="#结构" class="headerlink" title="结构"></a>结构</h2><p>Rust支持三种结构类型：经典结构、元组结构和单元结构。这些结构类型支持使用各种方式对数据进行分组和处理</p><ul><li>“经典C结构”最为常用。结构中的每个字段都具有名称和数据类型。定义经典结构后，可以使用语法<struct>.<field>访问结构中的字段</li><li>元组结构类似于经典结构，但字段没有名称。要访问元组结构中的字段，请使用索引元组时所用的语法：<struct>.<index>。与元组一样，元组结构中的索引值从0开始</li><li>“单元结构”最常用作标记<pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">struct Student &#123;    name: String,    level: u8,    remote: bool&#125;struct Grades(char, char, u8, f32);struct Unit;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul><h2 id="创建和使用数组"><a href="#创建和使用数组" class="headerlink" title="创建和使用数组"></a>创建和使用数组</h2><h3 id="定义数组"><a href="#定义数组" class="headerlink" title="定义数组"></a>定义数组</h3><ul><li>未指定长度的逗号分隔的值列表</li><li>初始值后跟一个分号，然后是数组长度</li></ul><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">&#x2F;&#x2F; Declare array, initialize all values, compiler infers length &#x3D; 7let days &#x3D; [&quot;Sunday&quot;, &quot;Monday&quot;, &quot;Tuesday&quot;, &quot;Wednesday&quot;, &quot;Thursday&quot;, &quot;Friday&quot;, &quot;Saturday&quot;];  &#x2F;&#x2F; Declare array, initialize all values to 0, length &#x3D; 5let bytes &#x3D; [0; 5];<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>在编译时，数组的签名定义为 <code>[T; size]</code>：</p><ul><li><code>T</code>是数组中所有元素的数据类型</li><li><code>size</code>是表示数组长度的非负整数</li></ul><p>该签名揭示有关数组的两个重要特征:</p><ul><li>数组的每个元素都具有相同的数据类型。 数据类型永远不会更改</li><li>数组大小是固定的。 长度永远不会更改</li></ul><p>仅数组中元素的值可随时间而更改。 数据类型和元素数量（长度）均保持不变。 只有这些值可以更改</p><h3 id="读取数组的值"><a href="#读取数组的值" class="headerlink" title="读取数组的值"></a>读取数组的值</h3><p>数组中的元素从 0 开始隐式编号。 我们在表达式 <code>&lt;array&gt;[&lt;index&gt;]</code> 中使用索引来访问的数组中的元素。 例如，<code>my_array[0]</code> 访问 <code>my_array</code> 变量中索引 0 位置的元素。 该表达式返回该索引位置的数组元素的值</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">&#x2F;&#x2F; Days of the weeklet days &#x3D; [&quot;Sunday&quot;, &quot;Monday&quot;, &quot;Tuesday&quot;, &quot;Wednesday&quot;, &quot;Thursday&quot;, &quot;Friday&quot;, &quot;Saturday&quot;];&#x2F;&#x2F; Get the first day of the weeklet first &#x3D; days[0];&#x2F;&#x2F; Get the second day of the weeklet second &#x3D; days[1];<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="Vector"><a href="#Vector" class="headerlink" title="Vector"></a>Vector</h2><p>Vector和数组一样，可以使用索引访问元素。<code>mut</code> 可变Vector添加元素可以使用 <code>push</code>函数，删除Vector最后一个元素可以使用 <code>pop</code>函数</p><h2 id="if-else"><a href="#if-else" class="headerlink" title="if else"></a>if else</h2><p>Rust中的<code>if-else</code> 语句块是可以充当表达式的</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">let formal &#x3D; true;let greeting &#x3D; if formal &#123; &#x2F;&#x2F; if used here as an expression    &quot;Good day to you.&quot;     &#x2F;&#x2F; return a String&#125; else &#123;    &quot;Hey!&quot;                 &#x2F;&#x2F; return a String&#125;;println!(&quot;&#123;&#125;&quot;, greeting)   &#x2F;&#x2F; prints &quot;Good day to you.&quot;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="合并多个测试条件"><a href="#合并多个测试条件" class="headerlink" title="合并多个测试条件"></a>合并多个测试条件</h3><p>可以将<code>if</code> 和<code>else</code> 组合在一起形成<code>else if</code> 表达式。可以在开头的<code>if</code> 条件后面和<code>else</code> 条件前面使用多个<code>else if</code>条件，这些条件是可选的</p><p>如果条件表达式的计算结果为<code>true</code>，则执行相应的操作块，跳过后面任何的<code>else if</code> 和<code>else</code> 块。如果条件表达式的结果为<code>false</code> ，则跳过相应的操作块。如果<code>if</code> 和 <code>else if</code> 条件的计算结果都是<code>false</code>，则执行所有的<code>else</code> 程序块</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">let num &#x3D; 500; &#x2F;&#x2F; num variable can be set at some point in the programlet out_of_range: bool;if num &lt; 0 &#123;    out_of_range &#x3D; true;&#125; else if num &#x3D;&#x3D; 0 &#123;    out_of_range &#x3D; true;&#125; else if num &gt; 512 &#123;    out_of_range &#x3D; true;&#125; else &#123;    out_of_range &#x3D; false;&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="错误处理"><a href="#错误处理" class="headerlink" title="错误处理"></a>错误处理</h2><ul><li>处理无法恢复的错误可以使用<code>panic!</code></li><li>如果值是可选或缺少值不是一种错误的情况，使用<code>Option</code> 枚举</li><li>当可能出现问题并且调用方法必须处理问题时，使用<code>Result</code> 枚举</li></ul><h3 id="使用Option类型来处理缺失"><a href="#使用Option类型来处理缺失" class="headerlink" title="使用Option类型来处理缺失"></a>使用Option类型来处理缺失</h3><p><code>Option&lt;T&gt;</code> 将自身列为两个变体之一：</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">enum Option&lt;T&gt; &#123;    None,     &#x2F;&#x2F; The value doesn&#96;t exist    Some(T),  &#x2F;&#x2F; The value exists&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p><code>Option&lt;T&gt;</code> 枚举声明的<code>&lt;T&gt;</code> 部分声明类型<code>T</code> 是通用的，将与<code>Option</code> 枚举的<code>Some</code> 变体相关联</p><p><code>None</code> 和<code>Some</code>不是类型，而是<code>Option&lt;T&gt;</code> 类型的变体。这表示在其他功能中，函数不能使用<code>Some</code> 或<code>None</code> 作为参数，而只能使用<code>Option&lt;T&gt;</code> 作为参数</p><h3 id="如何才能访问到Some-data-变体中的数据呢？"><a href="#如何才能访问到Some-data-变体中的数据呢？" class="headerlink" title="如何才能访问到Some(data) 变体中的数据呢？"></a>如何才能访问到<code>Some(data)</code> 变体中的数据呢？</h3><h4 id="模式匹配"><a href="#模式匹配" class="headerlink" title="模式匹配"></a>模式匹配</h4><p>Rust 中提供了一个功能强大的运算符，称为 <code>match</code>。 可利用该运算符，通过提供模式来控制程序流。 当 match 找到匹配的模式时，它会运行随该模式一起提供的代码</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">let fruits &#x3D; vec![&quot;banana&quot;, &quot;apple&quot;, &quot;coconut&quot;, &quot;orange&quot;, &quot;strawberry&quot;];for &amp;index in [0, 2, 99].iter() &#123;    match fruits.get(index) &#123;        Some(fruit_name) &#x3D;&gt; println!(&quot;It&#39;s a delicious &#123;&#125;!&quot;, fruit_name),        None &#x3D;&gt; println!(&quot;There is no fruit! :(&quot;),    &#125;&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="if-let-表达式"><a href="#if-let-表达式" class="headerlink" title="if let 表达式"></a>if let 表达式</h4><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">let a_number: Option&lt;u8&gt; &#x3D; Some(7);match a_number &#123;    Some(7) &#x3D;&gt; println!(&quot;That&#39;s my lucky number!&quot;),    _ &#x3D;&gt; &#123;&#125;,&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>这种情况下，可以用所有其他模式之后添加<code>_</code> 通配符，以匹配任何其他模式</p><p>使用<code>if let</code> 压缩代码：</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">let a_number: Option&lt;u8&gt; &#x3D; Some(7);if let Some(7) &#x3D; a_number &#123;    println!(&quot;That&#39;s my lucky number!&quot;);&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><h4 id="使用unwrap-和expect"><a href="#使用unwrap-和expect" class="headerlink" title="使用unwrap 和expect"></a>使用<code>unwrap</code> 和<code>expect</code></h4><p>可以使用<code>unwrap</code> 和<code>expect</code> 方法直接访问<code>Option</code> 类型的内部值。但是要小心，因为如果变体是<code>None</code>，则此方法会<code>panic</code></p><h3 id="使用Result-类型来处理错误"><a href="#使用Result-类型来处理错误" class="headerlink" title="使用Result 类型来处理错误"></a>使用Result 类型来处理错误</h3><p>Rust提供了用于返回和传播错误的<code>Result&lt;T, E&gt;</code> 枚举。按照惯例，<code>Ok(T)</code> 变量表示成功并包含一个值，而变量<code>Err(E)</code> 表示错误并包含一个错误值</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">enum Result&lt;T, E&gt; &#123;    Ok(T):  &#x2F;&#x2F; A value T was obtained.    Err(E): &#x2F;&#x2F; An error of type E was encountered instead.&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p>不同于描述缺少某个值的可能性<code>Option</code> 类型，<code>Result</code> 类型最适合在可能会失败的时候使用</p><p><code>Result</code> 类型还具有<code>unwrap</code> 和 <code>expect</code> 方法，这些方法执行以下操作之一：</p><ul><li>返回<code>Ok</code> 变量中的值</li><li>如果变体是<code>Err</code>，则导致程序<code>panic</code></li></ul><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">#[derive(Debug)]struct DivisionByZeroError;fn safe_division(dividend: f64, divisor: f64) -&gt; Result&lt;f64, DivisionByZeroError&gt; &#123;    if divisor &#x3D;&#x3D; 0.0 &#123;        Err(DivisionByZeroError)    &#125; else &#123;        Ok(dividend &#x2F; divisor)    &#125;&#125;fn main() &#123;    println!(&quot;&#123;:?&#125;&quot;, safe_division(9.0, 3.0));    println!(&quot;&#123;:?&#125;&quot;, safe_division(4.0, 0.0));    println!(&quot;&#123;:?&#125;&quot;, safe_division(0.0, 2.0));&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="内存管理"><a href="#内存管理" class="headerlink" title="内存管理"></a>内存管理</h2><p>Rust最强大的两个功能：所有权和借用</p><h3 id="什么是所有权？"><a href="#什么是所有权？" class="headerlink" title="什么是所有权？"></a>什么是所有权？</h3><p>Rust包含用于管理内存的所有权系统。在编译时，所有权系统会检查一组规则，以确保所有权功能允许程序运行而不减慢速度</p><h4 id="作用域界定规则"><a href="#作用域界定规则" class="headerlink" title="作用域界定规则"></a>作用域界定规则</h4><p>在Rust中，与大多数编程语言一样，变量仅在特定的作用域内有效。在Rust中，作用域常常由大括号<code>&#123;&#125;</code> 表示。常见的作用域还包括函数体、<code>if</code>、<code>else</code> 和<code>match</code> 分支</p><p>在Rust中，“变量”通常称为“绑定”。这是因为Rust中的“变量”不是多变的，它们默认不可变，因此不会经常改变。相反，我们常常会想到与数据“绑定”的名称，所以称为“绑定”</p><p>假设一个<code>string</code> 变量，它是在某个作用域内定义的一个字符串：</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">&#x2F;&#x2F; &#96;string&#96; is not valid and cannot be used here, because it&#39;s not yet declared.&#123;    let string &#x3D; String::from(&quot;ferris&quot;);   &#x2F;&#x2F; &#96;string&#96; is valid from this point forward.    &#x2F;&#x2F; do stuff with &#96;string&#96;.&#125;&#x2F;&#x2F; this scope is now over, so &#96;string&#96; is no longer valid and cannot be used.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>如果尝试在<code>string</code> 的范围之外使用它，将会得到一下错误示例：</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">&#123;    let string &#x3D; String::from(&quot;ferris&quot;);&#125;println!(&quot;&#123;&#125;&quot;, string);<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">error<span class="token punctuation">[</span>E0425<span class="token punctuation">]</span>: cannot <span class="token function">find</span> value <span class="token variable"><span class="token variable">`</span>string<span class="token variable">`</span></span> <span class="token keyword">in</span> this scope     --<span class="token operator">></span> src/main.rs:5:20      <span class="token operator">|</span>    <span class="token number">5</span> <span class="token operator">|</span>     println<span class="token operator">!</span><span class="token punctuation">(</span><span class="token string">"&#123;&#125;"</span>, string<span class="token punctuation">)</span><span class="token punctuation">;</span>      <span class="token operator">|</span>                    ^^^^^^ not found <span class="token keyword">in</span> this scope<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="所有权和删除"><a href="#所有权和删除" class="headerlink" title="所有权和删除"></a>所有权和删除</h4><p>Rust给范围的概念增加了一个转折。当对象超出范围时，便会将其“删除”。删除变量会释放与其关联的所有资源。对于文件的变量，文件最终会被关闭。对于已分配了与其关联的内存的变量，内存将被释放</p><p>在Rust中，将绑定被删除时释放的内容与自己“关联”到一起的绑定将“拥有”这些内容</p><p>在上一个例子中，<code>string</code> 变量拥有与之关联的<code>String</code> 数据。<code>string</code> 本身拥有堆分配的内存，其中包含该字符串的字符。在作用域的末尾，<code>string</code> 被“删除”，它拥有的<code>String</code> 被删除，最后<code>String</code> 拥有的内存被释放</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">&#123;    let string &#x3D; String::from(&quot;ferris&quot;);    &#x2F;&#x2F; string dropped here. The String data memory will be freed here.&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><h4 id="移动语义"><a href="#移动语义" class="headerlink" title="移动语义"></a>移动语义</h4><p>有时，我们不希望在作用域末尾删除与变量的关联的内容。相反，我们希望将某个项的所有权从一个绑定转移到另一个绑定</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">&#123;    let string &#x3D; String::from(&quot;ferris&quot;);    &#x2F;&#x2F; transfer ownership of string to the variable ferris.    let ferris &#x3D; string;    &#x2F;&#x2F; ferris dropped here. The string data memory will be freed here.&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>需要了解一个关键问题，那就是所有权一旦转移，旧变量将不再有效。当我们将<code>String</code> 的所有权从 <code>string</code> 转移到 <code>ferris</code> 之后，将无法再使用<code>string</code> 变量</p><p>如果我们尝试在将<code>String</code> 从<code>string</code> 移动到<code>ferris</code> 之后使用<code>string</code>，编译器将不会编译我们的代码：</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">let string &#x3D; String::from(&quot;hello world&quot;);let ferris &#x3D; string;&#x2F;&#x2F; We&#39;ll try to use string after we&#39;ve moved ownership of the string data from string to ferris.println!(&quot;&#123;&#125;&quot;, string);<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">error<span class="token punctuation">[</span>E0382<span class="token punctuation">]</span>: borrow of moved value: <span class="token variable"><span class="token variable">`</span>string<span class="token variable">`</span></span> --<span class="token operator">></span> src/main.rs:4:20  <span class="token operator">|</span><span class="token number">2</span> <span class="token operator">|</span>     <span class="token builtin class-name">let</span> string <span class="token operator">=</span> String::from<span class="token punctuation">(</span><span class="token string">"ferris"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token operator">|</span>         ------ move occurs because <span class="token variable"><span class="token variable">`</span>string<span class="token variable">`</span></span> has <span class="token builtin class-name">type</span> <span class="token variable"><span class="token variable">`</span>String<span class="token variable">`</span></span>, <span class="token function">which</span> does not implement the <span class="token variable"><span class="token variable">`</span>Copy<span class="token variable">`</span></span> trait<span class="token number">3</span> <span class="token operator">|</span>     <span class="token builtin class-name">let</span> ferris <span class="token operator">=</span> string<span class="token punctuation">;</span>  <span class="token operator">|</span>                  ------ value moved here<span class="token number">4</span> <span class="token operator">|</span>     println<span class="token operator">!</span><span class="token punctuation">(</span><span class="token string">"&#123;&#125;"</span>, string<span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token operator">|</span>                    ^^^^^^ value borrowed here after move<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>该结果被称为“移动后使用”编译错误</p><p>在Rust中，一个项一次只能拥有一段数据</p><h4 id="函数中的所有权"><a href="#函数中的所有权" class="headerlink" title="函数中的所有权"></a>函数中的所有权</h4><p>例子：将字符创作为参数传递给函数。将某个内容作为参数传递给函数，会将该内容移动到函数中</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">fn process(input: String) &#123;&#125;fn caller() &#123;    let s &#x3D; String::from(&quot;hello world&quot;);    process(s); &#x2F;&#x2F; Ownership of the string in &#96;s&#96; moved into &#96;process&#96;    process(s); &#x2F;&#x2F; Error! ownership already moved.&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>编译器提醒<code>s</code> 已被移动</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">error<span class="token punctuation">[</span>E0382<span class="token punctuation">]</span>: use of moved value: <span class="token variable"><span class="token variable">`</span>s<span class="token variable">`</span></span>     --<span class="token operator">></span> src/main.rs:6:13      <span class="token operator">|</span>    <span class="token number">4</span> <span class="token operator">|</span>     <span class="token builtin class-name">let</span> s <span class="token operator">=</span> String::from<span class="token punctuation">(</span><span class="token string">"Hello, world!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>      <span class="token operator">|</span>         - move occurs because <span class="token variable"><span class="token variable">`</span>s<span class="token variable">`</span></span> has <span class="token builtin class-name">type</span> <span class="token variable"><span class="token variable">`</span>String<span class="token variable">`</span></span>, <span class="token function">which</span> does not implement the <span class="token variable"><span class="token variable">`</span>Copy<span class="token variable">`</span></span> trait    <span class="token number">5</span> <span class="token operator">|</span>     process<span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span> // Transfers ownership of <span class="token variable"><span class="token variable">`</span>s<span class="token variable">`</span></span> to <span class="token variable"><span class="token variable">`</span>process<span class="token variable">`</span></span>      <span class="token operator">|</span>             - value moved here    <span class="token number">6</span> <span class="token operator">|</span>     process<span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span> // Error<span class="token operator">!</span> ownership already transferred.      <span class="token operator">|</span>             ^ value used here after move<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="复制而不是移动"><a href="#复制而不是移动" class="headerlink" title="复制而不是移动"></a>复制而不是移动</h4><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">fn process(input: u32) &#123;&#125;fn caller() &#123;    let n &#x3D; 1u32;    process(n); &#x2F;&#x2F; Ownership of the number in &#96;n&#96; copied into &#96;process&#96;    process(n); &#x2F;&#x2F; &#96;n&#96; can be used again because it wasn&#96;t moved, it was copied&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>简单类型，如数字是“复制”类型。它们实现<code>Copy</code> 特征，这意味着它们被复制而不是移动。大多数简单类型都执行相同的操作。复制数字的成本低，因此复制这些值是有意义的。复制字符串、向量或其他复杂类型的成本可能高昂，因此它们没有实现<code>Copy</code> 特征，而是被移动</p><h4 id="复制不实现Copy-的类型"><a href="#复制不实现Copy-的类型" class="headerlink" title="复制不实现Copy 的类型"></a>复制不实现<code>Copy</code> 的类型</h4><p>解决上一个示例中所示错误的一种方法是：在移动类型之前，显式复制它们，这在Rust中称为克隆。调用<code>.clone</code> 会复制内存并生成一个新值。新值被移动，这意味着仍然可以使用旧值</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">fn process(s: String) &#123;&#125;fn caller() &#123;    let s &#x3D; String::from(&quot;Hello world&quot;);    process(s.clone()); &#x2F;&#x2F; Passing another value, cloned from &#96;s&#96;    process(s); &#x2F;&#x2F; s was never moved and so it can still be used.&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>这种方法可能有用，但会导致代码运行速度变慢，因此每次调用<code>clone</code> 都是对数据的一次完整复制。此方法通过包括内存分配或其他高成本的操作。可以使用引用来“借用”值，从而避免这些成本</p><h3 id="了解借用"><a href="#了解借用" class="headerlink" title="了解借用"></a>了解借用</h3><p>通过将所有权从一个变量转移到另一个变量来转移一个值的所有权。对于实现<code>Copy</code> 特征的类型，例如简单的值（如数字），所有权不能被转移</p><p>还可以使用克隆过程显式复制值。调用<code>clone</code> 方法并获取复制的新值，这样原始值未被移动且仍可使用</p><p>此类功能通过使用引用来提供，通过引用，可以“借用”一些值，而无需拥有它们</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">let greeting &#x3D; String::from(&quot;hello&quot;);let greeting_reference &#x3D; &amp;greeting; &#x2F;&#x2F; We borrow &#96;greeting&#96; but the string data is still owned by &#96;greeting&#96;println!(&quot;Greeting: &#123;&#125;&quot;, greeting); &#x2F;&#x2F; We can still use &#96;greeting&#96;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p><code>greeting</code> 是使用引用符号(<code>&amp;</code>) 借用的。变量<code>greeting_reference</code> 的类型为字符串引用(<code>&amp;String</code>)。由于只借用了<code>greeting</code>，并没有移动所有权，因此，在创建<code>greeting_reference</code> 之后仍然可以使用<code>greeting</code></p><h4 id="函数中的引用"><a href="#函数中的引用" class="headerlink" title="函数中的引用"></a>函数中的引用</h4><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">fn print_greeting(message: &amp;String) &#123;    println!(&quot;Greeting: &#123;&#125;&quot;, message);&#125;fn main() &#123;    let greeting &#x3D; String::from(&quot;Hello&quot;);    print_greeting(&amp;greeting); &#x2F;&#x2F; &#96;print_greeting&#96; takes a &#96;&amp;String&#96; not an owned &#96;String&#96; so we borrow &#96;greeting&#96;    print_greeting(&amp;greeting); &#x2F;&#x2F; Since &#96;greeting&#96; didn&#39;t move into &#96;print_greeting&#96; we can use it again&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>通过借用，无需完全拥有某个值即可使用它。不过，借用值意味着并不能像完全拥有值那样执行权限范围内的所有操作</p><h4 id="改变借用的值"><a href="#改变借用的值" class="headerlink" title="改变借用的值"></a>改变借用的值</h4><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">fn change(message: &amp;String) &#123;  message.push_str(&quot;!&quot;); &#x2F;&#x2F; We try to add a &quot;!&quot; to the end of our message&#125;fn main() &#123;  let greeting &#x3D; String::from(&quot;Hello&quot;);  change(&amp;greeting); &#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>代码不能通过编译。收到的错误是：</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">error<span class="token punctuation">[</span>E0596<span class="token punctuation">]</span>: cannot borrow <span class="token variable"><span class="token variable">`</span>*message<span class="token variable">`</span></span> as mutable, as it is behind a <span class="token variable"><span class="token variable">`</span><span class="token operator">&amp;</span><span class="token variable">`</span></span> reference --<span class="token operator">></span> src/main.rs:2:3  <span class="token operator">|</span><span class="token number">1</span> <span class="token operator">|</span> fn change<span class="token punctuation">(</span>message: <span class="token operator">&amp;</span>String<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>  <span class="token operator">|</span>                    ------- help: consider changing this to be a mutable reference: <span class="token variable"><span class="token variable">`</span><span class="token operator">&amp;</span>mut String<span class="token variable">`</span></span><span class="token number">2</span> <span class="token operator">|</span>   message.push_str<span class="token punctuation">(</span><span class="token string">"!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> // We try to <span class="token function">add</span> a <span class="token string">"!"</span> to the end of our message  <span class="token operator">|</span>   ^^^^^^^ <span class="token variable"><span class="token variable">`</span>message<span class="token variable">`</span></span> is a <span class="token variable"><span class="token variable">`</span><span class="token operator">&amp;</span><span class="token variable">`</span></span> reference, so the data it refers to cannot be borrowed as mutable<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="借用和可变引用"><a href="#借用和可变引用" class="headerlink" title="借用和可变引用"></a>借用和可变引用</h4><p>不可变引用和可变引用还有一个不同之处：会对我们生成Rust程序的方式有根本的影响。借用任何<code>T</code> 类型的值时，以下规则都适用：</p><p>代码必须同时实现以下任一定义，但不能同时实现这两个定义：</p><ul><li>一个或多个不可变引用（<code>&amp;T</code>）</li><li>恰好一个可变引用（<code>&amp;mut T</code>）</li></ul><h3 id="使用生命周期验证引用"><a href="#使用生命周期验证引用" class="headerlink" title="使用生命周期验证引用"></a>使用生命周期验证引用</h3><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">fn main() &#123;    let x;    &#123;        let y &#x3D; 42;        x &#x3D; &amp;y; &#x2F;&#x2F; We store a reference to &#96;y&#96; in &#96;x&#96; but &#96;y&#96; is about to be dropped.    &#125;    println!(&quot;x: &#123;&#125;&quot;, x); &#x2F;&#x2F; &#96;x&#96; refers to &#96;y&#96; but &#96;y has been dropped!&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>这段代码编译失败</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">fn main() &#123;    let x;                &#x2F;&#x2F; ---------+-- &#39;a    &#123;                     &#x2F;&#x2F;          |        let y &#x3D; 42;       &#x2F;&#x2F; -+-- &#39;b  |        x &#x3D; &amp;y;           &#x2F;&#x2F;  |       |    &#125;                     &#x2F;&#x2F; -+       |    println!(&quot;x: &#123;&#125;&quot;, x); &#x2F;&#x2F;          |&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>内层 <code>&#39;b</code> 块的生存期比外层 <code>&#39;a</code> 块的生存期更短</p><p>Rust 编译器可以使用借用检查器来验证借用是否有效。 借用检查器会在编译时比较两个生存期。 在此场景中，<code>x</code> 的生存期为 <code>&#39;a</code>，但它引用了生存期为 <code>&#39;b</code> 的值。 引用主体（生存期为 <code>&#39;b</code> 的 y）的生存期比引用（生存期为 <code>&#39;a</code> 的 <code>x</code>）的生存期短，因此程序不会进行编译</p><p>另一个例子：</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">fn main() &#123;    let magic1 &#x3D; String::from(&quot;abracadabra!&quot;);    let result;    &#123;        let magic2 &#x3D; String::from(&quot;shazam!&quot;);        result &#x3D; longest_word(&amp;magic1, &amp;magic2);    &#125;    println!(&quot;The longest magic word is &#123;&#125;&quot;, result);&#125;fn longest_word&lt;&#39;a&gt;(x: &amp;&#39;a String, y: &amp;&#39;a String) -&gt; &amp;&#39;a String &#123;    if x.len() &gt; y.len() &#123;        x    &#125; else &#123;        y    &#125;&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>错误:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">error<span class="token punctuation">[</span>E0597<span class="token punctuation">]</span>: <span class="token variable"><span class="token variable">`</span>magic2<span class="token variable">`</span></span> does not live long enough     --<span class="token operator">></span> src/main.rs:6:40      <span class="token operator">|</span>    <span class="token number">6</span> <span class="token operator">|</span>         result <span class="token operator">=</span> longest_word<span class="token punctuation">(</span><span class="token operator">&amp;</span>magic1, <span class="token operator">&amp;</span>magic2<span class="token punctuation">)</span><span class="token punctuation">;</span>      <span class="token operator">|</span>                                        ^^^^^^^ borrowed value does not live long enough    <span class="token number">7</span> <span class="token operator">|</span>     <span class="token punctuation">&#125;</span>      <span class="token operator">|</span>     - <span class="token variable"><span class="token variable">`</span>magic2<span class="token variable">`</span></span> dropped here <span class="token keyword">while</span> still borrowed    <span class="token number">8</span> <span class="token operator">|</span>     println<span class="token operator">!</span><span class="token punctuation">(</span><span class="token string">"The longest magic word is &#123;&#125;"</span>, result<span class="token punctuation">)</span><span class="token punctuation">;</span>      <span class="token operator">|</span>                                              ------ borrow later used here<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>此错误表明编译器预期 <code>magic2</code> 的生存期与返回值和 <code>x</code> 输入参数的生存期相同。 Rust 预料会出现这种行为，因为我们使用同一生存期名称 (<code>&#39;a</code>) 对函数参数和返回值的生存期进行了批注</p><p>如果我们检查代码，作为人类，我们会看到 <code>magic1</code> 比 <code>magic2</code> 长。 我们会看到，结果包含对 <code>magic1</code> 的引用，该引用的生存期足够长，因此有效。 但是，Rust 在编译时无法运行该代码。 它会将 <code>&amp;magic1</code> 和 <code>&amp;magic2</code> 引用都视为可能的返回值，并会发出我们此前看到的错误</p><p><code>longest_word</code> 函数返回的引用生存期与传入的引用生存期中较小者相匹配。 因此，代码可能包含无效引用，借用检查器将禁止该引用</p><h2 id="Trait"><a href="#Trait" class="headerlink" title="Trait"></a>Trait</h2><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">trait Area &#123;    fn area(&amp;self) -&gt; f64;&#125;struct Circle &#123;    radius: f64,&#125;struct Rectangle &#123;    width: f64,    height: f64,&#125;impl Area for Circle &#123;    fn area(&amp;self) -&gt; f64 &#123;        use std::f64::consts::PI;        PI * self.radius.powf(2.0)    &#125;&#125;impl Area for Rectangle &#123;    fn area(&amp;self) -&gt; f64 &#123;        self.width * self.height    &#125;&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>为实现某种类型的特征，使用关键字<code>impl Trait for Type</code>，其中<code>Trait</code> 是要实现的特征的名称，<code>Type</code> 是实现器结构体或枚举的名称</p><p>在<code>impl</code> 块中，放置特征所需的方法签名，并使用自己希望特征的方法对于特定类型具有的特定行为填充方法主体</p><h3 id="迭代器"><a href="#迭代器" class="headerlink" title="迭代器"></a>迭代器</h3><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">trait Iterator &#123;    type Item;    fn next(&amp;mut self) -&gt; Option&lt;Self::Item&gt;;&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p><code>Iterator</code> 具有方法<code>next</code>，调用时它将返回<code>Option&lt;Item&gt;</code>。只要有元素，<code>next</code> 方法就会返回<code>Some(Item)</code>。用尽所有元素后，它将会返回<code>None</code> 以指示迭代已完成</p><p><code>type Item</code> 和 <code>Self::Item</code>，它们使用此特征定义关联的类型。此定义意味着<code>Iterator</code> 特征的每一次实现还需要定义关联的<code>Item</code> 类型，该类型用作<code>next</code> 方法的返回类型。换句话说，<code>Item</code> 类型将是从<code>for</code> 循环块内的迭代器返回的类型</p><h2 id="模块、包和第三方crate"><a href="#模块、包和第三方crate" class="headerlink" title="模块、包和第三方crate"></a>模块、包和第三方crate</h2><h3 id="理解代码组织背后的概念"><a href="#理解代码组织背后的概念" class="headerlink" title="理解代码组织背后的概念"></a>理解代码组织背后的概念</h3><ul><li>包<ul><li>包含一个或多个crete内的功能</li><li>包括有关如何生成这些crate的信息。该信息位于<code>Cargo.toml</code> 文件中</li></ul></li><li>箱<ul><li>是编译单元，即 Rust 编译器可以运行的最小码量</li><li>编译完成后，系统将生成可执行文件或库文件</li><li>其中包含未命名的隐式顶层模块</li></ul></li><li>模块<ul><li>是箱内的代码组织单位（或为嵌套形式）</li><li>可以具有跨其他模块的递归定义</li></ul></li></ul><h3 id="程序包"><a href="#程序包" class="headerlink" title="程序包"></a>程序包</h3><p>每当运行<code>Cargo new &lt;project-name&gt;</code> 命令时，Cargo将会为我们创建一个包</p><h3 id="板条箱"><a href="#板条箱" class="headerlink" title="板条箱"></a>板条箱</h3><p>Rust 的编译模型集中在名为箱 的项目中，可以将这些项目译为二进制文件或库文件</p><p>使用<code>cargo new</code> 命令创建的每个项目本身都是箱。可以在项目中用作依赖项的所有第三方Rust 代码也是单个箱</p><h3 id="库文件箱"><a href="#库文件箱" class="headerlink" title="库文件箱"></a>库文件箱</h3><p>创建库命令<code>cargo new --lib</code></p><h3 id="模块"><a href="#模块" class="headerlink" title="模块"></a>模块</h3><p>Rust 具有功能强大的模块系统。该系统可以分层方式将代码拆分为逻辑单元，从而提高其可读性和重用性</p><p>模块是项的集合：</p><ul><li>常量</li><li>类型别名</li><li>函数</li><li>结构</li><li>枚举</li><li>trait</li><li><code>impl</code> 块</li><li>其他模块</li></ul><p>模块还控制项隐私。项隐私将项标识为 public 和 private。public 表示项可以由外部代码使用。private 表示该项是内部实现详细信息，不能供外部使用</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">mod math &#123;    type Complex &#x3D; (f64, f64);    pub fn sin(f: f64) -&gt; f64 &#123; &#x2F;* ... *&#x2F; &#125;    pub fn cos(f: f64) -&gt; f64 &#123; &#x2F;* ... *&#x2F; &#125;    pub fn tan(f: f64) -&gt; f64 &#123; &#x2F;* ... *&#x2F; &#125;&#125;println!(&quot;&#123;&#125;&quot;, math::cos(45.0));<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>如果源文件中存在<code>mod</code> 声明，则在运行编译器之前，系统会将模块文件的内容插入到<code>mod</code> 声明的源文件中的所在位置。换句话说，系统不会对模块进行单独编译，只会编译箱</p><p>Rust 编译器会检查以确定是否可以跨模块使用项。默认情况下，Rust 中的所有内容都是专用的，并且只能由当前模块及其后代访问。与此相反，当项被声明<code>pub</code> 时，则可以将其视为可供外界访问</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">&#x2F;&#x2F; Declare a private structstruct Foo;&#x2F;&#x2F; Declare a public struct with a private fieldpub struct Bar &#123;    field: i32,&#125;&#x2F;&#x2F; Declare a public enum with two public variantspub enum State &#123;    PubliclyAccessibleVariant,    PubliclyAccessibleVariant2,&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="向项目中添加第三方箱"><a href="#向项目中添加第三方箱" class="headerlink" title="向项目中添加第三方箱"></a>向项目中添加第三方箱</h3><pre class="line-numbers language-toml" data-language="toml"><code class="language-toml"><span class="token punctuation">[</span><span class="token table class-name">dependencies</span><span class="token punctuation">]</span><span class="token key property">regex</span> <span class="token punctuation">=</span> <span class="token string">"1.4.2"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>如果在<code>Cargo.toml</code> 没有<code>[dependencies]</code> 部分，手动添加该部分即可</p><h2 id="单元测试"><a href="#单元测试" class="headerlink" title="单元测试"></a>单元测试</h2><p>Rust中的单元测试是用<code>#[test]</code> 属性标记的简单函数，可用于验证非测试代码是否按照预期方式正常运行。系统仅会在测试代码时编译这些函数</p><p>测试函数会运行要测试的代码。然后，这些函数通常使用<code>assert!</code> 或<code>assert_eq!</code> 宏来检查结果</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">fn add(a: i32, b: i32) -&gt; i32 &#123;    a + b&#125;#[test]fn add_works() &#123;    assert_eq!(add(1, 2), 3);    assert_eq!(add(10, 12), 22);    assert_eq!(add(5, -2), 3);&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="预期的失败"><a href="#预期的失败" class="headerlink" title="预期的失败"></a>预期的失败</h3><p>使用<code>should_panic</code>，便可以检查<code>panic!</code>。如果将此属性添加到测试函数，则当函数中的代码崩溃时，测试便会通过。当代码不崩溃时，测试便会失败</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">#[test]#[should_panic]fn add_fails() &#123;    assert_eq!(add(2, 2), 7);&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="忽略测试"><a href="#忽略测试" class="headerlink" title="忽略测试"></a>忽略测试</h3><p>可以使用<code>#[ignore]</code> 属性对带有<code>#[test]</code> 属性批注的函数进行批注。此属性会令系统在测试过程中跳过该测试函数</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">#[test]#[ignore &#x3D; &quot;not yet reviewed by the Q.A. team&quot;]fn add_negatives() &#123;    assert_eq!(add(-2, -2), -4)&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="测试模块"><a href="#测试模块" class="headerlink" title="测试模块"></a>测试模块</h3><p>大多数单元测试将进入带有<code>#[cfg(test)]</code> 属性的字模块</p><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">fn add(a: i32, b: i32) -&gt; i32 &#123;    a + b&#125;#[cfg(test)]mod add_function_tests &#123;    use super::*;    #[test]    fn add_works() &#123;        assert_eq!(add(1, 2), 3);        assert_eq!(add(10, 12), 22);        assert_eq!(add(5, -2), 3);    &#125;    #[test]    #[should_panic]    fn add_fails() &#123;        assert_eq!(add(2, 2), 7);    &#125;    #[test]    #[ignore]    fn add_negatives() &#123;        assert_eq!(add(-2, -2), -4)    &#125;&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><code>cfg</code> 属性负责控制条件编译，并仅会在谓词为<code>true</code> 时编译其所附带的内容。每当执行<code>cargo test</code> 命令时，Cargo都会自动发出<code>test</code> 编译标志，因此，当我们运行测试时，该标志将会始终为<code>true</code></p><p><code>use super::*;</code> 声明是<code>add_function_tests</code> 模块内部代码访问外部模块中<code>add</code> 的必要条件</p><h3 id="写入文档测试"><a href="#写入文档测试" class="headerlink" title="写入文档测试"></a>写入文档测试</h3><p>通过Rust，可以将文档示例作为测试来执行。记录Rust库的主要方式是使用三斜杠<code>///</code> 注释源代码，即熟知的文档注释。文档注释会写入到Markdown中，并支持其中的代码块，因此可以对这些代码块进行编译并将其用作测试</p><p>若要尝试此功能，需要先创建一个新的库项目</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">cargo</span> new <span class="token parameter variable">--lib</span> r20-test-doc<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><pre class="line-numbers language-Rust" data-language="Rust"><code class="language-Rust">&#x2F;&#x2F;&#x2F; Generally, the first line is a brief summary describing the function.&#x2F;&#x2F;&#x2F;&#x2F;&#x2F;&#x2F; The next lines present detailed documentation. &#x2F;&#x2F;&#x2F; Code blocks start with triple backticks. The code has an implicit &#96;fn main()&#96; inside and &#96;extern crate &lt;cratename&gt;&#96;,  &#x2F;&#x2F;&#x2F; which means you can just start writing code.&#x2F;&#x2F;&#x2F;&#x2F;&#x2F;&#x2F; &#96;&#96;&#96;&#x2F;&#x2F;&#x2F; let result &#x3D; basic_math::add(2, 3);&#x2F;&#x2F;&#x2F; assert_eq!(result, 5);&#x2F;&#x2F;&#x2F; &#96;&#96;&#96;pub fn add(a: i32, b: i32) -&gt; i32 &#123;    a + b&#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>与单元测试一样，如果文档测试未在运行时崩溃，则表示其顺利通过。若要验证某些结果，使用<code>aeert!</code> 宏来验证实际输出是否与预期相同。可以通过命令<code>cargo test</code> 调用此代码的测试套件</p><h3 id="写入集成测试"><a href="#写入集成测试" class="headerlink" title="写入集成测试"></a>写入集成测试</h3><p>单元和文档测试提供了简洁具体的测试。 但是，将 Crate 作为一个整体测试也是一种好办法。 然后，我们可以确认 Crate 的各代码部分是否按预期一起运行</p><p>若要将 Crate 作为成体进行测试，可以使用集成测试。 Rust 测试套件支持这种类型的测试，该测试仅调用库的公共 API 包含的函数。 我们可以使用集成测试来检查代码在其他人员使用它时的工作情况</p><p>这些测试的独特之处在于它们存在于单独的目录和文件中，因此它们可以在外部对库代码进行测试。 使用 Cargo 运行集成测试时，请将测试放在“tests”目录中。 Cargo 会运行此目录中的每个源文件。 在项目目录中创建测试，级别与你的 src 目录相同</p><h2 id="闭包"><a href="#闭包" class="headerlink" title="闭包"></a>闭包</h2><h3 id="三种Fn-特征"><a href="#三种Fn-特征" class="headerlink" title="三种Fn 特征"></a>三种<code>Fn</code> 特征</h3><ul><li><p><code>FnOnce</code>,该类型的闭包会拿走被捕获变量的所有权</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">fn</span> <span class="token function-definition function">fn_once</span><span class="token operator">&lt;</span><span class="token class-name">F</span><span class="token operator">></span><span class="token punctuation">(</span>func<span class="token punctuation">:</span> <span class="token class-name">F</span><span class="token punctuation">)</span> <span class="token keyword">where</span>    <span class="token class-name">F</span><span class="token punctuation">:</span> <span class="token class-name">FnOnce</span><span class="token punctuation">(</span><span class="token keyword">usize</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token keyword">bool</span> <span class="token operator">+</span> <span class="token class-name">Copy</span><span class="token punctuation">,</span><span class="token punctuation">&#123;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"&#123;func(3)&#125;"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"&#123;func(4)&#125;"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><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">&#123;</span>    <span class="token keyword">let</span> x <span class="token operator">=</span> <span class="token macro property">vec!</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span>    <span class="token function">fn_once</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>z<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">&#123;</span>z <span class="token operator">==</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 punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>如果想强制闭包取得捕获变量的所有权,可以在参数列表前添加<code>move</code>关键字,这种用法通常用于闭包的生命周期大于捕获变量的生命周期,例如将闭包返回或移入其他线程</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>thread<span class="token punctuation">;</span><span class="token keyword">let</span> v <span class="token operator">=</span> <span class="token macro property">vec!</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">let</span> handle <span class="token operator">=</span> <span class="token namespace">thread<span class="token punctuation">::</span></span><span class="token function">spawn</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span><span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">&#123;</span>    <span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"Here's a vector: &#123;:?&#125;"</span><span class="token punctuation">,</span> v<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>handle<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><p><code>FnMut</code>,它以可变借用的方式捕获了环境中的值,因此可以修改该值</p></li></ul><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">fn_mut</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token keyword">let</span> <span class="token keyword">mut</span> s <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token comment">// mut,update_string可变闭包</span>    <span class="token keyword">let</span> <span class="token keyword">mut</span> update_string <span class="token operator">=</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span><span class="token keyword">str</span><span class="token closure-punctuation punctuation">|</span></span> s<span class="token punctuation">.</span><span class="token function">push_str</span><span class="token punctuation">(</span><span class="token keyword">str</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token function">update_string</span><span class="token punctuation">(</span><span class="token string">"hello"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"&#123;:?&#125;"</span><span class="token punctuation">,</span> s<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">fn_mut1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token keyword">let</span> <span class="token keyword">mut</span> s <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> update_string <span class="token operator">=</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span><span class="token keyword">str</span><span class="token closure-punctuation punctuation">|</span></span> s<span class="token punctuation">.</span><span class="token function">push_str</span><span class="token punctuation">(</span><span class="token keyword">str</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token comment">// 编译器会自动推导出update_string闭包的类型</span>    <span class="token function">exec</span><span class="token punctuation">(</span>update_string<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"&#123;:?&#125;"</span><span class="token punctuation">,</span> s<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token keyword">fn</span> <span class="token function-definition function">exec</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token punctuation">,</span> <span class="token class-name">F</span><span class="token punctuation">:</span> <span class="token class-name">FnMut</span><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 operator">></span><span class="token punctuation">(</span><span class="token keyword">mut</span> f<span class="token punctuation">:</span> <span class="token class-name">F</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token function">f</span><span class="token punctuation">(</span><span class="token string">"world"</span><span class="token punctuation">)</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li><code>Fn</code>特征,它以不可变借用的方式捕获环境中的值</li></ul><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">fn_1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token keyword">let</span> s <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">"hello"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> update_string <span class="token operator">=</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>chs<span class="token closure-punctuation punctuation">|</span></span> <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"&#123;&#125; &#123;&#125;"</span><span class="token punctuation">,</span> s<span class="token punctuation">,</span> chs<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token function">exec1</span><span class="token punctuation">(</span>update_string<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token keyword">fn</span> <span class="token function-definition function">exec1</span><span class="token operator">&lt;</span><span class="token class-name">F</span><span class="token punctuation">:</span> <span class="token class-name">Fn</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span><span class="token operator">></span><span class="token punctuation">(</span>f<span class="token punctuation">:</span> <span class="token class-name">F</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token function">f</span><span class="token punctuation">(</span><span class="token string">"world"</span><span class="token punctuation">.</span><span class="token function">to_string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="move和Fn"><a href="#move和Fn" class="headerlink" title="move和Fn"></a><code>move</code>和<code>Fn</code></h3><p>在上面,我们讲到了<code>move</code>关键字对于<code>FnOnce</code>特征的重要性,但实际上使用了<code>move</code>的闭包依然可能实现了<code>Fn</code>或<code>FnMut</code>特征</p><p>因此,一个闭包实现了哪种Fn特征取决于该闭包如何使用被捕获的变量,而不是取决于闭包如何捕获它们.move本身强调的就是后者,闭包如何捕获变量:</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><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">&#123;</span>    <span class="token keyword">let</span> s <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> update_string <span class="token operator">=</span>  <span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span><span class="token closure-punctuation punctuation">|</span></span> <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"&#123;&#125;"</span><span class="token punctuation">,</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token function">exec</span><span class="token punctuation">(</span>update_string<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token keyword">fn</span> <span class="token function-definition function">exec</span><span class="token operator">&lt;</span><span class="token class-name">F</span><span class="token punctuation">:</span> <span class="token class-name">FnOnce</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">></span><span class="token punctuation">(</span>f<span class="token punctuation">:</span> <span class="token class-name">F</span><span class="token punctuation">)</span>  <span class="token punctuation">&#123;</span>    <span class="token function">f</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>这个闭包中使用了move关键字,所以我们的闭包捕获了它,但是由于闭包对s的使用仅仅是不可变借用,因此该闭包实际上还实现了Fn特征.因为该闭包不仅仅实现了FnOnce特征</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><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">&#123;</span>    <span class="token keyword">let</span> s <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> update_string <span class="token operator">=</span>  <span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span><span class="token closure-punctuation punctuation">|</span></span> <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"&#123;&#125;"</span><span class="token punctuation">,</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token function">exec</span><span class="token punctuation">(</span>update_string<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token keyword">fn</span> <span class="token function-definition function">exec</span><span class="token operator">&lt;</span><span class="token class-name">F</span><span class="token punctuation">:</span> <span class="token class-name">Fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">></span><span class="token punctuation">(</span>f<span class="token punctuation">:</span> <span class="token class-name">F</span><span class="token punctuation">)</span>  <span class="token punctuation">&#123;</span>    <span class="token function">f</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="三种Fn的关系"><a href="#三种Fn的关系" class="headerlink" title="三种Fn的关系"></a>三种Fn的关系</h3><p>实际上,一个闭包并不仅仅实现某一种Fn特征,规则如下:</p><ul><li>所有的闭包都自动实现了FnOnce特征,因此任何一个闭包都至少可以被调用一次</li><li>没有移出所捕获变量的所有权的闭包自动实现了FnMut特征</li><li>不需要对捕获变量进行改变的闭包自动实现了Fn特征</li></ul><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">fn_all</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token keyword">let</span> s <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">"Hello"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> update_string <span class="token operator">=</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span><span class="token closure-punctuation punctuation">|</span></span> <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"&#123;&#125;"</span><span class="token punctuation">,</span> s<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token function">exec_fn</span><span class="token punctuation">(</span>update_string<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token function">exec_fn_once</span><span class="token punctuation">(</span>update_string<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token function">exec_fn_mut</span><span class="token punctuation">(</span>update_string<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token keyword">fn</span> <span class="token function-definition function">exec_fn_once</span><span class="token operator">&lt;</span><span class="token class-name">F</span><span class="token punctuation">:</span> <span class="token class-name">FnOnce</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">></span><span class="token punctuation">(</span>f<span class="token punctuation">:</span> <span class="token class-name">F</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token function">f</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#125;</span><span class="token keyword">fn</span> <span class="token function-definition function">exec_fn_mut</span><span class="token operator">&lt;</span><span class="token class-name">F</span><span class="token punctuation">:</span> <span class="token class-name">FnMut</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token keyword">mut</span> f<span class="token punctuation">:</span> <span class="token class-name">F</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token function">f</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#125;</span><span class="token keyword">fn</span> <span class="token function-definition function">exec_fn</span><span class="token operator">&lt;</span><span class="token class-name">F</span><span class="token punctuation">:</span> <span class="token class-name">Fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">></span><span class="token punctuation">(</span>f<span class="token punctuation">:</span> <span class="token class-name">F</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token function">f</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="闭包作为函数返回值"><a href="#闭包作为函数返回值" class="headerlink" title="闭包作为函数返回值"></a>闭包作为函数返回值</h3><p>需要加上<code>impl</code>,或者使用智能指针(如Box)包裹返回</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token comment">// 编译报错</span><span class="token keyword">fn</span> <span class="token function-definition function">factory</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span><span class="token keyword">i32</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token keyword">impl</span> <span class="token class-name">Fn</span><span class="token punctuation">(</span><span class="token keyword">i32</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token keyword">i32</span> <span class="token punctuation">&#123;</span>    <span class="token keyword">let</span> num <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span>    <span class="token keyword">if</span> x <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">&#123;</span>        <span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>x<span class="token closure-punctuation punctuation">|</span></span> x <span class="token operator">+</span> num    <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>        <span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>x<span class="token closure-punctuation punctuation">|</span></span> x <span class="token operator">-</span> num    <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span class="token comment">// 改正</span><span class="token keyword">fn</span> <span class="token function-definition function">factory</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span><span class="token keyword">i32</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token class-name">Box</span><span class="token operator">&lt;</span><span class="token keyword">dyn</span> <span class="token class-name">Fn</span><span class="token punctuation">(</span><span class="token keyword">i32</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token keyword">i32</span><span class="token operator">></span> <span class="token punctuation">&#123;</span>    <span class="token keyword">let</span> num <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span>    <span class="token keyword">if</span> x <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">&#123;</span>        <span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>x<span class="token closure-punctuation punctuation">|</span></span> x <span class="token operator">+</span> num    <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>        <span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>x<span class="token closure-punctuation punctuation">|</span></span> x <span class="token operator">-</span> num    <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="迭代器-1"><a href="#迭代器-1" class="headerlink" title="迭代器"></a>迭代器</h2><h3 id="Iterator-和-IntoIterator的区别"><a href="#Iterator-和-IntoIterator的区别" class="headerlink" title="Iterator 和 IntoIterator的区别"></a>Iterator 和 IntoIterator的区别</h3><p>这两个其实很容易搞混.</p><p><code>Iterator</code>就是迭代器特征,只有实现了它才能成为迭代器,才能调用<code>next</code></p><p><code>IntoIterator</code>强调的是某一个类型如果实现了该特征,它可以通过<code>into_iter</code>, <code>iter</code>等方法变成一个迭代器</p><h3 id="消费者与适配器"><a href="#消费者与适配器" class="headerlink" title="消费者与适配器"></a>消费者与适配器</h3><p>消费者是迭代器上的方法,它会消费掉迭代器中的元素,然后返回其类型的值,这些消费者都是有一个共同的特点:在它们的定义中,都依赖<code>next</code>方法来消费元素,因此这也是为什么迭代器要实现<code>Iterator</code>特征,而该特征必须要实现<code>next</code>方法的原因</p><p><code>消费者适配器</code></p><p>只要迭代器上的某个方法A在其内部调用了<code>next</code>方法,那么A就被称为<code>消费性适配器</code>:因为<code>next</code>方法会消耗掉迭代器上的元素,所以方法A的调用也会消耗掉迭代器上的元素</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><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">&#123;</span>    <span class="token keyword">let</span> v1 <span class="token operator">=</span> <span class="token macro property">vec!</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> v1_iter <span class="token operator">=</span> v1<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 keyword">let</span> total<span class="token punctuation">:</span> <span class="token keyword">i32</span> <span class="token operator">=</span> v1_iter<span class="token punctuation">.</span><span class="token function">sum</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token macro property">assert_eq!</span><span class="token punctuation">(</span>total<span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token comment">// v1_iter 是借用了 v1，因此 v1 可以照常使用</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"&#123;:?&#125;"</span><span class="token punctuation">,</span>v1<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token comment">// 以下代码会报错，因为 `sum` 拿到了迭代器 `v1_iter` 的所有权</span>    <span class="token comment">// println!("&#123;:?&#125;",v1_iter);</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>如代码注释中所说明的:在使用<code>sum</code>方法后,我们将无法再使用<code>v1_iter</code>,因为<code>sum</code>拿走了该迭代器的所有权:</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">fn</span> <span class="token function-definition function">sum</span><span class="token operator">&lt;</span><span class="token class-name">S</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token class-name">S</span> <span class="token keyword">where</span>    <span class="token keyword">Self</span><span class="token punctuation">:</span> <span class="token class-name">Sized</span><span class="token punctuation">,</span>    <span class="token class-name">S</span><span class="token punctuation">:</span> <span class="token class-name">Sum</span><span class="token operator">&lt;</span><span class="token keyword">Self</span><span class="token punctuation">::</span><span class="token class-name">Item</span><span class="token operator">></span><span class="token punctuation">,</span><span class="token punctuation">&#123;</span>    <span class="token class-name">Sum</span><span class="token punctuation">::</span><span class="token function">sum</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">)</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><code>迭代器适配器</code></p><p>既然消费者适配器是消费掉迭代器,然后返回一个值.那么迭代器适配器,顾名思义,会返回一个新的迭代器,这是实现链式方式方法调用的关键: <code>v.iter().map().filter()...</code></p><p>与消费者适配器不同,迭代器适配器是惰性的,意味着需要一个消费者适配器来收尾,最终将迭代器转换成一个具体的值:</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">let</span> v1 <span class="token operator">=</span> <span class="token class-name">Vec</span><span class="token operator">&lt;</span><span class="token keyword">u32</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token macro property">vec!</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span>v1<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">map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>x<span class="token closure-punctuation punctuation">|</span></span> x <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 编译报错</span>warning<span class="token punctuation">:</span> unused `<span class="token class-name">Map</span>` that must be used <span class="token operator">-</span><span class="token punctuation">-></span> src<span class="token operator">/</span>main<span class="token punctuation">.</span>rs<span class="token punctuation">:</span><span class="token number">4</span><span class="token punctuation">:</span><span class="token number">5</span>  <span class="token operator">|</span><span class="token number">4</span> <span class="token operator">|</span>     v1<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">map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>x<span class="token closure-punctuation punctuation">|</span></span> x <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</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><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> note<span class="token punctuation">:</span> `<span class="token attribute attr-name">#[warn(unused_must_use)]</span>` on by default  <span class="token operator">=</span> note<span class="token punctuation">:</span> iterators are lazy and <span class="token keyword">do</span> nothing unless consumed <span class="token comment">// 迭代器 map 是惰性的，这里不产生任何效果</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>这里的<code>map</code>方法是一个迭代器适配器,它是惰性的,不产生任何行为,因此我们还需要一个消费者适配器进行收尾:</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">let</span> v1<span class="token punctuation">:</span> <span class="token class-name">Vec</span><span class="token operator">&lt;</span><span class="token keyword">i32</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token macro property">vec!</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">let</span> v2<span class="token punctuation">:</span> <span class="token class-name">Vec</span><span class="token operator">&lt;</span>_<span class="token operator">></span> <span class="token operator">=</span> v1<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">map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>x<span class="token closure-punctuation punctuation">|</span></span> x <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token macro property">assert_eq!</span><span class="token punctuation">(</span>v2<span class="token punctuation">,</span> <span class="token macro property">vec!</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><code>collect</code></p><p>上面代码中, 使用了<code>collect</code>方法,该方法就是一个消费者适配器, 使用它可以将一个迭代器中的元素收集到指定类型中, 这里我们为v2标注了<code>Vec&lt;_&gt;</code>类型,就是为了告诉<code>collect</code>: 请把迭代器中的元素消费掉, 然后把值收集成<code>Vec&lt;_&gt;</code>类型, 至于为何使用<code>_</code>, 因为编译器会帮我们自动推导</p><h2 id="智能指针"><a href="#智能指针" class="headerlink" title="智能指针"></a>智能指针</h2><p><code>堆栈</code></p><p>栈内存从高位地址向下增长，且栈内存是连续分配的</p><p>在 Rust 中，main 线程的栈大小是 8MB，普通线程是 2MB，在函数调用时会在其中创建一个临时栈空间，调用结束后 Rust 会让这个栈空间里的对象自动进入 Drop 流程，最后栈顶指针自动移动到上一个调用栈顶，无需程序员手动干预，因而栈内存申请和释放是非常高效的</p><p>与栈相反，堆上内存则是从低位地址向上增长，堆内存通常只受物理内存限制，而且通常是不连续的，因此从性能的角度看，栈往往比堆更高</p><p>相比其它语言，Rust 堆上对象还有一个特殊之处，它们都拥有一个所有者，因此受所有权规则的限制：当赋值时，发生的是所有权的转移（只需浅拷贝栈上的引用或智能指针即可），例如以下代码：</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><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">&#123;</span>    <span class="token keyword">let</span> b <span class="token operator">=</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token string">"world"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"&#123;&#125;"</span><span class="token punctuation">,</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token keyword">fn</span> <span class="token function-definition function">foo</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> <span class="token punctuation">-></span> <span class="token class-name">String</span> <span class="token punctuation">&#123;</span>    <span class="token keyword">let</span> a <span class="token operator">=</span> <span class="token string">"Hello, "</span><span class="token punctuation">.</span><span class="token function">to_string</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> x<span class="token punctuation">;</span>    a<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="堆栈的性能"><a href="#堆栈的性能" class="headerlink" title="堆栈的性能"></a>堆栈的性能</h3><p>很多人可能会觉得栈的性能肯定比堆高，其实未必。 由于我们在后面的性能专题会专门讲解堆栈的性能问题，因此这里就大概给出结论：</p><ul><li>小型数据，在栈上的分配性能和读取性能都要比堆上高</li><li>中型数据，栈上分配性能高，但是读取性能和堆上并无区别，因为无法利用寄存器或 CPU 高速缓存，最终还是要经过一次内存寻址</li><li>大型数据，只建议在堆上分配和使用</li></ul><h3 id="Box-的使用场景"><a href="#Box-的使用场景" class="headerlink" title="Box 的使用场景"></a>Box 的使用场景</h3><p>由于 Box 是简单的封装，除了将值存储在堆上外，并没有其它性能上的损耗。而性能和功能往往是鱼和熊掌，因此 Box 相比其它智能指针，功能较为单一，可以在以下场景中使用它：</p><ul><li>特意的将数据分配在堆上</li><li>数据较大时，又不想在转移所有权时进行数据拷贝</li><li>类型的大小在编译期无法确定，但是我们又需要固定大小的类型时</li><li>特征对象，用于说明对象实现了一个特征，而不是某个特定的类型</li></ul><h2 id="Drop"><a href="#Drop" class="headerlink" title="Drop"></a>Drop</h2><p><code>互斥的Copy和Drop</code></p><p>我们无法为一个类型同时实现<code>Copy</code> 和<code>Drop</code> 特征. 因为实现了<code>Copy</code> 的特征会被编译器隐式的复制, 因此非常难以预测析构函数执行的时间和频率. 因此这些实现了<code>Copy</code> 的类型无法拥有析构函数</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token attribute attr-name">#[derice(Debug)]</span><span class="token keyword">struct</span> <span class="token type-definition class-name">Foo</span><span class="token punctuation">;</span><span class="token keyword">impl</span> <span class="token class-name">Drop</span> <span class="token keyword">for</span> <span class="token class-name">Foo</span> <span class="token punctuation">&#123;</span>    <span class="token keyword">fn</span> <span class="token function-definition function">drop</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>        <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"Deopping Foo!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>以上代码报错如下:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">error<span class="token punctuation">[</span>E0184<span class="token punctuation">]</span>: the trait <span class="token variable"><span class="token variable">`</span>Copy<span class="token variable">`</span></span> may not be implemented <span class="token keyword">for</span> this <span class="token builtin class-name">type</span><span class="token punctuation">;</span> the <span class="token builtin class-name">type</span> has a destructor  --<span class="token operator">></span> src/main.rs:24:10   <span class="token operator">|</span><span class="token number">24</span> <span class="token operator">|</span> <span class="token comment">#[derive(Copy)]</span>   <span class="token operator">|</span>          ^^^^ Copy not allowed on types with destructors<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="关于Rc的简单总结"><a href="#关于Rc的简单总结" class="headerlink" title="关于Rc的简单总结"></a>关于Rc的简单总结</h2><ul><li>Rc&#x2F;Arc 是不可变引用, 无法修改它指向的值, 只能进行读取, 如果要修改, 需要配合内部可变性RefCell 或互斥锁Mutex</li><li>一旦最后一个拥有者消失, 则资源会自动被回收, 这个生命周期是在编译器就确定下来的</li><li>Rc 只能用于同一线程内部, 想要用于线程之间的对象共享, 需要使用Arc</li><li>Rc<T> 是一个智能指针, 实现了Deref 特征, 因此无需先解开Rc 指针, 再使用里面的T, 而是可以直接使用T</li></ul><h2 id="Arc的性能损耗"><a href="#Arc的性能损耗" class="headerlink" title="Arc的性能损耗"></a>Arc的性能损耗</h2><p>原子化可以带来线程安全, 但是都会伴随着性能损耗, 而且这种性能损耗还不小</p><h2 id="Cell"><a href="#Cell" class="headerlink" title="Cell"></a>Cell</h2><p>Cell 和 RefCell 在功能上没有区别，区别在于 Cell<T> 适用于 T 实现 Copy 的情况:</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>cell<span class="token punctuation">::</span></span><span class="token class-name">Cell</span><span class="token punctuation">;</span><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">&#123;</span>  <span class="token keyword">let</span> c <span class="token operator">=</span> <span class="token class-name">Cell</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token string">"asdf"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token keyword">let</span> one <span class="token operator">=</span> c<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  c<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"qwer"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token keyword">let</span> two <span class="token operator">=</span> c<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"&#123;&#125;,&#123;&#125;"</span><span class="token punctuation">,</span> one<span class="token punctuation">,</span> two<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><code>注意:</code></p><p><code>Cell</code> 智能指针跟上面笔记的智能指针有点不太一样的用法, 如例子所示, 获取指针的值是使用<code>get</code>, 设置指针的值是使用<code>set</code></p><p>而且获取到值之后还可以设置值? 这个貌似是违背了Rust的借用规则? (应该是的(bushi))</p><h3 id="通过Cell-from-mut解决借用冲突"><a href="#通过Cell-from-mut解决借用冲突" class="headerlink" title="通过Cell::from_mut解决借用冲突"></a>通过Cell::from_mut解决借用冲突</h3><p>在Rust1.37版本中新增了两个非常使用的方法:</p><ul><li>Cell::from_mut，该方法将 &amp;mut T 转为 &amp;Cell<T></li><li>Cell::as_slice_of_cells，该方法将 &amp;Cell&lt;[T]&gt; 转为 &amp;[Cell<T>]<pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">fn</span> <span class="token function-definition function">is_even</span><span class="token punctuation">(</span>i<span class="token punctuation">:</span> <span class="token keyword">i32</span><span class="token punctuation">)</span> <span class="token punctuation">-></span> <span class="token keyword">bool</span> <span class="token punctuation">&#123;</span>    i <span class="token operator">%</span> <span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">&#125;</span><span class="token keyword">fn</span> <span class="token function-definition function">retain_even</span><span class="token punctuation">(</span>nums<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token class-name">Vec</span><span class="token operator">&lt;</span><span class="token keyword">i32</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token keyword">let</span> <span class="token keyword">mut</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>    <span class="token keyword">for</span> num <span class="token keyword">in</span> nums<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">filter</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span><span class="token operator">&amp;</span>num<span class="token closure-punctuation punctuation">|</span></span> <span class="token function">is_even</span><span class="token punctuation">(</span><span class="token operator">*</span>num<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>        nums<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token operator">*</span>num<span class="token punctuation">;</span>        i <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>    nums<span class="token punctuation">.</span><span class="token function">truncate</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token comment">// 解决办法</span><span class="token keyword">fn</span> <span class="token function-definition function">retain_even</span><span class="token punctuation">(</span>nums<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token class-name">Vec</span><span class="token operator">&lt;</span><span class="token keyword">i32</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token keyword">let</span> <span class="token keyword">mut</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>    <span class="token keyword">for</span> j <span class="token keyword">in</span> <span class="token number">0</span><span class="token punctuation">..</span>nums<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">&#123;</span>        <span class="token keyword">if</span> <span class="token function">is_even</span><span class="token punctuation">(</span>nums<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>            nums<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> nums<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span>            i <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span>        <span class="token punctuation">&#125;</span>    <span class="token punctuation">&#125;</span>    nums<span class="token punctuation">.</span><span class="token function">truncate</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token comment">// Cell解决</span><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>cell<span class="token punctuation">::</span></span><span class="token class-name">Cell</span><span class="token punctuation">;</span><span class="token keyword">fn</span> <span class="token function-definition function">retain_even</span><span class="token punctuation">(</span>nums<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token class-name">Vec</span><span class="token operator">&lt;</span><span class="token keyword">i32</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token keyword">let</span> slice<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token punctuation">[</span><span class="token class-name">Cell</span><span class="token operator">&lt;</span><span class="token keyword">i32</span><span class="token operator">></span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token class-name">Cell</span><span class="token punctuation">::</span><span class="token function">from_mut</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> nums<span class="token punctuation">[</span><span class="token punctuation">..</span><span class="token punctuation">]</span><span class="token punctuation">)</span>        <span class="token punctuation">.</span><span class="token function">as_slice_of_cells</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> <span class="token keyword">mut</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>    <span class="token keyword">for</span> num <span class="token keyword">in</span> slice<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">filter</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>num<span class="token closure-punctuation punctuation">|</span></span> <span class="token function">is_even</span><span class="token punctuation">(</span>num<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>        slice<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>num<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        i <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>    nums<span class="token punctuation">.</span><span class="token function">truncate</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul><h2 id="RefCell"><a href="#RefCell" class="headerlink" title="RefCell"></a>RefCell</h2><p>由于 Cell 类型针对的是实现了 Copy 特征的值类型，因此在实际开发中，Cell 使用的并不多，因为我们要解决的往往是可变、不可变引用共存导致的问题，此时就需要借助于 RefCell 来达成目的</p><p>所有权, 借用规则与智能指针的对比:</p><table><thead><tr><th>Rust规则</th><th>智能指针带来的额外规则</th></tr></thead><tbody><tr><td>一个数据只有一个所有者</td><td><code>Rc/Arc</code> 让一个数据可以拥有多个所有者</td></tr><tr><td>要么多个不可变借用, 要么一个可变借用</td><td><code>RefCell</code> 实现编译器可变, 不可变引用共存</td></tr><tr><td>违背规则导致编译错误</td><td>违背规则导致运行时<code>panic</code></td></tr></tbody></table><p>可以看出, <code>Rc/Arc</code> 和<code>RefCell</code> 合在一起, 解决了Rust中严苛的所有权和借用规则带来的某些场景下难使用的问题. 但是它们并不是银弹, 例如<code>RefCell</code> 实际上并没有解决可变引用和不可变引用共存的问题, 只是将报错从编译期推迟到运行时, 从编译器错误变成了<code>panic</code> 异常:</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>cell<span class="token punctuation">::</span></span><span class="token class-name">RefCell</span><span class="token punctuation">;</span><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">&#123;</span>    <span class="token keyword">let</span> s <span class="token operator">=</span> <span class="token class-name">RefCell</span><span class="token punctuation">::</span><span class="token function">new</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">"hello, world"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> s1 <span class="token operator">=</span> s<span class="token punctuation">.</span><span class="token function">borrow</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> s2 <span class="token operator">=</span> s<span class="token punctuation">.</span><span class="token function">borrow_mut</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"&#123;&#125;,&#123;&#125;"</span><span class="token punctuation">,</span> s1<span class="token punctuation">,</span> s2<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">thread <span class="token string">'main'</span> panicked at <span class="token string">'already borrowed: BorrowMutError'</span>, src/main.rs:6:16note: run with <span class="token variable"><span class="token variable">`</span><span class="token assign-left variable">RUST_BACKTRACE</span><span class="token operator">=</span><span class="token number">1</span><span class="token variable">`</span></span> environment variable to display a backtrace<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>但是依然会因为违背了借用规则导致了运行期<code>panic</code></p><p>当确信编译器误报但不知道如何解决时, 或者有一个引用类型, 需要被四处使用和修改然后导致借用关系难以管理时, 可以优先考虑使用<code>RefCell</code></p><h3 id="RefCell简单总结"><a href="#RefCell简单总结" class="headerlink" title="RefCell简单总结"></a>RefCell简单总结</h3><ul><li>与Cell用于可Copy的值不同, RefCell用于引用</li><li>RefCell只是将借用规则从编译期推迟到程序运行期, 并不能帮你绕过这个规则</li><li>RefCell适用于编译期误报或者一个引用被在多处代码使用, 修改以至于难于管理借用关系时</li><li>使用RefCell时, 违背借用规则会导致运行期的panic</li></ul><h3 id="选择Cell还是RefCell"><a href="#选择Cell还是RefCell" class="headerlink" title="选择Cell还是RefCell"></a>选择Cell还是RefCell</h3><ul><li>Cell只适用于Copy类型, 用于提供值, 而RefCell用于提供引用</li><li>Cell不会panic, 而RefCell会</li></ul><h3 id="Rc-RefCell组合使用"><a href="#Rc-RefCell组合使用" class="headerlink" title="Rc + RefCell组合使用"></a>Rc + RefCell组合使用</h3><p>在Rust中, 一个常见的组合就是Rc 和RefCell 在一起使用, 前者可以实现一个数据拥有多个所有者, 后者可以实现数据的可变性: </p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>cell<span class="token punctuation">::</span></span><span class="token class-name">RefCell</span><span class="token punctuation">;</span><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>rc<span class="token punctuation">::</span></span><span class="token class-name">Rc</span><span class="token punctuation">;</span><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">&#123;</span>    <span class="token keyword">let</span> s <span class="token operator">=</span> <span class="token class-name">Rc</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token class-name">RefCell</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token string">"我很善变，还拥有多个主人"</span><span class="token punctuation">.</span><span class="token function">to_string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> s1 <span class="token operator">=</span> s<span class="token punctuation">.</span><span class="token function">clone</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> s2 <span class="token operator">=</span> s<span class="token punctuation">.</span><span class="token function">clone</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token comment">// let mut s2 = s.borrow_mut();</span>    s2<span class="token punctuation">.</span><span class="token function">borrow_mut</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">push_str</span><span class="token punctuation">(</span><span class="token string">", oh yeah!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"&#123;:?&#125;\n&#123;:?&#125;\n&#123;:?&#125;"</span><span class="token punctuation">,</span> s<span class="token punctuation">,</span> s1<span class="token punctuation">,</span> s2<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="CPU损耗"><a href="#CPU损耗" class="headerlink" title="CPU损耗"></a>CPU损耗</h3><ul><li>对 Rc<T> 解引用是免费的（编译期），但是 * 带来的间接取值并不免费</li><li>克隆 Rc<T> 需要将当前的引用计数跟 0 和 usize::Max 进行一次比较，然后将计数值加 1</li><li>释放（drop） Rc<T> 需要将计数值减 1， 然后跟 0 进行一次比较</li><li>对 RefCell 进行不可变借用，需要将 isize 类型的借用计数加 1，然后跟 0 进行比较</li><li>对 RefCell 的不可变借用进行释放，需要将 isize 减 1</li><li>对 RefCell 的可变借用大致流程跟上面差不多，但是需要先跟 0 比较，然后再减 1</li><li>对 RefCell 的可变借用进行释放，需要将 isize 加 1</li></ul><h2 id="多线程并发编程"><a href="#多线程并发编程" class="headerlink" title="多线程并发编程"></a>多线程并发编程</h2><h3 id="CPU多核"><a href="#CPU多核" class="headerlink" title="CPU多核"></a>CPU多核</h3><p>并行一定是并发, 反之并发只有在多核时才可能并行</p><h4 id="单核心并发"><a href="#单核心并发" class="headerlink" title="单核心并发"></a>单核心并发</h4><p>关键在于: 快速轮换处理不同的任务, 给用户带来所有任务同时在运行的假象</p><h4 id="多核心并行"><a href="#多核心并行" class="headerlink" title="多核心并行"></a>多核心并行</h4><p>当CPU核心增多到N时, 那么同一时间就能有N个任务被处理, 那么我们的并行度就是N, 相应的处理效率也就变成了单核心的N倍(实际情况并没有这么高)</p><h4 id="多核心并发"><a href="#多核心并发" class="headerlink" title="多核心并发"></a>多核心并发</h4><p>当核心增多到N时, 操作系统同时进行的任务肯定远不止N个, 这些任务将被放入M个线程队列中, 接着交给N个CPU核心去执行, 最后实现了M:N的处理模型, 在这种情况下, <code>并发与并行是同时发生的, 所有用户任务从表面来看都是并发的运行, 但实际上, 同一时刻只有N个任务能被同时并行的处理</code></p><ul><li>如果某个系统支持两个或多个动作的<code>同时存在</code>, 那么这个系统就是一个并发系统</li><li>如果某个系统支持两个或多个动作的<code>同时执行</code>, 那么这个系统就是一个并行系统</li></ul><p>在并发程序中可以同时拥有两个或多个线程. 这意味着, 如果程序在单核处理器上运行, 那么这两个线程将交替地换入或换出内存. 这些线程是<code>同时&quot;存在&quot;</code>的 – 每个线程都是处于执行过程中的某个状态. 如果程序能够并行执行, 那么就一定是运行在多核处理器上. 此时, 程序中的每个线程都将分配到一个独立的处理器核心上, 因此可以同时运行</p><p>所以, <code>&quot;并行&quot;概念是&quot;并发&quot;概念的一个子集</code>. 也就是说, 编写一个拥有多线程或者进程的并发程序, 但如果没有多核处理器来执行这个程序, 那么就不能以并行的方式运行代码. 因此, 凡是在求解单个问题时涉及多个执行流程的编程模式或者执行行为, 都属于并发编程的范畴</p><h3 id="编程语言的并发模型"><a href="#编程语言的并发模型" class="headerlink" title="编程语言的并发模型"></a>编程语言的并发模型</h3><ul><li>由于操作系统提供了创建线程的API, 因此部分语言会直接调用该API来创建线程, 因此最终程序内的线程和该程序占用的操作系统线程相等, 一般称之为1:1线程模型, 例如Rust</li><li>还有些语言的内部实现了自己的线程模型(绿色线程, 协程), 程序内部的M个线程最后会以某种隐射方式使用N个操作系统线程去运行, 因此称之为M:N现成模型, 其中M和N并没有特定的彼此限制关系. 一个典型的代表就是Go语言</li><li>还有写语言使用了Actor模型, 基于消息传递进行并行, 例如Erlang语言</li></ul><p>绿色线程&#x2F;协程的视线会显著增大运行时的大小, 因此Rust只在标准库中提供了1:1的线程模型, 如果你愿意牺牲一些性能来换取更精确的线程控制以及更小的线程上下文切换成本, 那么可以使用Rust中的M:N模型, 这些模型由三方库提供了实现, 例如大名鼎鼎的tokio</p><h3 id="使用线程"><a href="#使用线程" class="headerlink" title="使用线程"></a>使用线程</h3><p>由于多线程的代码是同时运行的，因此我们无法保证线程间的执行顺序，这会导致一些问题：</p><ul><li>竞态条件(race conditions)，多个线程以非一致性的顺序同时访问数据资源</li><li>死锁(deadlocks)，两个线程都想使用某个资源，但是又都在等待对方释放资源后才能使用，结果最终都无法继续执行</li><li>一些因为多线程导致的很隐晦的 BUG，难以复现和解决</li></ul><h4 id="多线程的性能"><a href="#多线程的性能" class="headerlink" title="多线程的性能"></a>多线程的性能</h4><h5 id="创建线程的性能"><a href="#创建线程的性能" class="headerlink" title="创建线程的性能"></a>创建线程的性能</h5><p>据不精确估算, 创建一个线程大概需要0.24毫秒, 随着线程的变多, 这个值会变得更大, 因此线程的创建耗时是不可忽略的, 只有当真的需要处理一个值得用线程去处理的任务时, 才使用线程, 一些鸡毛蒜皮的任务, 就无需创建线程了</p><h5 id="创建多少线程合适"><a href="#创建多少线程合适" class="headerlink" title="创建多少线程合适"></a>创建多少线程合适</h5><p>因为CPU的核心数限制, 当任务是CPU密集型时, 就算线程数超过CPU核心数, 也并不能帮你获得更好的性能, 因为每个线程的任务都可以轻松让CPU的某个核心跑满, 既然如此, 让线程数等于CPU核心数是最好的</p><p>但是当你的任务大部分时间都处于阻塞状态时, 就可以考虑增加多线程数量, 这样当某个线程处于阻塞状态时, 会被切走, 进而运行其它的线程, 典型就是网络IO操作, 我们可以为每一个进来的用户连接创建一个线程去处理, 该连接绝大部分时间都是处于IO读取阻塞状态, 因此有限的CPU核心完全可以处理成百上千的用户连接线程, 但是事实上, 对于这种网络IO情况, 一般都不再使用多线程的方式了, 毕竟操作系统的线程数是有限的, 意味着并发数也很容易达到上限, 而且过多的线程也会导致线程上下文切换的代价过大, 使用<code>async/await</code>的<code>M:N</code> 并发模型, 就没有这个烦恼</p><h5 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h5><p>Rust 的线程模式是1:1模型, 因为Rust要保持尽量小的运行时</p><p>使用thread::spawn来创建线程, 创建出的多个线程之间并不存在执行顺序关系, 因此代码逻辑千万不要依赖于线程间的执行顺序</p><p>main 线程若是结束, 则所有子线程都将被终止, 如果希望等待子线程结束后, 再结束main 线程, 需要使用创建线程时返回的句柄join 方法</p><p>在线程中无法直接借用外部环境中的变量值, 因为新线程的启动时间和结束时间点是不确定的, 所以Rust 无法保证该线程中借用的变量在使用过程中依然是合法的. 可以使用move 关键字将变量的所有权转移给新的线程来解决此问题</p><p>父线程结束后, 子线程仍在持续运行, 直到子线程的代码运行完成或者main 线程的结束</p><h3 id="线程间的消息传递"><a href="#线程间的消息传递" class="headerlink" title="线程间的消息传递"></a>线程间的消息传递</h3><h4 id="多发送者-单接受者"><a href="#多发送者-单接受者" class="headerlink" title="多发送者, 单接受者"></a>多发送者, 单接受者</h4><p>标准库提供了通道<code>std::sync::mpsc</code>, 其中<code>mpsc</code> 是<code>multiple producer, single consumer</code> 的缩写, 代表了该通道支持多个发送者, 但是只支持唯一的接收者. 当然, 支持多个发送者也就意味着支持单个发送者</p><h3 id="同步和异步的通道"><a href="#同步和异步的通道" class="headerlink" title="同步和异步的通道"></a>同步和异步的通道</h3><p>Rust标准库的<code>mpsc</code> 通道其实氛围两种类型: 同步和异步</p><h4 id="异步通道"><a href="#异步通道" class="headerlink" title="异步通道"></a>异步通道</h4><p>上述的例子都是使用的异步通道: 无论接收者是否正在接收消息, 消息发送者在发送消息的时候都不会阻塞</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>sync<span class="token punctuation">::</span></span>mpsc<span class="token punctuation">;</span><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>thread<span class="token punctuation">;</span><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>time<span class="token punctuation">::</span></span><span class="token class-name">Duration</span><span class="token punctuation">;</span><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">&#123;</span>    <span class="token keyword">let</span> <span class="token punctuation">(</span>tx<span class="token punctuation">,</span> rx<span class="token punctuation">)</span><span class="token operator">=</span> <span class="token namespace">mpsc<span class="token punctuation">::</span></span><span class="token function">channel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> handle <span class="token operator">=</span> <span class="token namespace">thread<span class="token punctuation">::</span></span><span class="token function">spawn</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span><span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">&#123;</span>        <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"发送之前"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        tx<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"发送之后"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"睡眠之前"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token namespace">thread<span class="token punctuation">::</span></span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token class-name">Duration</span><span class="token punctuation">::</span><span class="token function">from_secs</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"睡眠之后"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"receive &#123;&#125;"</span><span class="token punctuation">,</span> rx<span class="token punctuation">.</span><span class="token function">recv</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    handle<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="同步通道"><a href="#同步通道" class="headerlink" title="同步通道"></a>同步通道</h4><p>与异步通道相反, 同步通道发送消息是阻塞的, 只有在消息被接收后才接触阻塞</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>sync<span class="token punctuation">::</span></span>mpsc<span class="token punctuation">;</span><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>thread<span class="token punctuation">;</span><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>time<span class="token punctuation">::</span></span><span class="token class-name">Duration</span><span class="token punctuation">;</span><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">&#123;</span>    <span class="token keyword">let</span> <span class="token punctuation">(</span>tx<span class="token punctuation">,</span> rx<span class="token punctuation">)</span><span class="token operator">=</span> <span class="token namespace">mpsc<span class="token punctuation">::</span></span><span class="token function">sync_channel</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> handle <span class="token operator">=</span> <span class="token namespace">thread<span class="token punctuation">::</span></span><span class="token function">spawn</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span><span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">&#123;</span>        <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"发送之前"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        tx<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"发送之后"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"睡眠之前"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token namespace">thread<span class="token punctuation">::</span></span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token class-name">Duration</span><span class="token punctuation">::</span><span class="token function">from_secs</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"睡眠之后"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"receive &#123;&#125;"</span><span class="token punctuation">,</span> rx<span class="token punctuation">.</span><span class="token function">recv</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    handle<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="传输多种类型的数据"><a href="#传输多种类型的数据" class="headerlink" title="传输多种类型的数据"></a>传输多种类型的数据</h3><p>可以使用枚举来实现</p><p>但是有一点需要注意, Rust会按照枚举中占用内存最大的那个成员进行内存对齐, 这意味着就算传输的是枚举占用内存最小的成员, 它占用的内存依然和最大的成员相同, 因此会造成内存上的浪费</p><h2 id="线程同步-锁-Condvar和信号量"><a href="#线程同步-锁-Condvar和信号量" class="headerlink" title="线程同步: 锁, Condvar和信号量"></a>线程同步: 锁, Condvar和信号量</h2><p>共享内存可以说是同步的灵魂, 因为消息传递的底层实际上也是通过共享内存来实现, 两者区别:</p><ul><li>共享内存相对消息传递能节省多次内存拷贝的成本</li><li>共享内存的实现简洁的多</li><li>共享内存的锁竞争更多</li></ul><p>消息传递适用的场景很多: </p><ul><li>需要可靠和简单的(简单不等于简洁)实现时</li><li>需要模拟现实世界, 例如用消息去通知某个目标执行相应的操作时</li><li>需要一个任务处理流水线(管道)时, 等等</li></ul><p>而使用共享内存(并发原语)的场景往往就比较简单粗暴: 需要简洁的实现以及更高的性能时</p><p>总之, 消息传递类似一个单所有权的系统: 一个值同时只能有一个所有者, 如果另一个线程需要该值的所有权, 需要将所有权通过消息传递进行转移. 而共享内存类似于一个多所有权的系统: 多个线程可以同时访问同一个值</p><h3 id="互斥锁Mutex"><a href="#互斥锁Mutex" class="headerlink" title="互斥锁Mutex"></a>互斥锁Mutex</h3><p>互斥锁Mutex(mutual exclusion)</p><p>Mutex让多个线程并发的访问同一个值变成了排队访问: 同一时间, 只允许一个线程A 访问该值, 其他线程需要等待A 访问完成之后才能继续</p><p>单线程中使用Mutex:</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>sync<span class="token punctuation">::</span></span><span class="token class-name">Mutex</span><span class="token punctuation">;</span><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">&#123;</span>    <span class="token comment">// 使用`Mutex`结构体的关联函数创建新的互斥锁实例</span>    <span class="token keyword">let</span> m <span class="token operator">=</span> <span class="token class-name">Mutex</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">&#123;</span>        <span class="token comment">// 获取锁，然后deref为`m`的引用</span>        <span class="token comment">// lock返回的是Result</span>        <span class="token keyword">let</span> <span class="token keyword">mut</span> num <span class="token operator">=</span> m<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token operator">*</span>num <span class="token operator">=</span> <span class="token number">6</span><span class="token punctuation">;</span>        <span class="token comment">// 锁自动被drop</span>    <span class="token punctuation">&#125;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"m = &#123;:?&#125;"</span><span class="token punctuation">,</span> m<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>多线程中使用Mutex:</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>sync<span class="token punctuation">::</span></span><span class="token punctuation">&#123;</span><span class="token class-name">Arc</span><span class="token punctuation">,</span> <span class="token class-name">Mutex</span><span class="token punctuation">&#125;</span><span class="token punctuation">;</span><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>thread<span class="token punctuation">;</span><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">&#123;</span>    <span class="token keyword">let</span> counter <span class="token operator">=</span> <span class="token class-name">Arc</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token class-name">Mutex</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">let</span> <span class="token keyword">mut</span> handles <span class="token operator">=</span> <span class="token macro property">vec!</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>    <span class="token keyword">for</span> _ <span class="token keyword">in</span> <span class="token number">0</span><span class="token punctuation">..</span><span class="token number">10</span> <span class="token punctuation">&#123;</span>        <span class="token keyword">let</span> counter <span class="token operator">=</span> <span class="token class-name">Arc</span><span class="token punctuation">::</span><span class="token function">clone</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>counter<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">let</span> handle <span class="token operator">=</span> <span class="token namespace">thread<span class="token punctuation">::</span></span><span class="token function">spawn</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span><span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">&#123;</span>            <span class="token keyword">let</span> <span class="token keyword">mut</span> num <span class="token operator">=</span> counter<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token operator">*</span>num <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span>        <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        handles<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>handle<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>    <span class="token keyword">for</span> handle <span class="token keyword">in</span> handles <span class="token punctuation">&#123;</span>        handle<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"Result: &#123;&#125;"</span><span class="token punctuation">,</span> <span class="token operator">*</span>counter<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="内部可变性"><a href="#内部可变性" class="headerlink" title="内部可变性"></a>内部可变性</h4><p>Rc<T> 和 RefCell<T>的结合, 可以实现单线程的内部可变性</p><p>由于Mutex<T> 可以支持修改内部数据, 当结合Arc<T> 一起使用, 可以实现多线程的内部可变性</p><p>简单总结: Rc<T>&#x2F;RefCell<T> 用于单线程内部可变性, Arc<T>&#x2F;Mutex<T> 用于多线程内部可变性</p><h4 id="需要小心使用Mutex"><a href="#需要小心使用Mutex" class="headerlink" title="需要小心使用Mutex"></a>需要小心使用Mutex</h4><ul><li>在使用数据前必须先获取锁</li><li>在数据使用完成后, 必须及时的释放锁, 比如文章开头的例子, 使用内部语句块的目的就是为了及时释放锁</li></ul><h3 id="读写锁RwLock"><a href="#读写锁RwLock" class="headerlink" title="读写锁RwLock"></a>读写锁RwLock</h3><p>Mutex 会对每次读写都进行加锁, 但某些时候, 我们需要大量的并发读, Mutex 就无法满足需求, 此时就可以使用RwLock</p><pre class="line-numbers language-rust" data-language="rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>sync<span class="token punctuation">::</span></span><span class="token class-name">RwLock</span><span class="token punctuation">;</span><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">&#123;</span>    <span class="token keyword">let</span> lock <span class="token operator">=</span> <span class="token class-name">RwLock</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token comment">// 同一时间允许多个读</span>    <span class="token punctuation">&#123;</span>        <span class="token keyword">let</span> r1 <span class="token operator">=</span> lock<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">let</span> r2 <span class="token operator">=</span> lock<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token macro property">assert_eq!</span><span class="token punctuation">(</span><span class="token operator">*</span>r1<span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token macro property">assert_eq!</span><span class="token punctuation">(</span><span class="token operator">*</span>r2<span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span> <span class="token comment">// 读锁在此处被drop</span>    <span class="token comment">// 同一时间只允许一个写</span>    <span class="token punctuation">&#123;</span>        <span class="token keyword">let</span> <span class="token keyword">mut</span> w <span class="token operator">=</span> lock<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token operator">*</span>w <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span>        <span class="token macro property">assert_eq!</span><span class="token punctuation">(</span><span class="token operator">*</span>w<span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token comment">// 以下代码会阻塞发生死锁，因为读和写不允许同时存在</span>        <span class="token comment">// 写锁w直到该语句块结束才被释放，因此下面的读锁依然处于`w`的作用域中</span>        <span class="token comment">// let r1 = lock.read();</span>        <span class="token comment">// println!("&#123;:?&#125;",r1);</span>    <span class="token punctuation">&#125;</span><span class="token comment">// 写锁在此处被drop</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>同时允许多个读, 但是最多只能有一个写</li><li>读和写不能同时存在</li><li>读可以使用<code>read</code> <code>try_read</code>, 写<code>write</code> <code>try_write</code>, 在实际项目中, <code>try_xxx</code> 会安全很多</li></ul><h3 id="Mutex还是RwLock"><a href="#Mutex还是RwLock" class="headerlink" title="Mutex还是RwLock"></a>Mutex还是RwLock</h3><p>首先简单性上Mutex完胜, 因为使用RwLock得操心几个问题:</p><ul><li>读和写不能同时发生, 如果使用try_xxx解决, 就必须做大量的错误处理和失败重试机制</li><li>当读多写少时, 写操作可能会因为一直无法获得锁导致连续失败多次(Write starvation)</li><li>RwLock其实是操作系统提供的, 实现原理要比Mutex复杂得多, 因此单就锁的性能而言, 比不上原生实现的Mutex</li></ul><p>再来简单总结下两者的使用场景:</p><ul><li>追求高并发读取时, 使用RwLock, 因为Mutex一次只允许一个线程去读取</li><li>如果要保证写操作的成功性, 使用Mutex</li><li>不知道哪个适合, 统一使用Mutex</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Rust网页版ide&quot;&gt;&lt;a href=&quot;#Rust网页版ide&quot; class=&quot;headerlink&quot; title=&quot;Rust网页版ide&quot;&gt;&lt;/a&gt;Rust网页版ide&lt;/h2&gt;&lt;p&gt;&lt;code&gt;https://play.rust-lang.org/&lt;/cod</summary>
      
    
    
    
    <category term="笔记" scheme="https://ccnuu.github.io/categories/%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Rust" scheme="https://ccnuu.github.io/tags/Rust/"/>
    
  </entry>
  
  <entry>
    <title>Git常用命令</title>
    <link href="https://ccnuu.github.io/2023/07/14/Git%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/"/>
    <id>https://ccnuu.github.io/2023/07/14/Git%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/</id>
    <published>2023-07-14T15:23:15.000Z</published>
    <updated>2026-04-09T02:26:43.057Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Git常用命令"><a href="#Git常用命令" class="headerlink" title="Git常用命令"></a>Git常用命令</h1><h2 id="基本使用"><a href="#基本使用" class="headerlink" title="基本使用"></a>基本使用</h2><ul><li>首次克隆项目<ul><li>git clone 地址 [-b 分支]</li></ul></li><li>查看分支<ul><li>git branch</li></ul></li><li>查看工作区代码相对于暂存区的差别<ul><li>git status</li></ul></li><li>将当前目录下修改的所有代码从工作区添加到暂存区 . 代表当前目录<ul><li>git add .</li></ul></li><li>将缓存区内容添加到本地仓库<ul><li>git commit  -m ‘注释’</li></ul></li><li>将本地版本库推送到远程服务器<ul><li>git push origin 分支</li></ul></li><li>合并分支<ul><li>git merge 分支</li></ul></li><li>查看远程仓库<ul><li>git remote -v</li></ul></li><li>从远程仓库获取最新版本到本地仓库<ul><li>git fetch origin master</li></ul></li><li>比较本地的仓库和远程参考的区别<ul><li>git log -p master.. origin&#x2F;master</li></ul></li><li>把远程下载下来的代码合并到本地仓库，远程的和本地的合并<ul><li>git merge origin&#x2F;master</li></ul></li></ul><h3 id="git-remote-HTTP-Basic-Access-denied"><a href="#git-remote-HTTP-Basic-Access-denied" class="headerlink" title="git remote: HTTP Basic: Access denied"></a>git remote: HTTP Basic: Access denied</h3><ul><li>原因：<ul><li>本地git配置的用户名、密码与gitlabs上注册的用户名、密码不一致</li></ul></li><li>解决：<ul><li>如果账号密码有变动 用这个命令 git config –system –unset credential.helper 重新输入账号密码 应该就能解决了</li><li>如果用了第一个命令 还不能解决问题那么 用这个命令：git config –global http.emptyAuth true</li><li>如果以上两个方法不起作用，那么采用以下方法：进入控制面板》用户账号》凭据管理器》windows凭据》普通凭据，在里面找到git，点开编辑密码，更新为最新密码之后就可以正常操作了</li></ul></li></ul><h3 id="git更新本地代码"><a href="#git更新本地代码" class="headerlink" title="git更新本地代码"></a>git更新本地代码</h3><ul><li><p>git status(查看本地分支文件信息，确保更新时不产生冲突)</p></li><li><p>git checkout - <a href="%E8%8B%A5%E6%96%87%E4%BB%B6%E6%9C%89%E4%BF%AE%E6%94%B9%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%BF%98%E5%8E%9F%E5%88%B0%E6%9C%80%E5%88%9D%E7%8A%B6%E6%80%81%EF%BC%9B%E8%8B%A5%E6%96%87%E4%BB%B6%E9%9C%80%E8%A6%81%E6%9B%B4%E6%96%B0%E5%88%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%EF%BC%8C%E5%BA%94%E8%AF%A5%E5%85%88merge%E5%88%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E5%86%8D%E6%9B%B4%E6%96%B0%E6%9C%AC%E5%9C%B0">file name</a></p></li><li><p>git branch(查看当前分支情况)</p></li><li><p>git checkout remote branch(若分支为本地分支，则需要切换到服务器远程分支)</p></li><li><p>git pull(若命令成功，则更新代码)</p></li><li><p>回退版本</p><ul><li>git log 显示提交日志</li><li>git reset –hard <id></li></ul></li></ul><h3 id="git生成密钥公钥"><a href="#git生成密钥公钥" class="headerlink" title="git生成密钥公钥"></a>git生成密钥公钥</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">ssh-keygen <span class="token parameter variable">-t</span> rsa <span class="token parameter variable">-C</span> <span class="token string">"your_email@youremail.com"</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="撤销commit-m-‘’"><a href="#撤销commit-m-‘’" class="headerlink" title="撤销commit-m ‘’"></a>撤销commit-m ‘’</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">git</span> reset <span class="token parameter variable">--soft</span> HEAD^<span class="token function">git</span> revert <span class="token operator">&lt;</span>hashcode<span class="token operator">></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h3 id="修改commit注释"><a href="#修改commit注释" class="headerlink" title="修改commit注释"></a>修改commit注释</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">git</span> commit <span class="token parameter variable">--amend</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="撤销add"><a href="#撤销add" class="headerlink" title="撤销add"></a>撤销add</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 查看当前缓存区的文件</span><span class="token function">git</span> status <span class="token parameter variable">-s</span><span class="token function">git</span> reset HEAD<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><h3 id="gitee-github代码同步"><a href="#gitee-github代码同步" class="headerlink" title="gitee github代码同步"></a>gitee github代码同步</h3><ul><li><p>在已有项目git中，关联github仓库，<code>git remote add github https://github.com/ccnuu/parent.git</code></p></li><li><p>推送到github仓库，<code>git push github [master]</code></p></li><li><p>删除git默认远程仓库名称，<code>git remote rm origin</code></p></li><li><p>删除git关联远程仓库名称，<code>git remote rm github</code></p></li></ul><h3 id="Git中更新子模块"><a href="#Git中更新子模块" class="headerlink" title="Git中更新子模块"></a>Git中更新子模块</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">git</span> submodule <span class="token function">sync</span><span class="token function">git</span> submodule update <span class="token parameter variable">--init</span> <span class="token parameter variable">--recursive</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h3 id="只合并一个commit"><a href="#只合并一个commit" class="headerlink" title="只合并一个commit"></a>只合并一个commit</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">git</span> cherry-pick <span class="token operator">&lt;</span>hashcode<span class="token operator">></span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h2 id="本地代理sock"><a href="#本地代理sock" class="headerlink" title="本地代理sock"></a>本地代理sock</h2><p>安装代理工具</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">yay <span class="token parameter variable">-S</span> proxychains<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>配置 proxychains</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">vim</span> /etc/proxychains.confsocks5 <span class="token number">127.0</span>.0.1 <span class="token number">7890</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>然后再配置 clash 混合开启俩端口(7897)和 socks(7890) 端口</p><p>ssh 配置</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">vim</span> ~/.ssh/configHost github.com    <span class="token comment"># 告诉 SSH 不要提示用户确认主机指纹</span>    StrictHostKeyChecking no    <span class="token comment"># 告诉 SSH 将主机指纹信息写入 /dev/null (一个虚拟的空设备)，这样每次连接都会被当作是第一次，但因为我们禁用了检查，所以不会有问题。这避免了每次都要确认指纹的麻烦</span>    UserKnownHostsFile /dev/null<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><p>例如：</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">proxychains4 <span class="token function">git</span> clone git@github.com:llvm/llvm-project.git<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Git常用命令&quot;&gt;&lt;a href=&quot;#Git常用命令&quot; class=&quot;headerlink&quot; title=&quot;Git常用命令&quot;&gt;&lt;/a&gt;Git常用命令&lt;/h1&gt;&lt;h2 id=&quot;基本使用&quot;&gt;&lt;a href=&quot;#基本使用&quot; class=&quot;headerlink&quot; titl</summary>
      
    
    
    
    <category term="笔记" scheme="https://ccnuu.github.io/categories/%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Git" scheme="https://ccnuu.github.io/tags/Git/"/>
    
  </entry>
  
  <entry>
    <title>Hello Hexo</title>
    <link href="https://ccnuu.github.io/2023/07/13/HelloHexo/"/>
    <id>https://ccnuu.github.io/2023/07/13/HelloHexo/</id>
    <published>2023-07-13T02:17:16.000Z</published>
    <updated>2026-04-09T02:26:43.057Z</updated>
    
    <content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ hexo new <span class="token string">"My New Post"</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ hexo server<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ hexo generate<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ hexo deploy<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]></content>
    
    
    <summary type="html">Hexo配置</summary>
    
    
    
    <category term="Hexo" scheme="https://ccnuu.github.io/categories/Hexo/"/>
    
    
    <category term="Hexo" scheme="https://ccnuu.github.io/tags/Hexo/"/>
    
  </entry>
  
</feed>
