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.

312 lines
18 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.78 - 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.78.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-新版解读--178--诊断属性宏"><a class="header" href="#rust-新版解读--178--诊断属性宏">Rust 新版解读 | 1.78 | 诊断属性宏</a></h1>
<blockquote>
<p>Rust 1.78 官方 release doc: <a href="https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html">Announcing Rust 1.78.0 | Rust Blog</a></p>
</blockquote>
<p>通过 <a href="https://www.rust-lang.org/tools/install">rustup</a> 安装的同学可以使用以下命令升级到 1.78 版本:</p>
<pre><code class="language-shell">$ rustup update stable
</code></pre>
<h2 id="诊断属性宏"><a class="header" href="#诊断属性宏">诊断属性宏</a></h2>
<p>Rust 现在支持 <code>#[diagnostic]</code> 属性命名空间,用于影响编译器错误消息。这些被视为提示,编译器不需要使用它们,也不会因为提供了编译器不认识的诊断而报错。这种灵活性允许源代码提供诊断,即使不是所有编译器都支持,无论是不同版本还是完全不同的实现。</p>
<p>随着这个命名空间的出现,第一个支持的属性 <code>#[diagnostic::on_unimplemented]</code> 也随之而来,可以放在一个 trait 上,用于自定义当需要但未在类型上实现该 trait 时的消息。考虑下面来自<a href="https://github.com/rust-lang/rust/pull/119888/">稳定 PR</a> 里的示例:</p>
<pre><pre class="playground"><code class="language-rust edition2021">#[diagnostic::on_unimplemented(
message = "My Message for `ImportantTrait&lt;{A}&gt;` is not implemented for `{Self}`",
label = "My Label",
note = "Note 1",
note = "Note 2"
)]
trait ImportantTrait&lt;A&gt; {}
fn use_my_trait(_: impl ImportantTrait&lt;i32&gt;) {}
fn main() {
use_my_trait(String::new());
}</code></pre></pre>
<p>此前,编译器会给出一个内置错误,如下:</p>
<pre><code class="language-shell">error[E0277]: the trait bound `String: ImportantTrait&lt;i32&gt;` is not satisfied
--&gt; src/main.rs:12:18
|
12 | use_my_trait(String::new());
| ------------ ^^^^^^^^^^^^^ the trait `ImportantTrait&lt;i32&gt;` is not implemented for `String`
| |
| required by a bound introduced by this call
|
</code></pre>
<p>现在,使用 <code>#[diagnostic::on_unimplemented]</code>,自定义消息填充主要错误行,自定义标签放在源输出上。原始标签仍然写在帮助输出中,任何自定义注释也会被写入。 (这些细节未来可能会发生变化。)</p>
<pre><code class="language-shell">error[E0277]: My Message for `ImportantTrait&lt;i32&gt;` is not implemented for `String`
--&gt; src/main.rs:12:18
|
12 | use_my_trait(String::new());
| ------------ ^^^^^^^^^^^^^ My Label
| |
| required by a bound introduced by this call
|
= help: the trait `ImportantTrait&lt;i32&gt;` is not implemented for `String`
= note: Note 1
= note: Note 2
</code></pre>
<p>对于 trait 作者来说,如果你能提供更好的提示,而不是仅仅给出缺失部分,这种诊断就更有用。例如,这是标准库中的一个示例:</p>
<pre><pre class="playground"><code class="language-rust edition2021"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[diagnostic::on_unimplemented(
message = "the size for values of type `{Self}` cannot be known at compilation time",
label = "doesn't have a size known at compile-time"
)]
pub trait Sized {}
<span class="boring">}</span></code></pre></pre>
<p>更多信息,请参考<a href="https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-diagnostic-tool-attribute-namespace">诊断工具属性命名空间</a>的参考部分。</p>
<h2 id="不安全前提断言"><a class="header" href="#不安全前提断言">不安全前提断言</a></h2>
<p>Rust 标准库有许多用于不安全函数前提的断言,但历史上它们只在标准库的 <code>#[cfg(debug_assertions)]</code> 构建中启用,以避免影响发布性能。然而,由于标准库通常以发布模式编译和分发,大多数 Rust 开发者根本没有执行这些检查。</p>
<p>现在,这些断言的条件被延迟到代码生成,因此它们将根据用户自己对调试断言的设置进行检查(在调试和测试构建中默认启用)。这个变化有助于用户捕获他们代码中的未定义行为。</p>
<p>例如,<code>slice::from_raw_parts</code> 需要一个对齐的非空指针。下面故意错位指针的使用有未定义行为,虽然如果你运气不好,它可能在过去看起来“工作”,但调试断言现在可以捕获它:</p>
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
let slice: &amp;[u8] = &amp;[1, 2, 3, 4, 5];
let ptr = slice.as_ptr();
// 创建一个 `ptr` 的偏移量,它总是比 `u16` 的正确对齐少一个
let i = usize::from(ptr as usize &amp; 1 == 0);
let slice16: &amp;[u16] = unsafe { std::slice::from_raw_parts(ptr.add(i).cast::&lt;u16&gt;(), 2) };
dbg!(slice16);
}</code></pre></pre>
<p>在调试构建中,这将导致一个 panic</p>
<pre><code class="language-shell">thread 'main' panicked at library/core/src/panicking.rs:220:5:
unsafe precondition(s) violated: slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread caused non-unwinding panic. aborting.
</code></pre>
<h2 id="确定性重新对齐"><a class="header" href="#确定性重新对齐">确定性重新对齐</a></h2>
<p>标准库有一些函数可以改变指针和切片的对齐方式,但以前它们有一些注意事项,使它们在实践中难以依赖,如果你严格遵循它们的文档。这些注意事项主要是为了保护对 <code>const</code> 的判断,但它们只对非 <code>const</code> 使用稳定。现在它们承诺根据实际输入具有一致的运行时行为。</p>
<ul>
<li>
<p><a href="https://doc.rust-lang.org/std/primitive.pointer.html#method.align_offset"><code>pointer::align_offset</code></a> 计算改变指针到给定对齐方式所需的偏移量。如果不可能,它将返回 <code>usize::MAX</code>,但以前允许它始终返回 <code>usize::MAX</code>,现在这种行为被移除。</p>
</li>
<li>
<p><a href="https://doc.rust-lang.org/std/primitive.slice.html#method.align_to"><code>slice::align_to</code></a><a href="https://doc.rust-lang.org/std/primitive.slice.html#method.align_to_mut"><code>slice::align_to_mut</code></a> 都将切片转换为对齐的中间切片和剩余的不对齐头和尾切片。这些方法现在承诺返回最大可能的中间部分,而不允许实现返回不那么优化的东西,比如将所有东西作为头切片返回。</p>
</li>
</ul>
<h2 id="others"><a class="header" href="#others">Others</a></h2>
<p>其它更新细节和稳定的API列表参考<a href="https://blog.rust-lang.org/2024/05/02/Rust-1.78.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.77.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.79.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.77.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.79.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>