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.

311 lines
16 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.66 - 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.66.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-新版解读--166--重点-有字段枚举的显示判别"><a class="header" href="#rust-新版解读--166--重点-有字段枚举的显示判别">Rust 新版解读 | 1.66 | 重点: 有字段枚举的显示判别</a></h1>
<blockquote>
<p>Rust 1.66 官方 release doc: <a href="https://blog.rust-lang.org/2022/12/15/Rust-1.66.0.html">Announcing Rust 1.66.0 | Rust Blog</a></p>
</blockquote>
<p>通过 <a href="https://www.rust-lang.org/tools/install">rustup</a> 安装的同学可以使用以下命令升级到 1.66 版本:</p>
<pre><code class="language-shell">$ rustup update stable
</code></pre>
<h2 id="对有字段枚举的显示判别"><a class="header" href="#对有字段枚举的显示判别">对有字段枚举的显示判别</a></h2>
<p>枚举的显示判别在跨语言传递值时很关键,需要两个语言里每个枚举值的判别是一致的,比如:</p>
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[repr(u8)]
enum Bar {
A,
B,
C = 42,
D,
}
<span class="boring">}</span></code></pre></pre>
<p>这个例子里,枚举 <code>Bar</code> 使用了 <code>u8</code> 作为原语表形(representation),并且 <code>Bar::C</code> 使用 42 来判别,其它没有显示判别的枚举值会按照源码里地顺序自动地递增赋值,这里的 <code>Bar::A</code> 是0<code>Bar::B</code> 是1<code>Bar::D</code> 是43。如果没有显示判别那就只能在 <code>Bar::B</code><code>Bar::C</code> 之间加上 40 个无意义的枚举值了。</p>
<p>在1.66之前,枚举的显示判别只能用在无字段枚举上。现在对有字段枚举的显示判别也稳定了:</p>
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[repr(u8)]
enum Foo {
A(u8),
B(i8),
C(bool) = 42,
}
<span class="boring">}</span></code></pre></pre>
<p>注意:可以通过 <code>as</code> 转换(比如 <code>Bar::C as u8</code> )来判断一个无字段枚举的判别值,但是 Rust 还没有给有字段枚举提供语言层面上的获取原始判别值的方法,只能通过 unsafe 的代码来检查有字段枚举的判别值。考虑到这个使用场景往往出现在必须使用 unsafe 代码的跨语言的 FFI 里,希望这没有造成太大的负担。如果你的确需要的话,参考 <code>std::mem::discriminant</code></p>
<h2 id="黑盒方法-corehintblack_box"><a class="header" href="#黑盒方法-corehintblack_box">黑盒方法 <code>core::hint::black_box</code></a></h2>
<p>当对编译器产生的代码做基准测试时,常常需要阻止一些优化,比如下面的代码里, <code>push_cap</code> 在一个循环里执行了4次 <code>Vec::push</code> </p>
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn push_cap(v: &amp;mut Vec&lt;i32&gt;) {
for i in 0..4 {
v.push(i);
}
}
pub fn bench_push() -&gt; Duration {
let mut v = Vec::with_capacity(4);
let now = Instant::now();
push_cap(&amp;mut v);
now.elapsed()
}
<span class="boring">}</span></code></pre></pre>
<p>如果你检查一下在 x86_64 机器上编译的优化输出结果,你会注意到整个 <code>push_cap</code> 方法都被优化掉了...</p>
<pre><code class="language-text">example::bench_push:
sub rsp, 24
call qword ptr [rip + std::time::Instant::now@GOTPCREL]
lea rdi, [rsp + 8]
mov qword ptr [rsp + 8], rax
mov dword ptr [rsp + 16], edx
call qword ptr [rip + std::time::Instant::elapsed@GOTPCREL]
add rsp, 24
ret
</code></pre>
<p>现在可以通过调用 <code>black_box</code> 来避免类似情况的发送。 虽然实际上 <code>black_box</code> 内部只会取走值并直接返回,但是编译器会认为这个方法可能做任何事情。</p>
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use std::hint::black_box;
fn push_cap(v: &amp;mut Vec&lt;i32&gt;) {
for i in 0..4 {
v.push(i);
black_box(v.as_ptr());
}
}
<span class="boring">}</span></code></pre></pre>
<p>这样就可以得到展开循环的<a href="https://rust.godbolt.org/z/Ws1GGbY6Y">结果</a></p>
<pre><code class="language-text"> mov dword ptr [rbx], 0
mov qword ptr [rsp + 8], rbx
mov dword ptr [rbx + 4], 1
mov qword ptr [rsp + 8], rbx
mov dword ptr [rbx + 8], 2
mov qword ptr [rsp + 8], rbx
mov dword ptr [rbx + 12], 3
mov qword ptr [rsp + 8], rbx
</code></pre>
<p>你还能发现结果里有 <code>black_box</code> 带来的副作用,无意义的 <code>mov qword ptr [rsp + 8], rbx</code> 指令在每一次循环后出现,用来获取 <code>v.as_ptr()</code> 作为参数传递给并未真正使用的方法。</p>
<p>注意到上面的例子里,<code>push</code> 指令都不用考虑内存分配的问题,这是因为编译器运行在 <code>Vec::with_capacity(4)</code> 的条件下。你可以尝试改动一下 <code>black_box</code> 的位置或者在多处使用,来看看其对编译的优化输出的影响。</p>
<h2 id="cargo-remove"><a class="header" href="#cargo-remove"><code>cargo remove</code></a></h2>
<p>1.62里我们引入了 <code>cargo add</code> 来通过命令行给你的项目增加依赖项。现在可以使用 <code>cargo remove</code> 来移除依赖了。</p>
<h2 id="others"><a class="header" href="#others">Others</a></h2>
<p>其它更新细节和稳定的API列表参考<a href="https://blog.rust-lang.org/2022/12/15/Rust-1.66.0.html#stabilized-apis">原Blog</a></p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../../appendix/rust-versions/1.65.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.67.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.65.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.67.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>