<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
    xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
    xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
    >
<channel>
    <title>Joe&#x27;s Study Notes</title>
    <atom:link href="https://notes.zhihaoo.sol.build/rss.xml" rel="self" type="application/rss+xml" />
    <link>https://notes.zhihaoo.sol.build/</link>
    <description><![CDATA[
    <p>学习随笔</p>

    ]]></description>
    
    
    <item>
        <title>Find&#x95ED;&#x5305;&#x4E2D;&#x4E3A;&#x4EC0;&#x4E48;&#x4F1A;&#x51FA;&#x73B0;&#x26;&#x26;&#x8FD9;&#x79CD;&#x60C5;&#x51B5;?</title>
        <link>https://notes.zhihaoo.sol.build/4EB63666-509D-46BC-995D-061B85D94E4C/</link>
        <guid>https://notes.zhihaoo.sol.build/4EB63666-509D-46BC-995D-061B85D94E4C/</guid>
        <pubDate>Wed, 13 May 2026 10:44:12 +0800</pubDate>
        
        
        <description><![CDATA[
            <p>示例代码:</p> 
<pre><code class="language-rust">fn main() {
    let vec1 = vec![1, 2, 3];
    let vec2 = vec![4, 5, 6];

    // 对 vec1 的 `iter()` 举出 `&amp;i32` 类型。
    let mut iter = vec1.iter();
    // 对 vec2 的 `into_iter()` 举出 `i32` 类型。
    let mut into_iter = vec2.into_iter();

    // 对迭代器举出的元素的引用是 `&amp;&amp;i32` 类型。解构成 `i32` 类型。
    // 译注：注意 `find` 方法会把迭代器元素的引用传给闭包。迭代器元素自身
    // 是 `&amp;i32` 类型，所以传给闭包的是 `&amp;&amp;i32` 类型。
    println!("Find 2 in vec1: {:?}", iter     .find(|&amp;&amp;x| x == 2));
    // 对迭代器举出的元素的引用是 `&amp;i32` 类型。解构成 `i32` 类型。
    println!("Find 2 in vec2: {:?}", into_iter.find(| &amp;x| x == 2));

    let array1 = [1, 2, 3];
    let array2 = [4, 5, 6];

    // 对数组的 `iter()` 举出 `&amp;i32`。
    println!("Find 2 in array1: {:?}", array1.iter()     .find(|&amp;&amp;x| x == 2));
    // 对数组的 `into_iter()` 通常举出 `&amp;i32``。
    println!("Find 2 in array2: {:?}", array2.into_iter().find(|&amp;x| x == 2));
}

</code></pre> 
<p>疑问: 为什么<code>println!("Find 2 in vec1: {:?}", iter .find(|&amp;&amp;x| x == 2));</code>是&amp;&amp;?</p> 
<hr /> 
<p>find方法的实现:</p> 
<pre><code>pub trait Iterator {
    // 被迭代的类型。
    type Item;

    // `find` 接受 `&amp;mut self` 参数，表明函数的调用者可以被借用和修改，
    // 但不会被消耗。
    fn find&lt;P&gt;(&amp;mut self, predicate: P) -&gt; Option&lt;Self::Item&gt; where
        // `FnMut` 表示被捕获的变量最多只能被修改，而不能被消耗。
        // `&amp;Self::Item` 指明了被捕获变量的类型（译注：是对迭代器元素的引用类型）
        P: FnMut(&amp;Self::Item) -&gt; bool {}
}

</code></pre> 
<p>因为find接受的闭包参数是<code>FnMut(&amp;Self::Item) -&gt; bool</code>，也就是说，闭包收到的永远是迭代器元素的一个引用。</p> 
<p>iter()返回的是item的引用-&gt; <code>&amp;i32</code>, 所以iter()-&gt;find</p>
        ]]></description>
    </item>
    
    <item>
        <title>&#x6307;&#x9488;&#x548C;&#x5F15;&#x7528;</title>
        <link>https://notes.zhihaoo.sol.build/E9BB128C-4C1D-461C-A7B7-1BC27893AE95/</link>
        <guid>https://notes.zhihaoo.sol.build/E9BB128C-4C1D-461C-A7B7-1BC27893AE95/</guid>
        <pubDate>Mon, 11 May 2026 22:58:58 +0800</pubDate>
        
        
        <description><![CDATA[
            <h3>示例代码:</h3> 
<pre><code class="language-rust">fn main() {
    // 获得一个 `i32` 类型的引用。`&amp;` 表示取引用。
    let reference = &amp;4;

    match reference {
        // 如果用 `&amp;val` 这个模式去匹配 `reference`，就相当于做这样的比较：
        // `&amp;i32`（译注：即 `reference` 的类型）
        // `&amp;val`（译注：即用于匹配的模式）
        // ^ 我们看到，如果去掉匹配的 `&amp;`，`i32` 应当赋给 `val`。
        // 译注：因此可用 `val` 表示被 `reference` 引用的值 4。
        &amp;val =&gt; println!("Got a value via destructuring: {:?}", val),
    }

    // 如果不想用 `&amp;`，需要在匹配前解引用。
    match *reference {
        val =&gt; println!("Got a value via dereferencing: {:?}", val),
    }

    // 如果一开始就不用引用，会怎样？ `reference` 是一个 `&amp;` 类型，因为赋值语句
    // 的右边已经是一个引用。但下面这个不是引用，因为右边不是。
    let _not_a_reference = 3;

    // Rust 对这种情况提供了 `ref`。它更改了赋值行为，从而可以对具体值创建引用。
    // 下面这行将得到一个引用。
    let ref _is_a_reference = 3;

    // 相应地，定义两个非引用的变量，通过 `ref` 和 `ref mut` 仍可取得其引用。
    let value = 5;
    let mut mut_value = 6;

    // 使用 `ref` 关键字来创建引用。
    // 译注：下面的 r 是 `&amp;i32` 类型，它像 `i32` 一样可以直接打印，因此用法上
    // 似乎看不出什么区别。但读者可以把 `println!` 中的 `r` 改成 `*r`，仍然能
    // 正常运行。前面例子中的 `println!` 里就不能是 `*val`，因为不能对整数解
    // 引用。
    match value {
        ref r =&gt; println!("Got a reference to a value: {:?}", r),
    }

    // 类似地使用 `ref mut`。
    match mut_value {
        ref mut m =&gt; {
            // 已经获得了 `mut_value` 的引用，先要解引用，才能改变它的值。
            *m += 10;
            println!("We added 10. `mut_value`: {:?}", m);
        },
    }
}

</code></pre> 
<h3>运行结果:</h3> 
<pre><code>Got a value via destructuring: 4
Got a value via dereferencing: 4
Got a reference to a value: 5
We added 10. `mut_value`: 16
</code></pre> 
<hr /> 
<h3>有个疑问没有搞明白:</h3> 
<pre><code>let value = 5;

match value {
    ref r =&gt; println!("Got a reference to a value: {:?}", *r),
}
</code></pre> 
<p>可以运行, 但是</p> 
<pre><code>let reference = &amp;4;

match reference {
    &amp;val =&gt; println!("Got a value via destructuring: {:?}", *val),
}
</code></pre> 
<p>就运行不了, 会报错</p> 
<hr /> 
<p>Rust 模式匹配中的 <code>&amp;</code> 和 <code>ref</code> 意义相反：</p> 
<ul> 
 <li><code>&amp;</code> 在模式中：解构一个引用，提取出背后的值（所有权转移或复制）。</li> 
 <li><code>ref</code> 在模式中：创建一个引用，绑定到匹配的值上。</li> 
 <li>let reference = &amp;4 的reference取到的实际是&amp;i32, 所以匹配&amp;val就是取对应的值, 也就是4, 而4是具体的值, 使用*来解引用是不对的.</li> 
</ul> 
<hr /> 
<h3>为什么这样写也能正常打印?:</h3> 
<pre><code>let value = 5;

match value {
    ref r =&gt; println!("Got a reference to a value: {:?}", r),
}
</code></pre> 
<hr /> 
<h4>1. 两个版本的差异</h4> 
<pre><code class="language-rust">let value = 5;

match value {
    ref r =&gt; println!("Got a reference to a value: {:?}", *r),   // 显式解引用
}
</code></pre> 
<pre><code class="language-rust">let value = 5;

match value {
    ref r =&gt; println!("Got a reference to a value: {:?}", r),    // 直接打印引用
}
</code></pre> 
<hr /> 
<h4>2. 为什么直接打印引用 <code>r</code> 也可以？</h4> 
<p>关键在于 <code>println!</code> 的 <code>{:?}</code> 格式化器要求参数实现 <code>Debug</code> trait。<br /> 而标准库为 <strong>所有引用类型</strong>（<code>&amp;T</code> 和 <code>&amp;mut T</code>）都实现了 <code>Debug</code>，<strong>前提是 <code>T</code> 本身实现了 <code>Debug</code></strong>。</p> 
<p>具体来说标准库中有类似这样的实现（示意）：</p> 
<pre><code class="language-rust">impl&lt;T: Debug + ?Sized&gt; Debug for &amp;T {
    fn fmt(&amp;self, f: &amp;mut Formatter&lt;'_&gt;) -&gt; fmt::Result {
        Debug::fmt(&amp;**self, f)   // 递归地打印被引用的值
    }
}
</code></pre> 
<p>因此当你打印一个 <code>&amp;T</code> 时，输出的实际是 <strong>它指向的 <code>T</code> 的 <code>Debug</code> 表示</strong>，即自动解引用了一层（甚至多层）。</p> 
<ul> 
 <li>如果 <code>value</code> 的类型是 <code>i32</code>（实现了 <code>Debug</code>），那么 <code>r</code> 的类型是 <code>&amp;i32</code>，打印 <code>r</code> 会直接显示 <code>4</code>（假设 <code>value=4</code>）。</li> 
 <li>这与显式写 <code>*r</code> 的效果在 <strong>视觉输出上完全相同</strong>，因为 <code>*r</code> 是 <code>i32</code>，打印 <code>i32</code> 也是显示 <code>4</code>。</li> 
</ul> 
<hr /> 
<h4>3. 本质区别：类型不同，但输出相同</h4> 
<table> 
 <thead> 
  <tr> 
   <th>写法</th> 
   <th><code>r</code> 的类型</th> 
   <th><code>println!</code> 实际看到的参数类型</th> 
   <th>输出效果</th> 
  </tr> 
 </thead> 
 <tbody> 
  <tr> 
   <td><code>println!("...", *r)</code></td> 
   <td><code>&amp;i32</code></td> 
   <td><code>i32</code>（经解引用）</td> 
   <td><code>4</code></td> 
  </tr> 
  <tr> 
   <td><code>println!("...", r)</code></td> 
   <td><code>&amp;i32</code></td> 
   <td><code>&amp;i32</code></td> 
   <td><code>4</code>（因为 <code>Debug for &amp;i32</code> 自动解引用）</td> 
  </tr> 
 </tbody> 
</table> 
<p>虽然底层类型不同（一个是 <code>i32</code>，一个是 <code>&amp;i32</code>），但因为 <code>Debug</code> 对引用的实现很“智能”，最终打印出来的字符串是一样的（除非 <code>T</code> 的 <code>Debug</code> 实现有特殊行为，例如打印地址而不是值——但普通类型不会）。</p> 
<hr /> 
<h4>4. 什么时候必须显式解引用？</h4> 
<ul> 
 <li>当需要 <strong>值的所有权</strong> 或 <strong>值的实际类型</strong> 进行运算时（例如 <code>*r + 1</code>）。</li> 
 <li>当你使用的 trait 没有为引用实现，但为值实现了时（例如 <code>std::fmt::Display</code> 通常没有对引用自动实现，所以 <code>println!("{}", r)</code> 可能报错，而 <code>println!("{}", *r)</code> 可以）。</li> 
 <li>当你需要精确控制解引用层数（例如遇到 <code>&amp;&amp;T</code> 时）。</li> 
</ul> 
<p>对于 <code>Debug</code> (<code>{:?}</code>)，由于标准库贴心地为所有引用实现了它，所以通常可以偷懒不写 <code>*</code>。</p> 
<hr /> 
<h4>5. 总结</h4> 
<ul> 
 <li><code>ref r</code> 绑定了一个引用 <code>&amp;value</code>。</li> 
 <li>直接打印 <code>r</code> 能工作，因为 <code>Debug for &amp;T</code> 会自动打印出引用的值（类似于一次隐式解引用）。</li> 
 <li><code>*r</code> 则是显式解引用得到 <code>T</code> 后再打印。</li> 
 <li><strong>功能上两者输出相同</strong>，但前者少写一个 <code>*</code>，更简洁。</li> 
</ul> 
<p>所以两个写法（有 <code>*</code> 和无 <code>*</code>）都是正确的，区别只在于是否显式解引用。</p> 
<hr /> 
<h3>为什么这样写也报错?</h3> 
<pre><code>let reference = &amp;String::from("Hello");

match reference {
    &amp;val =&gt; println!("Got a value via destructuring: {:?}", val),
}

</code></pre> 
<hr /> 
<blockquote> 
 <p>原因在于 String 没有实现 Copy trait，而示例中的 i32 是 Copy 的。</p> 
</blockquote> 
<h4>1. 先看这个代码的编译错误:</h4> 
<pre><code>error[E0507]: cannot move out of `*reference` which is behind a shared reference
 --&gt; src/main.rs:4:11
  |
4 |     &amp;val =&gt; println!("...", val),
  |     ^^^
  |     |
  |     move occurs because `val` has type `String`, which does not implement the `Copy` trait
  |     help: consider borrowing here: `&amp;val`

</code></pre> 
<h4>2. 模式 <code>&amp;val</code> 做了什么？</h4> 
<p>当你在 <code>match</code> 中对一个 <code>&amp;T</code> 类型的值使用模式 <code>&amp;val</code>：</p> 
<ul> 
 <li>它会<strong>解构这个引用</strong>，把引用背后的 <code>T</code> 值<strong>移动</strong>（或复制）出来绑定到 <code>val</code>。</li> 
 <li>对于 <code>&amp;String</code>，<code>T</code> 就是 <code>String</code>（一个拥有堆上数据的类型）。</li> 
 <li><code>String</code> 没有实现 <code>Copy</code>，所以 <code>val</code> 会<strong>获取 <code>String</code> 的所有权</strong>。</li> 
</ul> 
<p>但是这里有个严重问题：<strong><code>reference</code> 只是一个共享引用 <code>&amp;String</code></strong>，它<strong>并不拥有</strong>这个 <code>String</code> 的所有权。所有权属于原本创建 <code>String</code> 的变量（如果存在）或者临时值。从共享引用中强行把所有权移走是<strong>绝对禁止</strong>的，因为这会让原所有者再也无法安全地释放内存。</p> 
<p>所以编译器报错：<code>cannot move out of borrowed content</code>。</p> 
<hr /> 
<h4>3. 为什么之前的 <code>&amp;i32</code> 可以工作？</h4> 
<pre><code class="language-rust">let reference = &amp;4;      // &amp;i32
match reference {
    &amp;val =&gt; println!("{}", val),  // 可以运行
}
</code></pre> 
<ul> 
 <li><code>i32</code> 实现了 <code>Copy</code>，因此 <code>&amp;val</code> 模式不会“移动”所有权，而是<strong>复制</strong>出一个新的 <code>i32</code> 值给 <code>val</code>。</li> 
 <li>复制一个 <code>i32</code> 只是复制 4 个字节，没有任何安全问题，也不影响原引用。</li> 
</ul> 
<p>这正是区别所在：<strong><code>Copy</code> 类型可以安全地从引用中取出值（复制），非 <code>Copy</code> 类型则不允许</strong>。</p> 
<hr /> 
<h4>4. 如何修正非 <code>Copy</code> 类型的情况？</h4> 
<h5>方案一：直接绑定引用（不析构）</h5> 
<pre><code class="language-rust">match reference {
    val =&gt; println!("Got a reference: {:?}", val),  // val 是 &amp;String
}
</code></pre> 
<p><code>val</code> 的类型是 <code>&amp;String</code>，没有移动所有权，只是把引用复制了一份（引用本身是 <code>Copy</code> 的）。</p> 
<h5>方案二：使用 <code>ref</code> 模式（显式创建引用）</h5> 
<pre><code class="language-rust">match reference {
    ref val =&gt; println!("Got a reference: {:?}", val), // val 是 &amp;&amp;String（双重引用）
}
</code></pre> 
<p><code>ref</code> 从匹配的值上创建一个引用，由于 <code>reference</code> 已经是 <code>&amp;String</code>，<code>ref val</code> 会得到 <code>&amp;&amp;String</code>。打印时由于 <code>Debug</code> 的自动解引用，仍然会显示 <code>"Hello"</code>。</p> 
<h5>方案三：解引用后匹配值（需要所有权转移场景）</h5> 
<p>如果你确实需要取得 <code>String</code> 的所有权，那必须确保你有权移动它——例如从原来的所有者变量直接匹配，而不是从引用：</p> 
<pre><code class="language-rust">let s = String::from("Hello");
match s {        // 直接匹配 owned String
    val =&gt; println!("{}", val),   // val 获得所有权
}
</code></pre> 
<hr /> 
<h4>5. 总结</h4> 
<blockquote> 
 <p>为什么 <code>&amp;val</code> 模式对 <code>&amp;String</code> 报错，而对 <code>&amp;i32</code> 不报错？</p> 
</blockquote> 
<ul> 
 <li><strong><code>&amp;val</code> 模式会尝试从引用中取出背后的值</strong>。</li> 
 <li>对于 <code>i32</code>（<code>Copy</code>），取出是<strong>复制</strong>，安全且允许。</li> 
 <li>对于 <code>String</code>（非 <code>Copy</code>），取出是<strong>移动所有权</strong>，但共享引用 <code>&amp;String</code> 不拥有所有权，因此被编译器禁止。</li> 
</ul> 
<p>修正方法通常是不用 <code>&amp;val</code> 析构，而是直接匹配变量获得引用，或者小心处理所有权。</p>
        ]]></description>
    </item>
    
</channel>
</rss>
