<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:content="http://purl.org/rss/1.0/modules/content/">

  <channel>
    <title>inasayang&#39;s blog</title>
    <link>/</link>
    <description>Recent blog posts on inasayang&#39;s blog</description>
    
    <generator>Hugo (https://gohugo.io)</generator>
    
    <language>zh-cn</language>
    
    <managingEditor>xiayangzzw@gmail.com (inasayang)</managingEditor>
    
    <webMaster>xiayangzzw@gmail.com (inasayang)</webMaster>
    
    <lastBuildDate>Tue, 15 Apr 2025 00:00:00 Z</lastBuildDate>
    
    <atom:link href="/tags/rust/index.xml" rel="self" type="application/rss+xml" />
    

    <item>
      <title>Rust | LTO和Thin LTO编译器</title>
      <link>/posts/250415_ltothinlto/</link>
      <pubDate>Tue, 15 Apr 2025 00:00:00 Z</pubDate>
      
      <author>xiayangzzw@gmail.com (inasayang)</author>

      
      
      
      

      <description>
      
      </description>
      <content:encoded>&lt;h2 id=&#34;lto-link-time-optimization&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#lto-link-time-optimization&#34;&gt;
        #
    &lt;/a&gt;
    LTO (Link Time Optimization)
&lt;/div&gt;
&lt;/h2&gt;
&lt;p&gt;链接时优化是一种编译器优化技术，它在程序的链接阶段而非传统的编译阶段执行代码优化。&lt;/p&gt;
&lt;h3 id=&#34;lto-的工作原理&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#lto-%e7%9a%84%e5%b7%a5%e4%bd%9c%e5%8e%9f%e7%90%86&#34;&gt;
        ##
    &lt;/a&gt;
    LTO 的工作原理
&lt;/div&gt;
&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;编译阶段&lt;/strong&gt;：编译器在编译单个源文件时，不仅生成机器代码，还保存中间表示（IR，Intermediate Representation）到目标文件中&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;链接阶段&lt;/strong&gt;：链接器收集所有模块的IR，将它们合并为一个统一的程序表示&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全局优化&lt;/strong&gt;：对整个程序执行优化，基于对所有代码的完整视图&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;lto-的主要优势&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#lto-%e7%9a%84%e4%b8%bb%e8%a6%81%e4%bc%98%e5%8a%bf&#34;&gt;
        ##
    &lt;/a&gt;
    LTO 的主要优势
&lt;/div&gt;
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;跨模块优化&lt;/strong&gt;：可以进行跨越多个源文件的优化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内联函数&lt;/strong&gt;：更强大的函数内联能力，包括跨编译单元边界&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;死代码消除&lt;/strong&gt;：更有效地移除未使用的代码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更精确的别名分析&lt;/strong&gt;：改进指针分析和内存访问优化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码大小减少&lt;/strong&gt;：通过移除不必要的代码减小二进制大小&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;lto-的缺点&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#lto-%e7%9a%84%e7%bc%ba%e7%82%b9&#34;&gt;
        ##
    &lt;/a&gt;
    LTO 的缺点
&lt;/div&gt;
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内存消耗大&lt;/strong&gt;：处理大型程序时需要大量内存&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;编译时间长&lt;/strong&gt;：链接过程变得更加复杂和耗时&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;thin-lto-轻量级链接时优化&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#thin-lto-%e8%bd%bb%e9%87%8f%e7%ba%a7%e9%93%be%e6%8e%a5%e6%97%b6%e4%bc%98%e5%8c%96&#34;&gt;
        #
    &lt;/a&gt;
    Thin LTO (轻量级链接时优化)
&lt;/div&gt;
&lt;/h2&gt;
&lt;p&gt;Thin LTO 是 LLVM 编译器基础设施引入的 LTO 变种，旨在解决传统 LTO 的性能和扩展性问题。&lt;/p&gt;
&lt;h3 id=&#34;thin-lto-的工作原理&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#thin-lto-%e7%9a%84%e5%b7%a5%e4%bd%9c%e5%8e%9f%e7%90%86&#34;&gt;
        ##
    &lt;/a&gt;
    Thin LTO 的工作原理
&lt;/div&gt;
&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;索引生成&lt;/strong&gt;：每个目标文件都独立生成索引，包含符号和引用信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并行优化&lt;/strong&gt;：基于索引信息，将全局优化工作分解成多个可并行执行的任务&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模块级优化&lt;/strong&gt;：在各个模块上并行执行优化，而不是合并所有IR&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;thin-lto-的主要优势&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#thin-lto-%e7%9a%84%e4%b8%bb%e8%a6%81%e4%bc%98%e5%8a%bf&#34;&gt;
        ##
    &lt;/a&gt;
    Thin LTO 的主要优势
&lt;/div&gt;
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;减少内存使用&lt;/strong&gt;：不需要加载整个程序的IR到内存&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并行编译&lt;/strong&gt;：通过并行化加速编译过程&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;增量编译支持&lt;/strong&gt;：更好地支持增量构建&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;保留大部分传统LTO的优化效果&lt;/strong&gt;：仍能执行跨模块优化&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;特性&lt;/th&gt;
					&lt;th&gt;LTO&lt;/th&gt;
					&lt;th&gt;Thin LTO&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;优化效果&lt;/td&gt;
					&lt;td&gt;最大化&lt;/td&gt;
					&lt;td&gt;接近LTO但略低&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;内存使用&lt;/td&gt;
					&lt;td&gt;高&lt;/td&gt;
					&lt;td&gt;中等&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;编译速度&lt;/td&gt;
					&lt;td&gt;慢&lt;/td&gt;
					&lt;td&gt;快（尤其在多核系统）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;并行度&lt;/td&gt;
					&lt;td&gt;有限&lt;/td&gt;
					&lt;td&gt;高&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;适用场景&lt;/td&gt;
					&lt;td&gt;最终发布构建&lt;/td&gt;
					&lt;td&gt;日常开发和发布&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;rust-中使用&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#rust-%e4%b8%ad%e4%bd%bf%e7%94%a8&#34;&gt;
        #
    &lt;/a&gt;
    Rust 中使用
&lt;/div&gt;
&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[profile.release]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;# lto = &amp;#34;off&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;# lto = &amp;#34;fat&amp;#34;   &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;# lto = &amp;#34;thin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;LTO 通常与其他优化标志一起使用。&lt;/p&gt;</content:encoded>
      
      <category>rust</category>
      
      <category>llvm</category>
      
      <category>compile</category>
      
      
      <guid isPermaLink="true">/posts/250415_ltothinlto/</guid>
    </item>
    

    <item>
      <title>Rust | Clone vs Copy</title>
      <link>/posts/230913_rustcopyclone/</link>
      <pubDate>Wed, 13 Sep 2023 00:00:00 Z</pubDate>
      
      <author>xiayangzzw@gmail.com (inasayang)</author>

      
      
      
      

      <description>
      
      </description>
      <content:encoded>&lt;h3 id=&#34;copy的含义&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#copy%e7%9a%84%e5%90%ab%e4%b9%89&#34;&gt;
        ##
    &lt;/a&gt;
    Copy的含义
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Copy&lt;/code&gt;的全名是&lt;code&gt;std::marker::Copy&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;std::marker&lt;/code&gt;模块里面所有的&lt;code&gt;trait&lt;/code&gt;都是特殊的&lt;code&gt;trait&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;它们是跟编译器密切绑定的，&lt;code&gt;impl&lt;/code&gt;这些&lt;code&gt;trait&lt;/code&gt;对编译器的行为有重要影响。在编译器眼里，它们与其他的&lt;code&gt;trait&lt;/code&gt;不一样。这几个&lt;code&gt;trait&lt;/code&gt;内部都没有方法，它们的唯一任务是给类型打一个“标记”，表明它符合某种约定——这些约定会影响编译器的静态检查以及代码生成&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;那么，&lt;code&gt;Copy&lt;/code&gt;这个&lt;code&gt;trait&lt;/code&gt;在编译器的眼里代表的是什么意思呢？&lt;/p&gt;
&lt;p&gt;简单点总结就是，如果一个类型&lt;code&gt;impl&lt;/code&gt;了&lt;code&gt;Copy trait&lt;/code&gt;，意味着任何时候，我们都可以通过简单的内存复制（在C语言里按字节复制&lt;code&gt;memcpy&lt;/code&gt;）实现该类型的复制，并且不会产生任何内存安全问题。&lt;/p&gt;
&lt;p&gt;一旦一个类型实现了&lt;code&gt;Copy trait&lt;/code&gt;，那么它在变量绑定、函数参数传递、函数返回值传递等场景下，都是&lt;code&gt;copy&lt;/code&gt;语义，而不再是默认的&lt;code&gt;move&lt;/code&gt;语义。&lt;/p&gt;
&lt;p&gt;最简单的赋值语句&lt;code&gt;x = y&lt;/code&gt;来说明&lt;code&gt;move&lt;/code&gt;语义和&lt;code&gt;copy&lt;/code&gt;语义的根本区别&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;move&lt;/code&gt;语义是“&lt;strong&gt;剪切、粘贴&lt;/strong&gt;”操作，变量&lt;code&gt;y&lt;/code&gt;把所有权递交给了&lt;code&gt;x&lt;/code&gt;之后，&lt;code&gt;y&lt;/code&gt;就彻底失效了，后面继续使用&lt;code&gt;y&lt;/code&gt;就会出编译错误&lt;/li&gt;
&lt;li&gt;&lt;code&gt;copy&lt;/code&gt;语义是“&lt;strong&gt;复制、粘贴&lt;/strong&gt;”操作，变量&lt;code&gt;y&lt;/code&gt;把所有权递交给了&lt;code&gt;x&lt;/code&gt;之后，它自己还留了一个副本，在这句赋值语句之后，&lt;code&gt;x&lt;/code&gt;和&lt;code&gt;y&lt;/code&gt;依然都可以继续使用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在&lt;code&gt;Rust&lt;/code&gt;里，&lt;code&gt;move&lt;/code&gt;语义和&lt;code&gt;copy&lt;/code&gt;语义具体执行的操作，是不允许由程序员自定义的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;move&lt;/code&gt;语义或者&lt;code&gt;copy&lt;/code&gt;语义都是执行的&lt;code&gt;memcpy&lt;/code&gt;，无法更改，这个过程中绝对不存在其他副作用。&lt;/p&gt;
&lt;p&gt;如果考虑后端优化，在许多情况下，不必要的内存复制实际上已经彻底优化掉了，不必担心执行效率的问题。没有必要每次都把&lt;code&gt;move&lt;/code&gt;或者&lt;code&gt;copy&lt;/code&gt;操作与具体的汇编代码联系起来，因为场景不同，优化结果不同，生成的代码也是不同的。只需记住的是语义。&lt;/p&gt;
&lt;h3 id=&#34;copy的实现条件&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#copy%e7%9a%84%e5%ae%9e%e7%8e%b0%e6%9d%a1%e4%bb%b6&#34;&gt;
        ##
    &lt;/a&gt;
    Copy的实现条件
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;并不是所有的类型都可以实现&lt;code&gt;Copy trait&lt;/code&gt;。&lt;code&gt;Rust&lt;/code&gt;规定，对于自定义类型，只有所有成员都实现了&lt;code&gt;Copy trait&lt;/code&gt;，这个类型才有资格实现&lt;code&gt;Copy trait&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;常见的数字类型、&lt;code&gt;bool&lt;/code&gt;类型、共享借用指针&lt;code&gt;&amp;amp;&lt;/code&gt;，都是具有&lt;code&gt;Copy&lt;/code&gt;属性的类型&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Box&lt;/code&gt;、&lt;code&gt;Vec&lt;/code&gt;、可写借用指针&lt;code&gt;&amp;amp;mut&lt;/code&gt;等类型都是不具备&lt;code&gt;Copy&lt;/code&gt;属性的类型&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于数组类型，如果内部的元素类型是&lt;code&gt;Copy&lt;/code&gt;，那么这个数组也是&lt;code&gt;Copy&lt;/code&gt;类型&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于元组&lt;code&gt;tuple&lt;/code&gt;类型，如果每一个元素都是&lt;code&gt;Copy&lt;/code&gt;类型，那么这个&lt;code&gt;tuple&lt;/code&gt;也是&lt;code&gt;Copy&lt;/code&gt;类型&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;struct&lt;/code&gt;和&lt;code&gt;enum&lt;/code&gt;类型不会自动实现&lt;code&gt;Copy trait&lt;/code&gt;。只有当&lt;code&gt;struct&lt;/code&gt;和&lt;code&gt;enum&lt;/code&gt;内部的每个元素都是&lt;code&gt;Copy&lt;/code&gt;类型时，编译器才允许我们针对此类型实现&lt;code&gt;Copy trait&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ca9ee6&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#e5c890&#34;&gt;T&lt;/span&gt;(&lt;span style=&#34;color:#e78284&#34;&gt;i32&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ca9ee6&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#8caaee&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; t1 &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; T(&lt;span style=&#34;color:#ef9f76&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; t2 &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; t1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#8caaee&#34;&gt;println!&lt;/span&gt; (&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;&lt;/span&gt;, t1.&lt;span style=&#34;color:#ef9f76&#34;&gt;0&lt;/span&gt;, t2.&lt;span style=&#34;color:#ef9f76&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译错误。原因是在&lt;code&gt;let t2 = t1&lt;/code&gt;；这条语句中执行的是&lt;code&gt;move&lt;/code&gt;语义。但是可以手动为它&lt;code&gt;impl Copy trait&lt;/code&gt;，这样它就具备了&lt;code&gt;copy&lt;/code&gt;语义&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Rust&lt;/code&gt;中只有&lt;code&gt;POD&lt;/code&gt;（&lt;code&gt;C++&lt;/code&gt;语言中的&lt;code&gt;Plain Old Data&lt;/code&gt;）类型才有资格实现&lt;code&gt;Copy trait&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;Rust&lt;/code&gt;中，如果一个类型只包含&lt;code&gt;POD&lt;/code&gt;数据类型的成员，并且没有自定义析构函数，那它就是&lt;code&gt;POD&lt;/code&gt;类型。&lt;/p&gt;
&lt;p&gt;比如：整数、浮点数、只包含&lt;code&gt;POD&lt;/code&gt;类型的数组等，都属于&lt;code&gt;POD&lt;/code&gt;类型；而&lt;code&gt;Box&lt;/code&gt; &lt;code&gt;String&lt;/code&gt; &lt;code&gt;Vec&lt;/code&gt;等不能按字节复制的类型，都不属于&lt;code&gt;POD&lt;/code&gt;类型。&lt;/p&gt;
&lt;p&gt;并不是所有满足&lt;code&gt;POD&lt;/code&gt;的类型都应该实现&lt;code&gt;Copy trait&lt;/code&gt;，是否实现&lt;code&gt;Copy&lt;/code&gt;取决于&lt;em&gt;业务需求&lt;/em&gt;。&lt;/p&gt;
&lt;h3 id=&#34;clone的含义&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#clone%e7%9a%84%e5%90%ab%e4%b9%89&#34;&gt;
        ##
    &lt;/a&gt;
    Clone的含义
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Clone&lt;/code&gt;的全名是&lt;code&gt;std::clone::Clone&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ca9ee6&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;color:#ca9ee6&#34;&gt;trait&lt;/span&gt; &lt;span style=&#34;color:#99d1db&#34;&gt;Clone&lt;/span&gt; : &lt;span style=&#34;color:#99d1db&#34;&gt;Sized&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ca9ee6&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#8caaee&#34;&gt;clone&lt;/span&gt;(&lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#99d1db&#34;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span style=&#34;color:#e5c890&#34;&gt;Self&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ca9ee6&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#8caaee&#34;&gt;clone_from&lt;/span&gt;(&lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#ca9ee6&#34;&gt;mut&lt;/span&gt; &lt;span style=&#34;color:#99d1db&#34;&gt;self&lt;/span&gt;, source: &lt;span style=&#34;color:#ca9ee6&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#e5c890&#34;&gt;Self&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e78284&#34;&gt;＊&lt;/span&gt;&lt;span style=&#34;color:#99d1db&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; source.clone()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;两个关联方法，分别是&lt;code&gt;clone_from&lt;/code&gt;和&lt;code&gt;clone&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;clone_from&lt;/code&gt;是有默认实现的，依赖于&lt;code&gt;clone&lt;/code&gt;方法的实现&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clone&lt;/code&gt;方法没有默认实现，需要手动实现&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;clone&lt;/code&gt;方法一般用于“基于语义的复制”操作。所以，跟具体类型的作用息息相关。比如，对于&lt;code&gt;Box&lt;/code&gt;类型，&lt;code&gt;clone&lt;/code&gt;执行的是“深复制”；而对于&lt;code&gt;Rc&lt;/code&gt;类型，&lt;code&gt;clone&lt;/code&gt;做的事情就是把引用计数值加1。&lt;/p&gt;
&lt;p&gt;虽然&lt;code&gt;Rust&lt;/code&gt;中的&lt;code&gt;clone&lt;/code&gt;方法一般是用来执行复制操作的，但是如果在自定义的&lt;code&gt;clone&lt;/code&gt;函数中做点别的什么工作，编译器也没办法禁止。可以根据需要在&lt;code&gt;clone&lt;/code&gt;函数中编写任意的逻辑。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对于实现了&lt;code&gt;copy&lt;/code&gt;的类型，它的&lt;code&gt;clone&lt;/code&gt;方法应该跟&lt;code&gt;copy&lt;/code&gt;语义相容，等同于按字节复制&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;自动derive&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#%e8%87%aa%e5%8a%a8derive&#34;&gt;
        ##
    &lt;/a&gt;
    自动derive
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;绝大多数情况下，实现&lt;code&gt;Copy&lt;/code&gt; &lt;code&gt;Clone&lt;/code&gt;这样的&lt;code&gt;trait&lt;/code&gt;都是一个重复而无聊的工作。因此，&lt;code&gt;Rust&lt;/code&gt;提供了一个&lt;code&gt;attribute&lt;/code&gt;，可以利用编译器自动生成这部分代码。示例如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;#[derive(Copy, Clone)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ca9ee6&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#e5c890&#34;&gt;MyStruct&lt;/span&gt;(&lt;span style=&#34;color:#e78284&#34;&gt;i32&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;derive&lt;/code&gt;会让编译器自动生成&lt;code&gt;impl Copy&lt;/code&gt;和&lt;code&gt;impl Clone&lt;/code&gt;这样的代码。自动生成的&lt;code&gt;clone&lt;/code&gt;方法，会依次调用每个成员的&lt;code&gt;clone&lt;/code&gt;方法。&lt;/p&gt;
&lt;p&gt;通过&lt;code&gt;derive&lt;/code&gt;方式自动实现&lt;code&gt;Copy&lt;/code&gt;和手工实现&lt;code&gt;Copy&lt;/code&gt;有微小的区别。当类型具有泛型参数的时候，比如&lt;code&gt;struct MyStruct&amp;lt;T&amp;gt;{}&lt;/code&gt;，通过&lt;code&gt;derive&lt;/code&gt;自动生成的代码会自动添加一个&lt;code&gt;T:Copy&lt;/code&gt;的约束。&lt;/p&gt;
&lt;h3 id=&#34;总结&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#%e6%80%bb%e7%bb%93&#34;&gt;
        ##
    &lt;/a&gt;
    总结
&lt;/div&gt;
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Copy&lt;/code&gt;内部没有方法，&lt;code&gt;Clone&lt;/code&gt;内部有两个方法&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Copy trait&lt;/code&gt;是给编译器用的，告诉编译器这个类型默认采用&lt;code&gt;copy&lt;/code&gt;语义，而不是&lt;code&gt;move&lt;/code&gt;语义。&lt;code&gt;Clone trait&lt;/code&gt;是给程序员用的，我们必须手动调用&lt;code&gt;clone&lt;/code&gt;方法，它才能发挥作用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Copy trait&lt;/code&gt;不是想实现就能实现的，它对类型是有要求的，有些类型不可能&lt;code&gt;impl Copy&lt;/code&gt;。而&lt;code&gt;Clone trait&lt;/code&gt;则没有什么前提条件，任何类型都可以实现（&lt;code&gt;unsized&lt;/code&gt;类型除外，因为无法使用&lt;code&gt;unsized&lt;/code&gt;类型作为返回值）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Copy trait&lt;/code&gt;规定了这个类型在执行变量绑定、函数参数传递、函数返回等场景下的操作方式。即这个类型在这种场景下，必然执行的是“&lt;strong&gt;简单内存复制&lt;/strong&gt;”操作，这是由编译器保证的，程序员无法控制。&lt;code&gt;Clone trait&lt;/code&gt;里面的&lt;code&gt;clone&lt;/code&gt;方法究竟会执行什么操作，则是取决于程序员自己写的逻辑。一般情况下，&lt;code&gt;clone&lt;/code&gt;方法应该执行一个“深复制”操作，但这不是强制性的，如果你愿意，在里面启动一个人工智能程序都是有可能的&lt;/li&gt;
&lt;li&gt;如果确实不需要&lt;code&gt;Clone trait&lt;/code&gt;执行其他自定义操作（绝大多数情况都是这样），编译器提供了一个工具，我们可以在一个类型上添加&lt;code&gt;#[derive(Clone)]&lt;/code&gt;，来让编译器自动生成那些重复的代码。编译器自动生成的&lt;code&gt;clone&lt;/code&gt;方法非常机械，就是依次调用每个成员的&lt;code&gt;clone&lt;/code&gt;方法&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Rust&lt;/code&gt;语言规定了在&lt;code&gt;T: Copy&lt;/code&gt;的情况下，&lt;code&gt;Clone trait&lt;/code&gt;代表的含义。即：当某变量&lt;code&gt;t: T&lt;/code&gt;符合&lt;code&gt;T: Copy&lt;/code&gt;时，它调用&lt;code&gt;t.clone()&lt;/code&gt; 方法的含义必须等同于“&lt;strong&gt;简单内存复制&lt;/strong&gt;”。也就是说，&lt;code&gt;clone&lt;/code&gt;的行为必须等同于&lt;code&gt;let x = std::ptr::read(&amp;amp;t);&lt;/code&gt;，也等同于&lt;code&gt;let x = t;&lt;/code&gt;。当&lt;code&gt;T: Copy&lt;/code&gt;时，不要在&lt;code&gt;Clone trait&lt;/code&gt;里面乱写逻辑。所以，当需要指定一个类型是&lt;code&gt;Copy&lt;/code&gt;的时候，最好使用&lt;code&gt;#[derive(Copy,Clone)]&lt;/code&gt;方式，避免手动实现&lt;code&gt;Clone&lt;/code&gt;导致错误。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;深入浅出Rust&lt;/li&gt;
&lt;/ul&gt;</content:encoded>
      
      <category>rust</category>
      
      
      <guid isPermaLink="true">/posts/230913_rustcopyclone/</guid>
    </item>
    

    <item>
      <title>Rust | Ownership</title>
      <link>/posts/230620_rustownership/</link>
      <pubDate>Tue, 20 Jun 2023 00:00:00 Z</pubDate>
      
      <author>xiayangzzw@gmail.com (inasayang)</author>

      
      
      
      

      <description>
      
      </description>
      <content:encoded>&lt;h2 id=&#34;一段不安全的代码&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#%e4%b8%80%e6%ae%b5%e4%b8%8d%e5%ae%89%e5%85%a8%e7%9a%84%e4%bb%a3%e7%a0%81&#34;&gt;
        #
    &lt;/a&gt;
    一段不安全的代码
&lt;/div&gt;
&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e78284&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#8caaee&#34;&gt;foo&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;int&lt;/span&gt; a;          &lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;// 变量a的作用域开始
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    a &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ef9f76&#34;&gt;100&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;*&lt;/span&gt;c &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;xyz&amp;#34;&lt;/span&gt;;   &lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;// 变量c的作用域开始
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ca9ee6&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;a;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}                   &lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;// 变量a和c的作用域结束
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;变量 &lt;code&gt;a&lt;/code&gt; 和 &lt;code&gt;c&lt;/code&gt; 都是局部变量，函数结束后将局部变量 &lt;code&gt;a&lt;/code&gt; 的地址返回，但局部变量 &lt;code&gt;a&lt;/code&gt; 存在栈中，在离开作用域后，&lt;code&gt;a&lt;/code&gt; 所申请的栈上内存都会被系统回收，从而造成了 &lt;code&gt;悬空指针(Dangling Pointer)&lt;/code&gt; 的问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;​		虽然编译可以通过，但是运行的时候会出现错误。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;变量 &lt;code&gt;c&lt;/code&gt;常量字符串，存储于常量区， &lt;code&gt;&amp;quot;xyz&amp;quot;&lt;/code&gt; 只有当整个程序结束后系统才能回收这片内存。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;栈stack与堆heap&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#%e6%a0%88stack%e4%b8%8e%e5%a0%86heap&#34;&gt;
        #
    &lt;/a&gt;
    栈(Stack)与堆(Heap)
&lt;/div&gt;
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;栈中的所有数据都必须占用已知且固定大小的内存空间&lt;/li&gt;
&lt;li&gt;对于大小未知或者可能变化的数据，需要存储在堆上
&lt;ul&gt;
&lt;li&gt;当向堆上放入数据时，需要请求一定大小的内存空间。操作系统在堆的某处找到一块足够大的空位，把它标记为已使用，并返回一个表示该位置地址的&lt;strong&gt;指针&lt;/strong&gt;, 该过程被称为&lt;strong&gt;在堆上分配内存&lt;/strong&gt;，有时简称为 “分配”(&lt;code&gt;allocating&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;接着，该指针会被推入&lt;strong&gt;栈&lt;/strong&gt;中，因为指针的大小是已知且固定的，在后续使用过程中，你将通过栈中的&lt;strong&gt;指针&lt;/strong&gt;，来获取数据在堆上的实际内存位置，进而访问该数据&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;写入
&lt;ul&gt;
&lt;li&gt;入栈比在堆上分配内存要快&lt;/li&gt;
&lt;li&gt;入栈时操作系统无需分配新的空间，只需要将新数据放入栈顶即可&lt;/li&gt;
&lt;li&gt;在堆上分配内存则需要更多的工作，这是因为操作系统必须首先找到一块足够存放数据的内存空间，接着做一些记录为下一次分配做准备&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;读取
&lt;ul&gt;
&lt;li&gt;得益于 CPU 高速缓存，使得处理器可以减少对内存的访问，高速缓存和内存的访问速度差异在 10 倍以上&lt;/li&gt;
&lt;li&gt;栈数据往往可以直接存储在 CPU 高速缓存中，而堆数据只能存储在内存中&lt;/li&gt;
&lt;li&gt;访问堆上的数据比访问栈上的数据慢，因为必须先访问栈再通过栈上的指针来访问内存&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;所有权原则&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#%e6%89%80%e6%9c%89%e6%9d%83%e5%8e%9f%e5%88%99&#34;&gt;
        #
    &lt;/a&gt;
    所有权原则
&lt;/div&gt;
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Rust 中每一个值都被一个变量所拥有，该变量被称为值的所有者&lt;/li&gt;
&lt;li&gt;一个值同时只能被一个变量所拥有，或者说一个值只能拥有一个所有者&lt;/li&gt;
&lt;li&gt;当所有者(变量)离开作用域范围时，这个值将被丢弃(drop)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;变量绑定背后的数据交互&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#%e5%8f%98%e9%87%8f%e7%bb%91%e5%ae%9a%e8%83%8c%e5%90%8e%e7%9a%84%e6%95%b0%e6%8d%ae%e4%ba%a4%e4%ba%92&#34;&gt;
        #
    &lt;/a&gt;
    变量绑定背后的数据交互
&lt;/div&gt;
&lt;/h2&gt;
&lt;h4 id=&#34;转移所有权&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#%e8%bd%ac%e7%a7%bb%e6%89%80%e6%9c%89%e6%9d%83&#34;&gt;
        ###
    &lt;/a&gt;
    转移所有权
&lt;/div&gt;
&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; x &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ef9f76&#34;&gt;5&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; y &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; x;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;两个值都是通过自动拷贝的方式来赋值的，都被存在栈中，完全无需在堆上分配内存&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; s1 &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#99d1db&#34;&gt;String&lt;/span&gt;::from(&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; s2 &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; s1;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对于基本类型（存储在栈上），Rust 会自动拷贝，但是 &lt;code&gt;String&lt;/code&gt; 不是基本类型，而且是存储在堆上的，因此不能自动拷贝。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;String&lt;/code&gt; 类型是一个复杂类型，由&lt;strong&gt;存储在栈中的堆指针&lt;/strong&gt;、&lt;strong&gt;字符串长度&lt;/strong&gt;、&lt;strong&gt;字符串容量&lt;/strong&gt;共同组成，其中&lt;strong&gt;堆指针&lt;/strong&gt;是最重要的，它指向了真实存储字符串内容的堆内存，至于长度和容量，如果你有 Go 语言的经验，这里就很好理解：容量是堆内存分配空间的大小，长度是目前已经使用的大小。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;String&lt;/code&gt; 类型指向了一个堆上的空间，这里存储着它的真实数据, 下面对上面代码中的 &lt;code&gt;let s2 = s1&lt;/code&gt; 分成两种情况讨论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;拷贝 &lt;code&gt;String&lt;/code&gt; 和存储在堆上的字节数组 如果该语句是拷贝所有数据(深拷贝)，那么无论是 &lt;code&gt;String&lt;/code&gt; 本身还是底层的堆上数据，都会被全部拷贝，这对于性能而言会造成非常大的影响&lt;/li&gt;
&lt;li&gt;只拷贝 &lt;code&gt;String&lt;/code&gt; 本身 这样的拷贝非常快，因为在 64 位机器上就拷贝了 &lt;code&gt;8字节的指针&lt;/code&gt;、&lt;code&gt;8字节的长度&lt;/code&gt;、&lt;code&gt;8字节的容量&lt;/code&gt;，总计 24 字节，但是带来了新的问题：&lt;strong&gt;一个值只允许有一个所有者&lt;/strong&gt;，而现在这个值（堆上的真实字符串数据）有了两个所有者：&lt;code&gt;s1&lt;/code&gt; 和 &lt;code&gt;s2&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当变量离开作用域后，Rust 会自动调用 &lt;code&gt;drop&lt;/code&gt; 函数并清理变量的堆内存。&lt;/p&gt;
&lt;p&gt;当 &lt;code&gt;s1&lt;/code&gt; 和 &lt;code&gt;s2&lt;/code&gt; 离开作用域，它们都会尝试释放相同的内存。这是一个叫做 &lt;strong&gt;二次释放（double free）&lt;/strong&gt; 的错误。&lt;/p&gt;
&lt;p&gt;所以，Rust 这样解决问题：&lt;strong&gt;当 &lt;code&gt;s1&lt;/code&gt; 赋予 &lt;code&gt;s2&lt;/code&gt; 后，Rust 认为 &lt;code&gt;s1&lt;/code&gt; 不再有效，因此也无需在 &lt;code&gt;s1&lt;/code&gt; 离开作用域后 &lt;code&gt;drop&lt;/code&gt; 任何东西，这就是把所有权从 &lt;code&gt;s1&lt;/code&gt; 转移给了 &lt;code&gt;s2&lt;/code&gt;，&lt;code&gt;s1&lt;/code&gt; 在被赋予 &lt;code&gt;s2&lt;/code&gt; 后就马上失效了&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;看看在所有权转移后再来使用旧的所有者&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;let s1 = String::from(&amp;#34;hello&amp;#34;);
let s2 = s1;
println!(&amp;#34;{}, world!&amp;#34;, s1);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Rust 会禁止你使用无效的引用&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ca9ee6&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#8caaee&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; x: &lt;span style=&#34;color:#ca9ee6&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#e78284&#34;&gt;str&lt;/span&gt; &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;hello, world&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; y &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; x;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8caaee&#34;&gt;println!&lt;/span&gt;(&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;&lt;/span&gt;,x,y);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;x&lt;/code&gt; 只是引用了存储在二进制中的字符串 &lt;code&gt;&amp;quot;hello, world&amp;quot;&lt;/code&gt;，并没有持有所有权。&lt;/p&gt;
&lt;p&gt;因此 &lt;code&gt;let y = x&lt;/code&gt; 中，仅仅是对该引用进行了拷贝，此时 &lt;code&gt;y&lt;/code&gt; 和 &lt;code&gt;x&lt;/code&gt; 都引用了同一个字符串。&lt;/p&gt;
&lt;h4 id=&#34;克隆深拷贝&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#%e5%85%8b%e9%9a%86%e6%b7%b1%e6%8b%b7%e8%b4%9d&#34;&gt;
        ###
    &lt;/a&gt;
    克隆(深拷贝)
&lt;/div&gt;
&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Rust 永远也不会自动创建数据的 “深拷贝”&lt;/strong&gt;。任何&lt;strong&gt;自动&lt;/strong&gt;的复制都不是深拷贝。&lt;/p&gt;
&lt;p&gt;如果&lt;strong&gt;确实&lt;/strong&gt;需要深度复制 &lt;code&gt;String&lt;/code&gt; 中堆上的数据，而不仅仅是栈上的数据，可以使用一个叫做 &lt;code&gt;clone&lt;/code&gt; 的方法。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; s1 &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#99d1db&#34;&gt;String&lt;/span&gt;::from(&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; s2 &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; s1.clone();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8caaee&#34;&gt;println!&lt;/span&gt;(&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;s1 = &lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;, s2 = &lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;&lt;/span&gt;, s1, s2);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;s2&lt;/code&gt; 完整的复制了 &lt;code&gt;s1&lt;/code&gt; 的数据&lt;/p&gt;
&lt;h4 id=&#34;拷贝浅拷贝&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#%e6%8b%b7%e8%b4%9d%e6%b5%85%e6%8b%b7%e8%b4%9d&#34;&gt;
        ###
    &lt;/a&gt;
    拷贝(浅拷贝)
&lt;/div&gt;
&lt;/h4&gt;
&lt;p&gt;浅拷贝只发生在栈上&lt;/p&gt;
&lt;p&gt;Rust 有一个叫做 &lt;code&gt;Copy&lt;/code&gt; 的特征，可以用在类似整型这样在栈中存储的类型。如果一个类型拥有 &lt;code&gt;Copy&lt;/code&gt; 特征，一个旧的变量在被赋值给其他变量后仍然可用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;任何基本类型的组合可以 &lt;code&gt;Copy&lt;/code&gt; ，不需要分配内存或某种形式资源的类型是可以 &lt;code&gt;Copy&lt;/code&gt; 的&lt;/strong&gt;。如下是一些 &lt;code&gt;Copy&lt;/code&gt; 的类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;所有整数类型&lt;/li&gt;
&lt;li&gt;布尔类型&lt;/li&gt;
&lt;li&gt;所有浮点数类型&lt;/li&gt;
&lt;li&gt;字符类型&lt;/li&gt;
&lt;li&gt;元组，当且仅当其包含的类型也都是 &lt;code&gt;Copy&lt;/code&gt; 的时候&lt;/li&gt;
&lt;li&gt;不可变引用 &lt;code&gt;&amp;amp;T&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;引用与解引用&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#%e5%bc%95%e7%94%a8%e4%b8%8e%e8%a7%a3%e5%bc%95%e7%94%a8&#34;&gt;
        #
    &lt;/a&gt;
    引用与解引用
&lt;/div&gt;
&lt;/h2&gt;
&lt;p&gt;常规引用是一个指针类型，指向了对象存储的内存地址。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ca9ee6&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#8caaee&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; x &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ef9f76&#34;&gt;5&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; y &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;x;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8caaee&#34;&gt;assert_eq!&lt;/span&gt;(&lt;span style=&#34;color:#ef9f76&#34;&gt;5&lt;/span&gt;, x);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8caaee&#34;&gt;assert_eq!&lt;/span&gt;(&lt;span style=&#34;color:#ef9f76&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;*&lt;/span&gt;y);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;不可变引用&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#%e4%b8%8d%e5%8f%af%e5%8f%98%e5%bc%95%e7%94%a8&#34;&gt;
        #
    &lt;/a&gt;
    不可变引用
&lt;/div&gt;
&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ca9ee6&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#8caaee&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; s1 &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#99d1db&#34;&gt;String&lt;/span&gt;::from(&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; len &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; calculate_length(&lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;s1);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8caaee&#34;&gt;println!&lt;/span&gt;(&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;The length of &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#39; is &lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;.&amp;#34;&lt;/span&gt;, s1, len);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ca9ee6&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#8caaee&#34;&gt;calculate_length&lt;/span&gt;(s: &lt;span style=&#34;color:#ca9ee6&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#99d1db&#34;&gt;String&lt;/span&gt;) -&amp;gt; &lt;span style=&#34;color:#e78284&#34;&gt;usize&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    s.len()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://pic1.zhimg.com/80/v2-fc68ea4a1fe2e3fe4c5bb523a0a8247c_1440w.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;通过 &lt;code&gt;&amp;amp;s1&lt;/code&gt; 语法，我们创建了一个&lt;strong&gt;指向 &lt;code&gt;s1&lt;/code&gt; 的引用&lt;/strong&gt;，但是并不拥有它。因为并不拥有这个值，当引用离开作用域后，其指向的值也不会被丢弃。&lt;/p&gt;
&lt;h2 id=&#34;可变引用&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#%e5%8f%af%e5%8f%98%e5%bc%95%e7%94%a8&#34;&gt;
        #
    &lt;/a&gt;
    可变引用
&lt;/div&gt;
&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ca9ee6&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#8caaee&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#ca9ee6&#34;&gt;mut&lt;/span&gt; s &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#99d1db&#34;&gt;String&lt;/span&gt;::from(&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    change(&lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#ca9ee6&#34;&gt;mut&lt;/span&gt; s);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ca9ee6&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#8caaee&#34;&gt;change&lt;/span&gt;(some_string: &lt;span style=&#34;color:#ca9ee6&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#e5c890&#34;&gt;mut&lt;/span&gt; &lt;span style=&#34;color:#99d1db&#34;&gt;String&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    some_string.push_str(&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;, world&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;s&lt;/code&gt; 是可变类型，其次创建一个可变的引用 &lt;code&gt;&amp;amp;mut s&lt;/code&gt; 和接受可变引用参数 &lt;code&gt;some_string: &amp;amp;mut String&lt;/code&gt; 的函数。&lt;/p&gt;
&lt;p&gt;可变引用同时只能存在一个&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ca9ee6&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#8caaee&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#ca9ee6&#34;&gt;mut&lt;/span&gt; s &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#99d1db&#34;&gt;String&lt;/span&gt;::from(&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; r1 &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;s;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; r2 &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;s;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8caaee&#34;&gt;println!&lt;/span&gt;(&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt; and &lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;&lt;/span&gt;, r1, r2);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;// 新编译器中，r1,r2作用域在这里结束
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; r3 &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#ca9ee6&#34;&gt;mut&lt;/span&gt; s;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8caaee&#34;&gt;println!&lt;/span&gt;(&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;&lt;/span&gt;, r3);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;// 老编译器中，r1、r2、r3作用域在这里结束
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;// 新编译器中，r3作用域在这里结束
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;引用作用域的结束位置从花括号变成最后一次使用的位置&lt;/strong&gt;，因此 &lt;code&gt;r1&lt;/code&gt; 借用和 &lt;code&gt;r2&lt;/code&gt; 借用在 &lt;code&gt;println!&lt;/code&gt; 后，就结束了，此时 &lt;code&gt;r3&lt;/code&gt; 可以顺利借用到可变引用。&lt;/p&gt;
&lt;h3 id=&#34;悬垂引用dangling-references&#34; &gt;
&lt;div&gt;
    &lt;a href=&#34;#%e6%82%ac%e5%9e%82%e5%bc%95%e7%94%a8dangling-references&#34;&gt;
        ##
    &lt;/a&gt;
    悬垂引用(Dangling References)
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;指针指向某个值后，这个值被释放掉了，而指针仍然存在，其指向的内存可能不存在任何值或已被其它变量重新使用。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ca9ee6&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#8caaee&#34;&gt;dangle&lt;/span&gt;() -&amp;gt; &lt;span style=&#34;color:#ca9ee6&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#99d1db&#34;&gt;String&lt;/span&gt; { &lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;// dangle 返回一个字符串的引用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; s &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#99d1db&#34;&gt;String&lt;/span&gt;::from(&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;); &lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;// s 是一个新字符串
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;s &lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;// 返回字符串 s 的引用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;// 这里 s 离开作用域并被丢弃。其内存被释放。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#737994;font-style:italic&#34;&gt;// 危险！
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;解决方法是直接返回 &lt;code&gt;String&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ca9ee6&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#8caaee&#34;&gt;no_dangle&lt;/span&gt;() -&amp;gt; &lt;span style=&#34;color:#99d1db&#34;&gt;String&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e78284&#34;&gt;let&lt;/span&gt; s &lt;span style=&#34;color:#99d1db;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#99d1db&#34;&gt;String&lt;/span&gt;::from(&lt;span style=&#34;color:#a6d189&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;String&lt;/code&gt; 的 &lt;strong&gt;所有权被转移给外面的调用者&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://course.rs/basic/ownership/ownership.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;https://course.rs/basic/ownership/ownership.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://course.rs/basic/ownership/borrowing.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;https://course.rs/basic/ownership/borrowing.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded>
      
      <category>rust</category>
      
      <category>ownership</category>
      
      
      <guid isPermaLink="true">/posts/230620_rustownership/</guid>
    </item>
    
  </channel>
</rss>
