|
|
<!DOCTYPE HTML>
|
|
|
<html lang="en" class="light sidebar-visible" dir="ltr">
|
|
|
<head>
|
|
|
<!-- Book generated using mdBook -->
|
|
|
<meta charset="UTF-8">
|
|
|
<title>使用 Deref Trait 将智能指针当作常规引用处理 - 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-7d935aa5.js";
|
|
|
</script>
|
|
|
<!-- Start loading toc.js asap -->
|
|
|
<script src="toc-9d5d6d0e.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="使用-deref-trait-将智能指针当作常规引用处理"><a class="header" href="#使用-deref-trait-将智能指针当作常规引用处理">使用 <code>Deref</code> Trait 将智能指针当作常规引用处理</a></h2>
|
|
|
<!-- https://github.com/rust-lang/book/blob/main/src/ch15-02-deref.md -->
|
|
|
<!-- commit 56ec353290429e6547109e88afea4de027b0f1a9 -->
|
|
|
<p>实现 <code>Deref</code> trait 允许我们定制<strong>解引用运算符</strong>(<em>dereference operator</em>)<code>*</code>(不要与乘法运算符或通配符相混淆)。通过这种方式实现 <code>Deref</code> trait 的智能指针可以被当作常规引用来对待,可以编写操作引用的代码并同样适用于智能指针。</p>
|
|
|
<p>让我们首先看看解引用运算符如何处理常规引用,接着尝试定义我们自己的类似 <code>Box<T></code> 的类型并看看为何解引用运算符不能像引用一样工作。我们会探索如何实现 <code>Deref</code> trait 使得智能指针以类似引用的方式工作变为可能。最后,我们会讨论 Rust 的 <strong>Deref 强制转换</strong>(<em>deref coercions</em>)特性以及它是如何处理引用或智能指针的。</p>
|
|
|
<blockquote>
|
|
|
<p>我们将要构建的 <code>MyBox<T></code> 类型与真正的 <code>Box<T></code> 有一个很大的区别:我们的版本不会在堆上储存数据。这个例子重点关注 <code>Deref</code>,所以其数据实际存放在何处,相比其类似指针的行为来说不算重要。</p>
|
|
|
</blockquote>
|
|
|
<h3 id="追踪指针的值"><a class="header" href="#追踪指针的值">追踪指针的值</a></h3>
|
|
|
<p>常规引用是一个指针类型,一种理解指针的方式是将其看成指向储存在其他某处值的箭头。在示例 15-6 中,创建了一个 <code>i32</code> 值的引用,接着使用解引用运算符来跟踪所引用的值:</p>
|
|
|
<p><span class="filename">文件名:src/main.rs</span></p>
|
|
|
<pre class="playground"><code class="language-rust edition2024">fn main() {
|
|
|
let x = 5;
|
|
|
let y = &x;
|
|
|
|
|
|
assert_eq!(5, x);
|
|
|
assert_eq!(5, *y);
|
|
|
}</code></pre>
|
|
|
<p><span class="caption">示例 15-6:使用解引用运算符来跟踪 <code>i32</code> 值的引用</span></p>
|
|
|
<p>变量 <code>x</code> 存放了一个 <code>i32</code> 值 <code>5</code>。<code>y</code> 等于 <code>x</code> 的一个引用。可以断言 <code>x</code> 等于 <code>5</code>。然而,如果希望对 <code>y</code> 的值做出断言,必须使用 <code>*y</code> 来追踪引用所指向的值(也就是<strong>解引用</strong>),这样编译器就可以比较实际的值了。一旦解引用了 <code>y</code>,就可以访问 <code>y</code> 所指向的整型值并可以与 <code>5</code> 做比较。</p>
|
|
|
<p>相反如果尝试编写 <code>assert_eq!(5, y);</code>,则会得到如下编译错误:</p>
|
|
|
<pre><code class="language-console">$ cargo run
|
|
|
Compiling deref-example v0.1.0 (file:///projects/deref-example)
|
|
|
error[E0277]: can't compare `{integer}` with `&{integer}`
|
|
|
--> src/main.rs:6:5
|
|
|
|
|
|
|
6 | assert_eq!(5, y);
|
|
|
| ^^^^^^^^^^^^^^^^ no implementation for `{integer} == &{integer}`
|
|
|
|
|
|
|
= help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`
|
|
|
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
|
|
|
|
|
|
For more information about this error, try `rustc --explain E0277`.
|
|
|
error: could not compile `deref-example` (bin "deref-example") due to 1 previous error
|
|
|
</code></pre>
|
|
|
<p>不允许比较数字的引用与数字,因为它们是不同的类型。必须使用解引用运算符追踪引用所指向的值。</p>
|
|
|
<h3 id="像引用一样使用-boxt"><a class="header" href="#像引用一样使用-boxt">像引用一样使用 <code>Box<T></code></a></h3>
|
|
|
<p>可以使用 <code>Box<T></code> 代替引用来重写示例 15-6 中的代码,示例 15-7 中 <code>Box<T></code> 上使用的解引用运算符与示例 15-6 中引用上使用的解引用运算符有着一样的功能:</p>
|
|
|
<p><span class="filename">文件名:src/main.rs</span></p>
|
|
|
<pre class="playground"><code class="language-rust edition2024">fn main() {
|
|
|
let x = 5;
|
|
|
let y = Box::new(x);
|
|
|
|
|
|
assert_eq!(5, x);
|
|
|
assert_eq!(5, *y);
|
|
|
}</code></pre>
|
|
|
<p><span class="caption">示例 15-7:在 <code>Box<i32></code> 上使用解引用运算符</span></p>
|
|
|
<p>示例 15-7 相比示例 15-6 主要不同的地方就是将 <code>y</code> 设置为一个指向 <code>x</code> 值拷贝的 <code>Box<T></code> 实例,而不是指向 <code>x</code> 值的引用。在最后的断言中,可以使用解引用运算符以 <code>y</code> 为引用时相同的方式追踪 <code>Box<T></code> 的指针。接下来让我们通过实现自己的类型来探索 <code>Box<T></code> 能这么做有何特殊之处。</p>
|
|
|
<h3 id="自定义智能指针"><a class="header" href="#自定义智能指针">自定义智能指针</a></h3>
|
|
|
<p>为了体会默认情况下智能指针与引用的不同,让我们创建一个类似于标准库提供的 <code>Box<T></code> 类型的智能指针。接着学习如何增加使用解引用运算符的功能。</p>
|
|
|
<p>从根本上说,<code>Box<T></code> 被定义为包含一个元素的元组结构体,所以示例 15-8 以相同的方式定义了 <code>MyBox<T></code> 类型。我们还定义了 <code>new</code> 函数来对应定义于 <code>Box<T></code> 的 <code>new</code> 函数:</p>
|
|
|
<p><span class="filename">文件名:src/main.rs</span></p>
|
|
|
<pre class="playground"><code class="language-rust edition2024">struct MyBox<T>(T);
|
|
|
|
|
|
impl<T> MyBox<T> {
|
|
|
fn new(x: T) -> MyBox<T> {
|
|
|
MyBox(x)
|
|
|
}
|
|
|
}
|
|
|
<span class="boring">
|
|
|
</span><span class="boring">fn main() {}</span></code></pre>
|
|
|
<p><span class="caption">示例 15-8:定义 <code>MyBox<T></code> 类型</span></p>
|
|
|
<p>这里定义了一个结构体 <code>MyBox</code> 并声明了一个泛型参数 <code>T</code>,因为我们希望其可以存放任何类型的值。<code>MyBox</code> 是一个包含 <code>T</code> 类型元素的元组结构体。<code>MyBox::new</code> 函数获取一个 <code>T</code> 类型的参数并返回一个存放传入值的 <code>MyBox</code> 实例。</p>
|
|
|
<p>尝试将示例 15-7 中的代码加入示例 15-8 中并修改 <code>main</code> 使用我们定义的 <code>MyBox<T></code> 类型代替 <code>Box<T></code>。示例 15-9 中的代码不能编译,因为 Rust 不知道如何解引用 <code>MyBox</code>:</p>
|
|
|
<p><span class="filename">文件名:src/main.rs</span></p>
|
|
|
<pre><code class="language-rust ignore does_not_compile"><span class="boring">struct MyBox<T>(T);
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring">impl<T> MyBox<T> {
|
|
|
</span><span class="boring"> fn new(x: T) -> MyBox<T> {
|
|
|
</span><span class="boring"> MyBox(x)
|
|
|
</span><span class="boring"> }
|
|
|
</span><span class="boring">}
|
|
|
</span><span class="boring">
|
|
|
</span>fn main() {
|
|
|
let x = 5;
|
|
|
let y = MyBox::new(x);
|
|
|
|
|
|
assert_eq!(5, x);
|
|
|
assert_eq!(5, *y);
|
|
|
}</code></pre>
|
|
|
<p><span class="caption">示例 15-9:尝试以使用引用和 <code>Box<T></code> 相同的方式使用 <code>MyBox<T></code></span></p>
|
|
|
<p>下面是相应的编译错误:</p>
|
|
|
<pre><code class="language-console">$ cargo run
|
|
|
Compiling deref-example v0.1.0 (file:///projects/deref-example)
|
|
|
error[E0614]: type `MyBox<{integer}>` cannot be dereferenced
|
|
|
--> src/main.rs:14:19
|
|
|
|
|
|
|
14 | assert_eq!(5, *y);
|
|
|
| ^^
|
|
|
|
|
|
For more information about this error, try `rustc --explain E0614`.
|
|
|
error: could not compile `deref-example` (bin "deref-example") due to 1 previous error
|
|
|
</code></pre>
|
|
|
<p><code>MyBox<T></code> 类型不能解引用,因为我们尚未在该类型上实现这个功能。为了启用 <code>*</code> 运算符的解引用功能,需要实现 <code>Deref</code> trait。</p>
|
|
|
<h3 id="实现-deref-trait"><a class="header" href="#实现-deref-trait">实现 <code>Deref</code> trait</a></h3>
|
|
|
<p>如第十章 <a href="ch10-02-traits.html#为类型实现-trait">“为类型实现 trait”</a> 部分所讨论的,为了实现 trait,需要提供 trait 所需的方法实现。<code>Deref</code> trait,由标准库提供,要求实现名为 <code>deref</code> 的方法,其借用 <code>self</code> 并返回一个内部数据的引用。示例 15-10 包含定义于 <code>MyBox</code> 之上的 <code>Deref</code> 实现:</p>
|
|
|
<p><span class="filename">文件名:src/main.rs</span></p>
|
|
|
<pre class="playground"><code class="language-rust edition2024">use std::ops::Deref;
|
|
|
|
|
|
impl<T> Deref for MyBox<T> {
|
|
|
type Target = T;
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
&self.0
|
|
|
}
|
|
|
}
|
|
|
<span class="boring">
|
|
|
</span><span class="boring">struct MyBox<T>(T);
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring">impl<T> MyBox<T> {
|
|
|
</span><span class="boring"> fn new(x: T) -> MyBox<T> {
|
|
|
</span><span class="boring"> MyBox(x)
|
|
|
</span><span class="boring"> }
|
|
|
</span><span class="boring">}
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span><span class="boring"> let x = 5;
|
|
|
</span><span class="boring"> let y = MyBox::new(x);
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring"> assert_eq!(5, x);
|
|
|
</span><span class="boring"> assert_eq!(5, *y);
|
|
|
</span><span class="boring">}</span></code></pre>
|
|
|
<p><span class="caption">示例 15-10:<code>MyBox<T></code> 上的 <code>Deref</code> 实现</span></p>
|
|
|
<p><code>type Target = T;</code> 语法定义了用于此 trait 的关联类型。关联类型是一个稍有不同的定义泛型参数的方式,现在还无需过多地担心它;第二十章会详细介绍。</p>
|
|
|
<p><code>deref</code> 方法体中写入了 <code>&self.0</code>,这样 <code>deref</code> 返回了我希望通过 <code>*</code> 运算符访问的值的引用。回忆一下第五章 <a href="ch05-01-defining-structs.html#使用没有命名字段的元组结构体来创建不同的类型">“使用没有命名字段的元组结构体来创建不同的类型”</a> 部分 <code>.0</code> 用来访问元组结构体的第一个元素。示例 15-9 中的 <code>main</code> 函数中对 <code>MyBox<T></code> 值的 <code>*</code> 调用现在可以编译并能通过断言了!</p>
|
|
|
<p>没有 <code>Deref</code> trait 的话,编译器只会解引用 <code>&</code> 引用类型。<code>deref</code> 方法向编译器提供了获取任何实现了 <code>Deref</code> trait 的类型的值,并且调用这个类型的 <code>deref</code> 方法来获取一个它知道如何解引用的 <code>&</code> 引用的能力。</p>
|
|
|
<p>当我们在示例 15-9 中输入 <code>*y</code> 时,Rust 事实上在底层运行了如下代码:</p>
|
|
|
<pre><code class="language-rust ignore">*(y.deref())</code></pre>
|
|
|
<p>Rust 将 <code>*</code> 运算符替换为先调用 <code>deref</code> 方法再进行普通解引用的操作,如此我们便不用担心是否还需手动调用 <code>deref</code> 方法了。Rust 的这个特性可以让我们写出行为一致的代码,无论面对的是常规引用还是实现了 <code>Deref</code> 的类型。</p>
|
|
|
<p><code>deref</code> 方法返回值的引用,以及 <code>*(y.deref())</code> 括号外边的普通解引用仍为必须的原因在于所有权。如果 <code>deref</code> 方法直接返回值而不是值的引用,其值将被移出 <code>self</code>。在这里以及大部分使用解引用运算符的情况下我们并不希望获取 <code>MyBox<T></code> 内部值的所有权。</p>
|
|
|
<p>注意,每次当我们在代码中使用 <code>*</code> 时, <code>*</code> 运算符都被替换成了先调用 <code>deref</code> 方法再接着使用 <code>*</code> 解引用的操作,且只会发生一次,不会对 <code>*</code> 操作符无限递归替换,解引用出上面 <code>i32</code> 类型的值就停止了,这个值与示例 15-9 中 <code>assert_eq!</code> 的 <code>5</code> 相匹配。</p>
|
|
|
<h3 id="函数和方法的隐式-deref-强制转换"><a class="header" href="#函数和方法的隐式-deref-强制转换">函数和方法的隐式 Deref 强制转换</a></h3>
|
|
|
<p><strong>Deref 强制转换</strong>(<em>deref coercions</em>)将实现了 <code>Deref</code> trait 的类型的引用转换为另一种类型的引用。例如,Deref 强制转换可以将 <code>&String</code> 转换为 <code>&str</code>,因为 <code>String</code> 实现了 <code>Deref</code> trait 因此可以返回 <code>&str</code>。Deref 强制转换是 Rust 在函数或方法传参上的一种便利操作,并且只能作用于实现了 <code>Deref</code> trait 的类型。当这种特定类型的引用作为实参传递给和形参类型不同的函数或方法时将自动进行。这时会有一系列的 <code>deref</code> 方法被调用,把我们提供的类型转换成了参数所需的类型。</p>
|
|
|
<p>Deref 强制转换的加入使得 Rust 程序员编写函数和方法调用时无需增加过多显式使用 <code>&</code> 和 <code>*</code> 的引用和解引用。这个功能也使得我们可以编写更多同时作用于引用或智能指针的代码。</p>
|
|
|
<p>作为展示 Deref 强制转换的实例,让我们使用示例 15-8 中定义的 <code>MyBox<T></code>,以及示例 15-10 中增加的 <code>Deref</code> 实现。示例 15-11 展示了一个有着字符串 slice 参数的函数定义:</p>
|
|
|
<p><span class="filename">文件名:src/main.rs</span></p>
|
|
|
<pre class="playground"><code class="language-rust edition2024">fn hello(name: &str) {
|
|
|
println!("Hello, {name}!");
|
|
|
}
|
|
|
<span class="boring">
|
|
|
</span><span class="boring">fn main() {}</span></code></pre>
|
|
|
<p><span class="caption">示例 15-11:<code>hello</code> 函数有着 <code>&str</code> 类型的参数 <code>name</code></span></p>
|
|
|
<p>可以使用字符串 slice 作为参数调用 <code>hello</code> 函数,比如 <code>hello("Rust");</code>。Deref 强制转换使得用 <code>MyBox<String></code> 类型值的引用调用 <code>hello</code> 成为可能,如示例 15-12 所示:</p>
|
|
|
<p><span class="filename">文件名:src/main.rs</span></p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">use std::ops::Deref;
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring">impl<T> Deref for MyBox<T> {
|
|
|
</span><span class="boring"> type Target = T;
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring"> fn deref(&self) -> &T {
|
|
|
</span><span class="boring"> &self.0
|
|
|
</span><span class="boring"> }
|
|
|
</span><span class="boring">}
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring">struct MyBox<T>(T);
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring">impl<T> MyBox<T> {
|
|
|
</span><span class="boring"> fn new(x: T) -> MyBox<T> {
|
|
|
</span><span class="boring"> MyBox(x)
|
|
|
</span><span class="boring"> }
|
|
|
</span><span class="boring">}
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring">fn hello(name: &str) {
|
|
|
</span><span class="boring"> println!("Hello, {name}!");
|
|
|
</span><span class="boring">}
|
|
|
</span><span class="boring">
|
|
|
</span>fn main() {
|
|
|
let m = MyBox::new(String::from("Rust"));
|
|
|
hello(&m);
|
|
|
}</code></pre>
|
|
|
<p><span class="caption">示例 15-12:因为 Deref 强制转换,使用 <code>MyBox<String></code> 的引用调用 <code>hello</code> 是可行的</span></p>
|
|
|
<p>这里使用 <code>&m</code> 调用 <code>hello</code> 函数,其为 <code>MyBox<String></code> 值的引用。因为示例 15-10 中在 <code>MyBox<T></code> 上实现了 <code>Deref</code> trait,Rust 可以通过 <code>deref</code> 调用将 <code>&MyBox<String></code> 变为 <code>&String</code>。标准库中提供了 <code>String</code> 上的 <code>Deref</code> 实现,其会返回字符串 slice,这可以在 <code>Deref</code> 的 API 文档中看到。Rust 再次调用 <code>deref</code> 将 <code>&String</code> 变为 <code>&str</code>,这就符合 <code>hello</code> 函数的定义了。</p>
|
|
|
<p>如果 Rust 没有实现 Deref 强制转换,为了使用 <code>&MyBox<String></code> 类型的值调用 <code>hello</code>,则不得不编写示例 15-13 中的代码来代替示例 15-12:</p>
|
|
|
<p><span class="filename">文件名:src/main.rs</span></p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">use std::ops::Deref;
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring">impl<T> Deref for MyBox<T> {
|
|
|
</span><span class="boring"> type Target = T;
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring"> fn deref(&self) -> &T {
|
|
|
</span><span class="boring"> &self.0
|
|
|
</span><span class="boring"> }
|
|
|
</span><span class="boring">}
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring">struct MyBox<T>(T);
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring">impl<T> MyBox<T> {
|
|
|
</span><span class="boring"> fn new(x: T) -> MyBox<T> {
|
|
|
</span><span class="boring"> MyBox(x)
|
|
|
</span><span class="boring"> }
|
|
|
</span><span class="boring">}
|
|
|
</span><span class="boring">
|
|
|
</span><span class="boring">fn hello(name: &str) {
|
|
|
</span><span class="boring"> println!("Hello, {name}!");
|
|
|
</span><span class="boring">}
|
|
|
</span><span class="boring">
|
|
|
</span>fn main() {
|
|
|
let m = MyBox::new(String::from("Rust"));
|
|
|
hello(&(*m)[..]);
|
|
|
}</code></pre>
|
|
|
<p><span class="caption">示例 15-13:如果 Rust 没有 Deref 强制转换则必须编写的代码</span></p>
|
|
|
<p><code>(*m)</code> 将 <code>MyBox<String></code> 解引用为 <code>String</code>。接着 <code>&</code> 和 <code>[..]</code> 获取了整个 <code>String</code> 的字符串 slice 来匹配 <code>hello</code> 的签名。没有 Deref 强制转换所有这些符号混在一起将更难以读写和理解。Deref 强制转换使得 Rust 自动的帮我们处理这些转换。</p>
|
|
|
<p>当所涉及到的类型定义了 <code>Deref</code> trait,Rust 会分析这些类型并使用任意多次 <code>Deref::deref</code> 调用以获得匹配参数的类型。这些解析都发生在编译时,所以利用 Deref 强制转换并没有运行时开销!</p>
|
|
|
<h3 id="deref-强制转换如何与可变性交互"><a class="header" href="#deref-强制转换如何与可变性交互">Deref 强制转换如何与可变性交互</a></h3>
|
|
|
<p>类似于如何使用 <code>Deref</code> trait 重载不可变引用的 <code>*</code> 运算符,Rust 提供了 <code>DerefMut</code> trait 用于重载可变引用的 <code>*</code> 运算符。</p>
|
|
|
<p>Rust 在发现类型和 trait 实现满足三种情况时会进行 Deref 强制转换:</p>
|
|
|
<ol>
|
|
|
<li>当 <code>T: Deref<Target=U></code> 时从 <code>&T</code> 到 <code>&U</code>。</li>
|
|
|
<li>当 <code>T: DerefMut<Target=U></code> 时从 <code>&mut T</code> 到 <code>&mut U</code>。</li>
|
|
|
<li>当 <code>T: Deref<Target=U></code> 时从 <code>&mut T</code> 到 <code>&U</code>。</li>
|
|
|
</ol>
|
|
|
<p>头两个情况除了第二种实现了可变性之外是相同的:第一种情况表明如果有一个 <code>&T</code>,而 <code>T</code> 实现了返回 <code>U</code> 类型的 <code>Deref</code>,则可以透明地得到 <code>&U</code>。第二种情况表明对于可变引用也有着相同的行为。</p>
|
|
|
<p>第三个情况有些微妙:Rust 也会将可变引用强转为不可变引用。但反之是<strong>不可能</strong> 的:不可变引用永远也不能强转为可变引用。因为根据借用规则,如果有一个可变引用,其必须是这些数据的唯一引用(否则程序将无法编译)。将一个可变引用转换为不可变引用永远也不会打破借用规则。将不可变引用转换为可变引用则需要初始的不可变引用是数据唯一的不可变引用,而借用规则无法保证这一点。因此,Rust 无法假设将不可变引用转换为可变引用是可能的。</p>
|
|
|
|
|
|
</main>
|
|
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
|
<!-- Mobile navigation buttons -->
|
|
|
<a rel="prev" href="ch15-01-box.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-03-drop.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-01-box.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-03-drop.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>
|