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.
trpl-zh-cn/ch15-01-box.html

375 lines
36 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="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>使用 Box&lt;T&gt; 指向堆上数据 - Rust 程序设计语言 简体中文版</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-de23e50b.svg">
<link rel="shortcut icon" href="favicon-8114d1fc.png">
<link rel="stylesheet" href="css/variables-8adf115d.css">
<link rel="stylesheet" href="css/general-2459343d.css">
<link rel="stylesheet" href="css/chrome-ae938929.css">
<link rel="stylesheet" href="css/print-9e4910d8.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="fonts/fonts-9644e21d.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="mdbook-highlight-css" href="highlight-493f70e1.css">
<link rel="stylesheet" id="mdbook-tomorrow-night-css" href="tomorrow-night-4c0ae647.css">
<link rel="stylesheet" id="mdbook-ayu-highlight-css" href="ayu-highlight-3fdfc3ac.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="ferris-d33b75bf.css">
<link rel="stylesheet" href="theme/2018-edition-4e126c62.css">
<link rel="stylesheet" href="theme/semantic-notes-9b5766c0.css">
<link rel="stylesheet" href="theme/listing-cab26221.css">
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-e0ffcbc3.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-fb31ca2f.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="mdbook-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="mdbook-sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("mdbook-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 = false;
}
if (sidebar === 'visible') {
sidebar_toggle.checked = true;
} else {
html.classList.remove('sidebar-visible');
}
</script>
<nav id="mdbook-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="mdbook-sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="mdbook-page-wrapper" class="page-wrapper">
<div class="page">
<div id="mdbook-menu-bar-hover-placeholder"></div>
<div id="mdbook-menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="mdbook-sidebar-toggle" class="icon-button" for="mdbook-sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="mdbook-sidebar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></span>
</label>
<button id="mdbook-theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="mdbook-theme-list">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M371.3 367.1c27.3-3.9 51.9-19.4 67.2-42.9L600.2 74.1c12.6-19.5 9.4-45.3-7.6-61.2S549.7-4.4 531.1 9.6L294.4 187.2c-24 18-38.2 46.1-38.4 76.1L371.3 367.1zm-19.6 25.4l-116-104.4C175.9 290.3 128 339.6 128 400c0 3.9 .2 7.8 .6 11.6c1.8 17.5-10.2 36.4-27.8 36.4H96c-17.7 0-32 14.3-32 32s14.3 32 32 32H240c61.9 0 112-50.1 112-112c0-2.5-.1-5-.2-7.5z"/></svg></span>
</button>
<ul id="mdbook-theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-ayu">Ayu</button></li>
</ul>
<button id="mdbook-search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="mdbook-searchbar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg></span>
</button>
</div>
<h1 class="menu-title">Rust 程序设计语言 简体中文版</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<span class=fa-svg id="print-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg></span>
</a>
<a href="https://github.com/KaiserY/trpl-zh-cn/tree/main" title="Git repository" aria-label="Git repository">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg></span>
</a>
</div>
</div>
<div id="mdbook-search-wrapper" class="hidden">
<form id="mdbook-searchbar-outer" class="searchbar-outer">
<div class="search-wrapper">
<input type="search" id="mdbook-searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="mdbook-searchresults-outer" aria-describedby="searchresults-header">
<div class="spinner-wrapper">
<span class=fa-svg id="fa-spin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M304 48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zm0 416c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM48 304c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm464-48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM142.9 437c18.7-18.7 18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zm0-294.2c18.7-18.7 18.7-49.1 0-67.9S93.7 56.2 75 75s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zM369.1 437c18.7 18.7 49.1 18.7 67.9 0s18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9z"/></svg></span>
</div>
</div>
</form>
<div id="mdbook-searchresults-outer" class="searchresults-outer hidden">
<div id="mdbook-searchresults-header" class="searchresults-header"></div>
<ul id="mdbook-searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('mdbook-sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('mdbook-sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#mdbook-sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="mdbook-content" class="content">
<main>
<h2 id="使用-boxt-指向堆上的数据"><a class="header" href="#使用-boxt-指向堆上的数据">使用 <code>Box&lt;T&gt;</code> 指向堆上的数据</a></h2>
<p><a href="https://github.com/rust-lang/book/blob/ecef81cbc6f0c2d1c8a67409329b0641258c04c2/src/ch15-01-box.md">ch15-01-box.md</a></p>
<p>最简单直接的智能指针是 box其类型写作 <code>Box&lt;T&gt;</code>。Box 允许你将数据存储在堆上而不是栈上。留在栈上的则是指向堆数据的指针。如果你想回顾一下栈和堆之间的区别,可以参考第四章。</p>
<p>除了把数据存储在堆上而不是栈上之外box 没有性能开销。不过,它们也没有太多额外能力。你最常在以下这些场景中使用它们:</p>
<ul>
<li>当有一个在编译时未知大小的类型,而又想要在需要确切大小的上下文中使用这个类型值的时候</li>
<li>当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候</li>
<li>当希望拥有一个值并只关心它的类型是否实现了特定 trait 而不是其具体类型的时候</li>
</ul>
<p>我们会在<a href="#box-允许创建递归类型">“Box 允许创建递归类型”</a>一节中展示第一种场景。在第二种情况下,转移大量数据的所有权可能会花费很长时间,因为数据会在栈上被复制。为了改善这种场景下的性能,我们可以把大量数据放进 box 中存储到堆上。这样,只有少量指针数据会在栈上被复制,而它所指向的数据则会一直留在堆上的同一位置。第三种情况被称为<strong>trait 对象</strong><em>trait object</em>),第十八章中的<a href="ch18-02-trait-objects.html#使用-trait-object-来抽象出共享行为">“使用 trait 对象来抽象共享行为”</a>专门讨论了这个主题。所以你在这里学到的内容,还会在那一节中再次用到!</p>
<h3 id="在堆上存储数据"><a class="header" href="#在堆上存储数据">在堆上存储数据</a></h3>
<p>在讨论 <code>Box&lt;T&gt;</code> 的堆存储用例之前,让我们熟悉一下语法以及如何与存储在 <code>Box&lt;T&gt;</code> 中的值进行交互。</p>
<p>示例 15-1 展示了如何使用 box 在堆上存储一个 <code>i32</code> 值。</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre class="playground"><code class="language-rust edition2024">fn main() {
let b = Box::new(5);
println!("b = {b}");
}</code></pre>
<p><span class="caption">示例 15-1使用 box 在堆上储存一个 <code>i32</code></span></p>
<p>我们将变量 <code>b</code> 定义为一个 <code>Box</code>,它指向值 <code>5</code>,而这个值被分配在堆上。这个程序会打印 <code>b = 5</code>;在这个例子里,我们访问 box 中数据的方式,和数据位于栈上时的方式类似。和任何拥有所有权的值一样,当 box 离开作用域时,就像 <code>b</code><code>main</code> 结束时那样,它会被释放。释放时既会清理 box 本身(存储在栈上),也会清理它指向的数据(存储在堆上)。</p>
<p>把单个值放到堆上并没有太大意义,所以你不会经常像示例 15-1 那样单独使用 box。对于像单个 <code>i32</code> 这样的值来说,把它们放在默认存储位置栈上,在大多数情况下更合适。接下来,我们来看一个如果没有 box 就无法定义的类型。</p>
<h3 id="box-允许创建递归类型"><a class="header" href="#box-允许创建递归类型">Box 允许创建递归类型</a></h3>
<p><strong>递归类型</strong><em>recursive type</em>)的值可以拥有另一个同类型的值作为其自身的一部分。但是这会产生一个问题,因为 Rust 需要在编译时知道类型占用多少空间。递归类型的值嵌套理论上可以无限地进行下去,所以 Rust 不知道递归类型需要多少空间。因为 box 有一个已知的大小,所以通过在递归类型定义中插入 box就可以创建递归类型了。</p>
<p>作为递归类型的例子,让我们来看看 cons list。这是一种在函数式编程语言中常见的数据类型。我们将定义的 cons list 除了递归之外都很简单,因此这个例子里的概念,在你遇到更复杂的递归类型场景时也会很有用。</p>
<h4 id="理解-cons-list"><a class="header" href="#理解-cons-list">理解 cons list</a></h4>
<p>cons list 是一种来自 Lisp 编程语言及其方言的数据结构,由嵌套的 pair 组成,也是 Lisp 版本的链表。它的名字来源于 Lisp 中的 <code>cons</code> 函数(即 <em>construct function</em> 的缩写),这个函数用它的两个参数构造一个新的 pair。通过对一个由某个值和另一个 pair 组成的 pair 调用 <code>cons</code>,我们就能构造出由递归 pair 组成的 cons list。</p>
<p>例如这里有一个包含列表 <code>1, 2, 3</code> 的 cons list 的伪代码表示,其每个对在一个括号中:</p>
<pre><code class="language-text">(1, (2, (3, Nil)))
</code></pre>
<p>cons list 中的每一项都包含两个元素:当前项的值,以及下一项。列表中的最后一项只包含一个名为 <code>Nil</code> 的值而没有下一项。cons list 是通过递归调用 <code>cons</code> 函数构造出来的。用来表示递归基例的规范名称是 <code>Nil</code>。注意,这和第六章讨论过的 “null” 或 “nil” 概念并不相同,后者表示无效或缺失的值。</p>
<p>cons list 并不是一个 Rust 中常见的类型。大部分在 Rust 中需要列表的时候,<code>Vec&lt;T&gt;</code> 是一个更好的选择。其他更为复杂的递归数据类型<strong>确实</strong>在 Rust 的很多场景中很有用,不过通过以 cons list 作为开始,我们可以探索如何使用 box 毫不费力地定义一个递归数据类型。</p>
<p>示例 15-2 包含一个 cons list 的枚举定义。注意这还不能编译因为这个类型没有已知的大小,之后我们会展示:</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre><code class="language-rust ignore does_not_compile">enum List {
Cons(i32, List),
Nil,
}
<span class="boring">
</span><span class="boring">fn main() {}</span></code></pre>
<p><span class="caption">示例 15-2第一次尝试定义一个代表 <code>i32</code> 值的 cons list 数据结构的枚举</span></p>
<blockquote>
<p>注意:出于示例的需要我们选择实现一个只存放 <code>i32</code> 值的 cons list。也可以用泛型正如第十章讲到的来定义一个可以存放任何类型值的 cons list 类型。</p>
</blockquote>
<p>使用这个 cons list 来储存列表 <code>1, 2, 3</code> 将看起来如示例 15-3 所示:</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre><code class="language-rust ignore does_not_compile"><span class="boring">enum List {
</span><span class="boring"> Cons(i32, List),
</span><span class="boring"> Nil,
</span><span class="boring">}
</span><span class="boring">
</span>// --snip--
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Cons(2, Cons(3, Nil)));
}</code></pre>
<p><span class="caption">示例 15-3使用 <code>List</code> 枚举储存列表 <code>1, 2, 3</code></span></p>
<p>第一个 <code>Cons</code> 储存了 <code>1</code> 和另一个 <code>List</code> 值。这个 <code>List</code> 是另一个包含 <code>2</code><code>Cons</code> 值和下一个 <code>List</code> 值。接着又有另一个存放了 <code>3</code><code>Cons</code> 值和最后一个值为 <code>Nil</code><code>List</code>,非递归变体代表了列表的结尾。</p>
<p>如果尝试编译示例 15-3 的代码,会得到如示例 15-4 所示的错误:</p>
<pre><code class="language-console">$ cargo run
Compiling cons-list v0.1.0 (file:///projects/cons-list)
error[E0072]: recursive type `List` has infinite size
--&gt; src/main.rs:1:1
|
1 | enum List {
| ^^^^^^^^^
2 | Cons(i32, List),
| ---- recursive without indirection
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&amp;`) to break the cycle
|
2 | Cons(i32, Box&lt;List&gt;),
| ++++ +
error[E0391]: cycle detected when computing when `List` needs drop
--&gt; src/main.rs:1:1
|
1 | enum List {
| ^^^^^^^^^
|
= note: ...which immediately requires computing when `List` needs drop again
= note: cycle used when computing whether `List` needs drop
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
Some errors have detailed explanations: E0072, E0391.
For more information about an error, try `rustc --explain E0072`.
error: could not compile `cons-list` (bin "cons-list") due to 2 previous errors
</code></pre>
<p><span class="caption">示例 15-4尝试定义一个递归枚举时得到的错误</span></p>
<p>这个错误表明,这个类型“有无限大小”。原因在于,我们把 <code>List</code> 的一个变体定义成了递归的它直接持有另一个同类型的值。因此Rust 无法判断存储一个 <code>List</code> 值到底需要多少空间。让我们拆开看看为什么会出现这个错误。首先,先来看看 Rust 是如何决定存储非递归类型的值需要多少空间的。</p>
<h4 id="计算非递归类型的大小"><a class="header" href="#计算非递归类型的大小">计算非递归类型的大小</a></h4>
<p>回忆一下第六章讨论枚举定义时示例 6-2 中定义的 <code>Message</code> 枚举:</p>
<pre class="playground"><code class="language-rust edition2024">enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
<span class="boring">
</span><span class="boring">fn main() {}</span></code></pre>
<p>当 Rust 需要知道要为 <code>Message</code> 值分配多少空间时,它可以检查每一个变体并发现 <code>Message::Quit</code> 并不需要任何空间,<code>Message::Move</code> 需要足够储存两个 <code>i32</code> 值的空间,依此类推。因为 enum 实际上只会使用其中的一个变体,所以 <code>Message</code> 值所需的空间等于储存其最大变体的空间大小。</p>
<p>与之相对的是,当 Rust 试图确定像示例 15-2 中 <code>List</code> 枚举这样的递归类型需要多少空间时,会发生什么。编译器先查看 <code>Cons</code> 变体,它持有一个 <code>i32</code> 类型的值和一个 <code>List</code> 类型的值。因此,<code>Cons</code> 所需的空间等于一个 <code>i32</code> 的大小再加上一个 <code>List</code> 的大小。为了算出 <code>List</code> 类型需要多少内存,编译器又要继续查看它的变体,并再次从 <code>Cons</code> 开始。<code>Cons</code> 又持有一个 <code>i32</code> 和一个 <code>List</code>,这个过程就会无限持续下去,如图 15-1 所示:</p>
<img alt="An infinite Cons list" src="img/trpl15-01.svg" class="center" style="width: 50%;" />
<p><span class="caption">图 15-1一个包含无限个 <code>Cons</code> 变体的无限 <code>List</code></span></p>
<h4 id="获取一个已知大小的给递归类型"><a class="header" href="#获取一个已知大小的给递归类型">获取一个已知大小的给递归类型</a></h4>
<p>因为 Rust 无法计算出要为定义为递归的类型分配多少空间,所以编译器给出了一个包括了有用建议的错误:</p>
<pre><code class="language-text">help: insert some indirection (e.g., a `Box`, `Rc`, or `&amp;`) to break the cycle
|
2 | Cons(i32, Box&lt;List&gt;),
| ++++ +
</code></pre>
<p>在这里,<em>indirection</em> 的意思是:不要直接存储一个值,而是通过存储一个指向该值的指针,间接地存储它。</p>
<p>因为 <code>Box&lt;T&gt;</code> 是一个指针Rust 总是知道 <code>Box&lt;T&gt;</code> 需要多少空间:指针的大小并不会随它指向的数据量而变化。这意味着我们可以在 <code>Cons</code> 变体中放一个 <code>Box&lt;T&gt;</code>,而不是直接再放一个 <code>List</code> 值。这个 <code>Box&lt;T&gt;</code> 会指向下一个位于堆上的 <code>List</code> 值,而不是把这个 <code>List</code> 值直接放在 <code>Cons</code> 变体内部。从概念上说,我们仍然有一个“由列表组成的列表”,但现在这种实现更像是把这些项彼此相连,而不是一层层相互包含。</p>
<p>我们可以修改示例 15-2 中 <code>List</code> 枚举的定义和示例 15-3 中对 <code>List</code> 的应用,如示例 15-5 所示,这是可以编译的:</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre class="playground"><code class="language-rust edition2024">enum List {
Cons(i32, Box&lt;List&gt;),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}</code></pre>
<p><span class="caption">示例 15-5为了拥有已知大小而使用 <code>Box&lt;T&gt;</code><code>List</code> 定义</span></p>
<p><code>Cons</code> 变体将会需要一个 <code>i32</code> 的大小加上储存 box 指针数据的空间。<code>Nil</code> 变体不储存值,所以它比 <code>Cons</code> 变体需要更少的空间。现在我们知道了任何 <code>List</code> 值最多需要一个 <code>i32</code> 加上 box 指针数据的大小。通过使用 box打破了这无限递归的连锁这样编译器就能够计算出储存 <code>List</code> 值需要的大小了。图 15-2 展示了现在 <code>Cons</code> 变体看起来像什么:</p>
<img alt="A finite Cons list" src="img/trpl15-02.svg" class="center" />
<p><span class="caption">图 15-2因为 <code>Cons</code> 存放一个 <code>Box</code> 所以 <code>List</code> 不是无限大小的了</span></p>
<p>Box 只提供间接存储和堆分配;它没有我们将在其他智能指针类型中看到的那些额外特殊能力。它也没有那些特殊能力带来的性能开销,因此在像 cons list 这样我们只需要“间接存储”这一特性的场景里Box 就很有用。我们还会在第十八章看到更多 Box 的用例。</p>
<p><code>Box&lt;T&gt;</code> 类型之所以是智能指针,是因为它实现了 <code>Deref</code> trait这让 <code>Box&lt;T&gt;</code> 的值可以像引用一样被处理。当 <code>Box&lt;T&gt;</code> 的值离开作用域时,由于 <code>Drop</code> trait 的实现box 指向的堆数据也会被清理掉。这两个 trait 对本章余下将讨论的其他智能指针类型所提供的功能会更加重要。接下来,我们更详细地看看这两个 trait。</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="ch15-00-smart-pointers.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span>
</a>
<a rel="next prefetch" href="ch15-02-deref.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="ch15-00-smart-pointers.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span>
</a>
<a rel="next prefetch" href="ch15-02-deref.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
</nav>
</div>
<template id=fa-eye><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></template>
<template id=fa-eye-slash><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg></span></template>
<template id=fa-copy><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg></span></template>
<template id=fa-play><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg></span></template>
<template id=fa-clock-rotate-left><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9V168c0 13.3 10.7 24 24 24H134.1c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24V256c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65V152c0-13.3-10.7-24-24-24z"/></svg></span></template>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr-ef4e11c1.min.js"></script>
<script src="mark-09e88c2c.min.js"></script>
<script src="searcher-c2a407aa.js"></script>
<script src="clipboard-1626706a.min.js"></script>
<script src="highlight-abc7f01d.js"></script>
<script src="book-a0b12cfe.js"></script>
<!-- Custom JS scripts -->
<script src="ferris-2317480c.js"></script>
</div>
</body>
</html>