You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
17 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE HTML>
<html lang="zh-CN" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>1.65 - Rust语言圣经(Rust Course)</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../../favicon.svg">
<link rel="shortcut icon" href="../../favicon.png">
<link rel="stylesheet" href="../../css/variables.css">
<link rel="stylesheet" href="../../css/general.css">
<link rel="stylesheet" href="../../css/chrome.css">
<link rel="stylesheet" href="../../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="highlight-css" href="../../highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="../../tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="../../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="../../theme/style.css">
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "../../";
const default_light_theme = "light";
const default_dark_theme = "navy";
</script>
<!-- Start loading toc.js asap -->
<script src="../../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Rust语言圣经(Rust Course)</h1>
<div class="right-buttons">
<a href="../../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/sunface/rust-course" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/sunface/rust-course/edit/main/src/appendix/rust-versions/1.65.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="rust-新版解读--165--重点-泛型关联类型新绑定语法"><a class="header" href="#rust-新版解读--165--重点-泛型关联类型新绑定语法">Rust 新版解读 | 1.65 | 重点: 泛型关联类型,新绑定语法!</a></h1>
<blockquote>
<p>Rust 1.65 官方 release doc: <a href="https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html">Announcing Rust 1.65.0 | Rust Blog</a></p>
</blockquote>
<p>通过 <a href="https://www.rust-lang.org/tools/install">rustup</a> 安装的同学可以使用以下命令升级到 1.65 版本:</p>
<pre><code class="language-shell">$ rustup update stable
</code></pre>
<h2 id="泛型关联类型-generic-associated-types-gats"><a class="header" href="#泛型关联类型-generic-associated-types-gats">泛型关联类型 Generic associated types (GATs)</a></h2>
<p>关联类型associated types里现在可以加上生命周期、类型、const泛型了类似于</p>
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Foo {
type Bar&lt;'x&gt;;
}
<span class="boring">}</span></code></pre></pre>
<p>三言两语说不清这个变化的好处,看几个例子来感受一下:</p>
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>/// 一个类似于 `Iterator` 的 trait ,可以借用 `Self`。
trait LendingIterator {
type Item&lt;'a&gt; where Self: 'a;
fn next&lt;'a&gt;(&amp;'a mut self) -&gt; Option&lt;Self::Item&lt;'a&gt;&gt;;
}
/// 可以给智能指针类型,比如 `Rc` 和 `Arc` 实现的 trait来实现指针类型的泛用性
trait PointerFamily {
type Pointer&lt;T&gt;: Deref&lt;Target = T&gt;;
fn new&lt;T&gt;(value: T) -&gt; Self::Pointer&lt;T&gt;;
}
/// 允许借用数组对象,对不需要连续存储数据的固定长度数组类型很有用
trait BorrowArray&lt;T&gt; {
type Array&lt;'x, const N: usize&gt; where Self: 'x;
fn borrow_array&lt;'a, const N: usize&gt;(&amp;'a self) -&gt; Self::Array&lt;'a, N&gt;;
}
<span class="boring">}</span></code></pre></pre>
<p>泛型关联类型十分通用,能够写出许多之前无法实现的模式。更多的信息可以参考下面的链接:</p>
<ul>
<li><a href="https://blog.rust-lang.org/2021/08/03/GATs-stabilization-push.html">2021/08/03/GAT稳定版本推进</a></li>
<li><a href="https://blog.rust-lang.org/2022/10/28/gats-stabilization.html">2022/10/28/GAT稳定版本发布公告</a></li>
</ul>
<p>第一个对上面的例子进行了更深入的讨论,第二个讨论了一些已知的局限性。</p>
<p>更深入的阅读可以在关联类型的 <a href="https://doc.rust-lang.org/nightly/reference/items/associated-items.html#associated-types">nightly reference</a><a href="https://rust-lang.github.io/rfcs/1598-generic_associated_types.html">原始 RFC</a>已经过去6.5年了!) 里找到。</p>
<h2 id="let---else-语法"><a class="header" href="#let---else-语法"><code>let</code> - <code>else</code> 语法</a></h2>
<p>新的 <code>let</code> 语法,尝试模式匹配,找不到匹配的情况下执行发散的 <code>else</code> 块。</p>
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let PATTERN: TYPE = EXPRESSION else {
DIVERGING_CODE;
};
<span class="boring">}</span></code></pre></pre>
<p>常规的 <code>let</code> 语法仅能使用 <code>irrefutable patterns</code>,直译为不可反驳的模式,也就是一定要匹配上。一般情况下都是单个变量绑定,也用在解开结构体,元组,数组等复合类型上。原先并不适用条件匹配,比如从枚举里确定枚举值。直到现在我们有了 <code>let</code> - <code>else</code>。这是 <code>refutable pattern</code>,直译为可反驳的模式,能够像常规 <code>let</code> 一样匹配并绑定变量到周围范围内,在模式不匹配的时候执行发送的 <code>else</code> (可以是 <code>break</code>, <code>return</code>, <code>panic!</code>)。</p>
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn get_count_item(s: &amp;str) -&gt; (u64, &amp;str) {
let mut it = s.split(' ');
let (Some(count_str), Some(item)) = (it.next(), it.next()) else {
panic!("Can't segment count item pair: '{s}'");
};
let Ok(count) = u64::from_str(count_str) else {
panic!("Can't parse integer: '{count_str}'");
};
(count, item)
}
assert_eq!(get_count_item("3 chairs"), (3, "chairs"));
<span class="boring">}</span></code></pre></pre>
<p><code>if</code> - <code>else</code><code>match</code> 或者 <code>if let</code> 最大不一样的地方是变量绑定的范围,在此之前你需要多写一点重复的代码和一次外层的 <code>let</code> 绑定来完成:</p>
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span> let (count_str, item) = match (it.next(), it.next()) {
(Some(count_str), Some(item)) =&gt; (count_str, item),
_ =&gt; panic!("Can't segment count item pair: '{s}'"),
};
let count = if let Ok(count) = u64::from_str(count_str) {
count
} else {
panic!("Can't parse integer: '{count_str}'");
};
<span class="boring">}</span></code></pre></pre>
<h2 id="break-跳出标记过的代码块"><a class="header" href="#break-跳出标记过的代码块"><code>break</code> 跳出标记过的代码块</a></h2>
<p>块表达式现在可以标记为 <code>break</code> 的目标,来达到提前终止块的目的。这听起来有点像 <code>goto</code> 语法,不过这并不是随意的跳转,只能从块里跳转到块末尾。这在之前已经可以用 <code>loop</code> 块来实现了,你可能大概率见过这种总是只执行一次的 <code>loop</code></p>
<p>1.65 可以直接给块语句添加标记来提前退出了,还可以携带返回值:</p>
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let result = 'block: {
do_thing();
if condition_not_met() {
break 'block 1;
}
do_next_thing();
if condition_not_met() {
break 'block 2;
}
do_last_thing();
3
};
<span class="boring">}</span></code></pre></pre>
<h2 id="others"><a class="header" href="#others">Others</a></h2>
<p>其它更新细节和稳定的API列表参考<a href="https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html">原Blog</a></p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../../appendix/rust-versions/1.64.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../../appendix/rust-versions/1.66.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../../appendix/rust-versions/1.64.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../../appendix/rust-versions/1.66.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../../ace.js"></script>
<script src="../../editor.js"></script>
<script src="../../mode-rust.js"></script>
<script src="../../theme-dawn.js"></script>
<script src="../../theme-tomorrow_night.js"></script>
<script src="../../elasticlunr.min.js"></script>
<script src="../../mark.min.js"></script>
<script src="../../searcher.js"></script>
<script src="../../clipboard.min.js"></script>
<script src="../../highlight.js"></script>
<script src="../../book.js"></script>
<!-- Custom JS scripts -->
<script src="../../assets/custom2.js"></script>
<script src="../../assets/bigPicture.js"></script>
</div>
</body>
</html>