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.

382 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>生命周期过大-01 - 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/compiler/fight-with-compiler/lifetime/too-long1.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="生命周期声明的范围过大"><a class="header" href="#生命周期声明的范围过大">生命周期声明的范围过大</a></h1>
<p>在大多时候Rust 的生命周期你只要标识了,即可以通过编译,但是总是存在一些情况,会导致编译无法通过,本文就讲述这样一种情况:因为生命周期声明的范围过大,导致了编译无法通过,希望大家喜欢</p>
<h2 id="例子-1"><a class="header" href="#例子-1">例子 1</a></h2>
<pre><pre class="playground"><code class="language-rust edition2021">struct Interface&lt;'a&gt; {
manager: &amp;'a mut Manager&lt;'a&gt;
}
impl&lt;'a&gt; Interface&lt;'a&gt; {
pub fn noop(self) {
println!("interface consumed");
}
}
struct Manager&lt;'a&gt; {
text: &amp;'a str
}
struct List&lt;'a&gt; {
manager: Manager&lt;'a&gt;,
}
impl&lt;'a&gt; List&lt;'a&gt; {
pub fn get_interface(&amp;'a mut self) -&gt; Interface {
Interface {
manager: &amp;mut self.manager
}
}
}
fn main() {
let mut list = List {
manager: Manager {
text: "hello"
}
};
list.get_interface().noop();
println!("Interface should be dropped here and the borrow released");
// this fails because inmutable/mutable borrow
// but Interface should be already dropped here and the borrow released
use_list(&amp;list);
}
fn use_list(list: &amp;List) {
println!("{}", list.manager.text);
}</code></pre></pre>
<p>运行后报错:</p>
<pre><code class="language-console">error[E0502]: cannot borrow `list` as immutable because it is also borrowed as mutable // `list`无法被借用,因为已经被可变借用
--&gt; src/main.rs:40:14
|
34 | list.get_interface().noop();
| ---- mutable borrow occurs here // 可变借用发生在这里
...
40 | use_list(&amp;list);
| ^^^^^
| |
| immutable borrow occurs here // 新的不可变借用发生在这
| mutable borrow later used here // 可变借用在这里结束
</code></pre>
<p>这段代码看上去并不复杂,实际上难度挺高的,首先在直觉上,<code>list.get_interface()</code>借用的可变引用,按理来说应该在这行代码结束后,就归还了,为何能持续到<code>use_list(&amp;list)</code>后面呢?</p>
<p>这是因为我们在<code>get_interface</code>方法中声明的<code>lifetime</code>有问题,该方法的参数的生明周期是<code>'a</code>,而<code>List</code>的生命周期也是<code>'a</code>,说明该方法至少活得跟<code>List</code>一样久,再回到<code>main</code>函数中,<code>list</code>可以活到<code>main</code>函数的结束,因此<code>list.get_interface()</code>借用的可变引用也会活到<code>main</code>函数的结束,在此期间,自然无法再进行借用了。</p>
<p>要解决这个问题,我们需要为<code>get_interface</code>方法的参数给予一个不同于<code>List&lt;'a&gt;</code>的生命周期<code>'b</code>,最终代码如下:</p>
<pre><pre class="playground"><code class="language-rust edition2021">struct Interface&lt;'b, 'a: 'b&gt; {
manager: &amp;'b mut Manager&lt;'a&gt;
}
impl&lt;'b, 'a: 'b&gt; Interface&lt;'b, 'a&gt; {
pub fn noop(self) {
println!("interface consumed");
}
}
struct Manager&lt;'a&gt; {
text: &amp;'a str
}
struct List&lt;'a&gt; {
manager: Manager&lt;'a&gt;,
}
impl&lt;'a&gt; List&lt;'a&gt; {
pub fn get_interface&lt;'b&gt;(&amp;'b mut self) -&gt; Interface&lt;'b, 'a&gt;
where 'a: 'b {
Interface {
manager: &amp;mut self.manager
}
}
}
fn main() {
let mut list = List {
manager: Manager {
text: "hello"
}
};
list.get_interface().noop();
println!("Interface should be dropped here and the borrow released");
// this fails because inmutable/mutable borrow
// but Interface should be already dropped here and the borrow released
use_list(&amp;list);
}
fn use_list(list: &amp;List) {
println!("{}", list.manager.text);
}</code></pre></pre>
<p>当然,咱还可以给生命周期给予更有意义的名称:</p>
<pre><pre class="playground"><code class="language-rust edition2021">struct Interface&lt;'text, 'manager&gt; {
manager: &amp;'manager mut Manager&lt;'text&gt;
}
impl&lt;'text, 'manager&gt; Interface&lt;'text, 'manager&gt; {
pub fn noop(self) {
println!("interface consumed");
}
}
struct Manager&lt;'text&gt; {
text: &amp;'text str
}
struct List&lt;'text&gt; {
manager: Manager&lt;'text&gt;,
}
impl&lt;'text&gt; List&lt;'text&gt; {
pub fn get_interface&lt;'manager&gt;(&amp;'manager mut self) -&gt; Interface&lt;'text, 'manager&gt;
where 'text: 'manager {
Interface {
manager: &amp;mut self.manager
}
}
}
fn main() {
let mut list = List {
manager: Manager {
text: "hello"
}
};
list.get_interface().noop();
println!("Interface should be dropped here and the borrow released");
// this fails because inmutable/mutable borrow
// but Interface should be already dropped here and the borrow released
use_list(&amp;list);
}
fn use_list(list: &amp;List) {
println!("{}", list.manager.text);
}</code></pre></pre>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../../../compiler/fight-with-compiler/lifetime/intro.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="../../../compiler/fight-with-compiler/lifetime/too-long2.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="../../../compiler/fight-with-compiler/lifetime/intro.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="../../../compiler/fight-with-compiler/lifetime/too-long2.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>