<?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, 20 Jun 2023 00:00:00 Z</lastBuildDate>
    
    <atom:link href="/tags/ownership/index.xml" rel="self" type="application/rss+xml" />
    

    <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>
