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.

308 lines
20 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.60 - 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.60.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-新版解读--160--重点-查看-cargo-构建耗时详情cargo-feature-增加新语法"><a class="header" href="#rust-新版解读--160--重点-查看-cargo-构建耗时详情cargo-feature-增加新语法">Rust 新版解读 | 1.60 | 重点: 查看 Cargo 构建耗时详情、Cargo Feature 增加新语法</a></h1>
<blockquote>
<p>原文链接: https://blog.rust-lang.org/2022/04/07/Rust-1.60.0.html</p>
</blockquote>
<p>通过 <a href="https://www.rust-lang.org/tools/install">rustup</a> 安装的同学可以使用以下命令升级到 1.60 版本:</p>
<pre><code class="language-shell">$ rustup update stable
</code></pre>
<h2 id="基于源码的代码覆盖"><a class="header" href="#基于源码的代码覆盖">基于源码的代码覆盖</a></h2>
<p>rustc 新增了基于 LLVM 的代码覆盖率测量,想要测试的同学可以通过以下方式重新构建你的项目:</p>
<pre><code class="language-shell">$ RUSTFLAGS="-C instrument-coverage" cargo build
</code></pre>
<p>运行新生成的可执行文件将在当前目录下产生一个 <code>default.profraw</code> 文件( 路径和文件名可以通过环境变量进行<a href="https://doc.rust-lang.org/stable/rustc/instrument-coverage.html#running-the-instrumented-binary-to-generate-raw-coverage-profiling-data">覆盖</a> )。</p>
<p><code>llvm-tools-preview</code> 组件包含了 <code>llvm-profdata</code>,可以用于处理和合并<ruby>原生的测量结果输出<rt>raw profile output)</rt></ruby>(测量区域执行数)。</p>
<p><code>llvm-cov</code> 用于报告生成,它将 <code>llvm-profdata</code> 处理后的输出跟二进制可执行文件自身相结合,对于前者大家可能好理解,但是为何要跟后者可执行文件相结合呢?原因在于可执行文件中嵌入了一个从计数器到实际源代码单元的映射。</p>
<pre><code class="language-shell">rustup component add llvm-tools-preview
$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-profdata merge -sparse default.profraw -o default.profdata
$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-cov show -Xdemangler=rustfilt target/debug/coverage-testing \
-instr-profile=default.profdata \
-show-line-counts-or-regions \
-show-instantiations
</code></pre>
<p>基于一个简单的 hello world 可执行文件,执行以上命令就可以获得如下带有标记的结果:</p>
<pre><pre class="playground"><code class="language-rust edition2021">1| 1|fn main() {
2| 1| println!("Hello, world!");
3| 1|}</code></pre></pre>
<p>从结果中可以看出:每一行代码都已经被成功覆盖。</p>
<p>如果大家还想要了解更多,可以看下<a href="https://doc.rust-lang.org/rustc/instrument-coverage.html">官方的 rustc 文档</a>。目前来说,基准功能已经稳定了,并将以某种形式存在于未来所有的 Rust 发布版本中。 但输出格式和产生这些输出的 LLVM 工具可能依然会发生变化,基于此,大家在使用时需要确保 <code>llvm-tools-preview</code> 和 rustc ( 用于编译代码的 )使用了相同的版本。</p>
<h2 id="查看-cargo-构建耗时"><a class="header" href="#查看-cargo-构建耗时">查看 Cargo 构建耗时</a></h2>
<p>新版本中,以下命令已经可以正常使用了:</p>
<pre><code class="language-shell">$ cargo build --timings
Compiling hello-world v0.1.0 (hello-world)
Timing report saved to target/cargo-timings/cargo-timing-20220318T174818Z.html
Finished dev [unoptimized + debuginfo] target(s) in 0.98s
</code></pre>
<p>此命令会生成一个 <code>cargo build</code> 的耗时详情报告,除了上面提到的路径外,报告还会被拷贝到 <code>target/cargo-timings/cargo-timing.html</code>。这里是一个<a href="https://blog.rust-lang.org/images/2022-04-07-timing.html">在线示例</a>。该报告在你需要提升构建速度时会非常有用,更多的信息请<a href="https://doc.rust-lang.org/nightly/cargo/reference/timings.html">查看文档</a></p>
<h2 id="cargo-feature-的新语法"><a class="header" href="#cargo-feature-的新语法">Cargo Feature 的新语法</a></h2>
<blockquote>
<p>关于 Cargo Features ,强烈推荐大家看看 <a href="https://course.rs/cargo/reference/features/intro.html">Cargo 使用指南</a>,可能是目前最好的中文翻译版本。</p>
</blockquote>
<p>新版本为 Cargo Features 引入了两个新的语法: 命名空间 ( Namespaced )和弱依赖,它们可以让 features 跟可选依赖进行更好的交互。</p>
<p>Cargo 支持<a href="https://course.rs/cargo/reference/features/intro.html#%E5%8F%AF%E9%80%89%E4%BE%9D%E8%B5%96">可选依赖</a>已经很久了,例如以下代码所示:</p>
<pre><code class="language-toml">[dependencies]
jpeg-decoder = { version = "0.1.20", default-features = false, optional = true }
[features]
# 通过开启 jpeg-decoder 依赖的 "rayon` feture来启用并行化处理
parallel = ["jpeg-decoder/rayon"]
</code></pre>
<p>这个例子有两点值得注意:</p>
<ul>
<li>可选依赖 <code>jpeg-decoder</code> 隐式地定义了一个同名的 feature当启用 <code>jpeg-decoder</code> feature 时将同时启用 <code>jpeg-decoder</code></li>
<li><code>"jpeg-decoder/rayon"</code> 语法会启用 <code>jpeg-decoder</code> 依赖,并且还会启用 <code>jpeg-decoder</code> 依赖的 <code>rayon</code> feature</li>
</ul>
<p>而命名空间正是为了处理第一个问题而出现的。新版本中,我们可以在 <code>[features]</code> 中使用 <code>dep:</code> 前缀来显式地引用一个可选的依赖。再无需像第一点一样:先隐式的将可选依赖暴露为一个 feature再通过 feature 来启用它。</p>
<p>这样一来,我们将能更好的定义可选依赖所对应的 feture包括将可选依赖隐藏在一个更具描述性的 feature 名称后面。</p>
<p>弱依赖用于处理第二点: 根据第二点,<code>optional-dependency/feature-name</code> 必定会启用 <code>optional-dependency</code> 这个可选依赖。然而在一些场景中,我们只希望在其它 features 已经启用了可选依赖 <code>optional-dependency</code> 时才去启用 <code>feature-name</code> 这个 feature。</p>
<p>从 1.60 开始,我们可以使用 <code>"package-name?/feature-name"</code> 这种带有 <code>?</code> 形式的语法: 只有当其它项已经启用了可选依赖 <code>package-name</code> 的情况下才去开启给定的 feature <code>feature-name</code></p>
<blockquote>
<p>译者注:简单来说,要启用 <code>feature</code> 必须需要别人先启用了其前置的可选依赖,再也无法像之前的第二点一样,既能开启可选依赖,又能启用 feature。</p>
</blockquote>
<p>例如,我们希望为自己的库增加一些序列化功能,它需要开启某个可选依赖中的指定 feature可以这么做:</p>
<pre><code class="language-toml">[dependencies]
serde = { version = "1.0.133", optional = true }
rgb = { version = "0.8.25", optional = true }
[features]
serde = ["dep:serde", "rgb?/serde"]
</code></pre>
<p>这里定义了以下关系:</p>
<ol>
<li>开启 <code>serde</code> feature 将启用可选的 <code>serde</code> 依赖</li>
<li>只有当 <code>rgb</code> 依赖在其它地方已经被启用后,此处才能启用 <code>rgb</code><code>serde</code> feature</li>
</ol>
<h2 id="增量编译重启开启"><a class="header" href="#增量编译重启开启">增量编译重启开启</a></h2>
<p><a href="https://course.rs/appendix/rust-versions/1.59.html">1.59 更新说明中</a>,我们有提到因为某些问题,增量编译被默认关闭了,现在官方修复了其中一些,并且确认目前的状态不会再影响用户的使用,因此在 1.60 版本中,增量编译又重新默认开启了。</p>
<h2 id="instant-单调性保证"><a class="header" href="#instant-单调性保证">Instant 单调性保证</a></h2>
<blockquote>
<p>译者注Instant 可以获取当前的时间,因此保证其单调增长是非常重要的,例如 uuid 的生成往往依赖于时间戳的单调增长,一旦时间回退,就可能出现 uuid 重复的情况。</p>
</blockquote>
<p>在目前所有的平台上,<code>Instant</code> 会去尝试使用系统提供的 API 来保证单调性行为( 目前主要针对 tier 1 的平台 )。然而在实际场景中这种单调性偶尔会因为硬件、虚拟化或操作系统bug 等原因而失效。</p>
<p>为了解决这些失效或是平台没有提供 API 的情况,<code>Instant::duration_since</code>, <code>Instant::elapsed</code><code>Instant::sub</code> 现在饱和为零( 这里不太好翻译,原文是 now saturate to zero大概意思是非负)。而在老版本中,这种时间回退的情况会导致 panic。</p>
<p><code>Instant::checked_duration_since</code> 也可以用于检测和处理单调性失败或 <code>Instants</code> 的减法顺序不正确的情况。</p>
<p>但是目前的解决方法会遮掩一些错误的发生因此在未来版本中Rust 可能会重新就某些场景引入 panic 机制。</p>
<p>在 1.60 版本前,单调性主要通过标准库的互斥锁 Mutex 或原子性 atomic 来保证,但是在 <code>Instant::now()</code> 调用频繁时,可能会导致明显的性能问题。</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../../appendix/rust-versions/1.59.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.61.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.59.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.61.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>