trpl-zh-cn/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html
2024-09-16 16:35:14 +00:00

497 lines
48 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE HTML>
<html lang="zh-CN" class="light" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>使用 use 关键字将路径引入作用域 - Rust 程序设计语言 简体中文版</title>
<!-- Custom HTML head -->
<meta name="description" content="Rust 程序设计语言 简体中文版">
<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" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="ferris.css">
<link rel="stylesheet" href="theme/2018-edition.css">
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var 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>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('light')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var 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';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="title-page.html">Rust 程序设计语言</a></li><li class="chapter-item expanded affix "><a href="foreword.html">前言</a></li><li class="chapter-item expanded affix "><a href="ch00-00-introduction.html">简介</a></li><li class="chapter-item expanded "><a href="ch01-00-getting-started.html"><strong aria-hidden="true">1.</strong> 入门指南</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch01-01-installation.html"><strong aria-hidden="true">1.1.</strong> 安装</a></li><li class="chapter-item expanded "><a href="ch01-02-hello-world.html"><strong aria-hidden="true">1.2.</strong> Hello, World!</a></li><li class="chapter-item expanded "><a href="ch01-03-hello-cargo.html"><strong aria-hidden="true">1.3.</strong> Hello, Cargo!</a></li></ol></li><li class="chapter-item expanded "><a href="ch02-00-guessing-game-tutorial.html"><strong aria-hidden="true">2.</strong> 写个猜数字游戏</a></li><li class="chapter-item expanded "><a href="ch03-00-common-programming-concepts.html"><strong aria-hidden="true">3.</strong> 常见编程概念</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch03-01-variables-and-mutability.html"><strong aria-hidden="true">3.1.</strong> 变量与可变性</a></li><li class="chapter-item expanded "><a href="ch03-02-data-types.html"><strong aria-hidden="true">3.2.</strong> 数据类型</a></li><li class="chapter-item expanded "><a href="ch03-03-how-functions-work.html"><strong aria-hidden="true">3.3.</strong> 函数</a></li><li class="chapter-item expanded "><a href="ch03-04-comments.html"><strong aria-hidden="true">3.4.</strong> 注释</a></li><li class="chapter-item expanded "><a href="ch03-05-control-flow.html"><strong aria-hidden="true">3.5.</strong> 控制流</a></li></ol></li><li class="chapter-item expanded "><a href="ch04-00-understanding-ownership.html"><strong aria-hidden="true">4.</strong> 认识所有权</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch04-01-what-is-ownership.html"><strong aria-hidden="true">4.1.</strong> 什么是所有权?</a></li><li class="chapter-item expanded "><a href="ch04-02-references-and-borrowing.html"><strong aria-hidden="true">4.2.</strong> 引用与借用</a></li><li class="chapter-item expanded "><a href="ch04-03-slices.html"><strong aria-hidden="true">4.3.</strong> Slice 类型</a></li></ol></li><li class="chapter-item expanded "><a href="ch05-00-structs.html"><strong aria-hidden="true">5.</strong> 使用结构体组织相关联的数据</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch05-01-defining-structs.html"><strong aria-hidden="true">5.1.</strong> 结构体的定义和实例化</a></li><li class="chapter-item expanded "><a href="ch05-02-example-structs.html"><strong aria-hidden="true">5.2.</strong> 结构体示例程序</a></li><li class="chapter-item expanded "><a href="ch05-03-method-syntax.html"><strong aria-hidden="true">5.3.</strong> 方法语法</a></li></ol></li><li class="chapter-item expanded "><a href="ch06-00-enums.html"><strong aria-hidden="true">6.</strong> 枚举和模式匹配</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch06-01-defining-an-enum.html"><strong aria-hidden="true">6.1.</strong> 枚举的定义</a></li><li class="chapter-item expanded "><a href="ch06-02-match.html"><strong aria-hidden="true">6.2.</strong> match 控制流结构</a></li><li class="chapter-item expanded "><a href="ch06-03-if-let.html"><strong aria-hidden="true">6.3.</strong> if let 简洁控制流</a></li></ol></li><li class="chapter-item expanded "><a href="ch07-00-managing-growing-projects-with-packages-crates-and-modules.html"><strong aria-hidden="true">7.</strong> 使用包、Crate 和模块管理不断增长的项目</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch07-01-packages-and-crates.html"><strong aria-hidden="true">7.1.</strong> 包和 Crate</a></li><li class="chapter-item expanded "><a href="ch07-02-defining-modules-to-control-scope-and-privacy.html"><strong aria-hidden="true">7.2.</strong> 定义模块来控制作用域与私有性</a></li><li class="chapter-item expanded "><a href="ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html"><strong aria-hidden="true">7.3.</strong> 引用模块项目的路径</a></li><li class="chapter-item expanded "><a href="ch07-04-bringing-paths-into-scope-with-the-use-keyword.html" class="active"><strong aria-hidden="true">7.4.</strong> 使用 use 关键字将路径引入作用域</a></li><li class="chapter-item expanded "><a href="ch07-05-separating-modules-into-different-files.html"><strong aria-hidden="true">7.5.</strong> 将模块拆分成多个文件</a></li></ol></li><li class="chapter-item expanded "><a href="ch08-00-common-collections.html"><strong aria-hidden="true">8.</strong> 常见集合</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch08-01-vectors.html"><strong aria-hidden="true">8.1.</strong> 使用 Vector 储存列表</a></li><li class="chapter-item expanded "><a href="ch08-02-strings.html"><strong aria-hidden="true">8.2.</strong> 使用字符串储存 UTF-8 编码的文本</a></li><li class="chapter-item expanded "><a href="ch08-03-hash-maps.html"><strong aria-hidden="true">8.3.</strong> 使用 Hash Map 储存键值对</a></li></ol></li><li class="chapter-item expanded "><a href="ch09-00-error-handling.html"><strong aria-hidden="true">9.</strong> 错误处理</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch09-01-unrecoverable-errors-with-panic.html"><strong aria-hidden="true">9.1.</strong> 用 panic! 处理不可恢复的错误</a></li><li class="chapter-item expanded "><a href="ch09-02-recoverable-errors-with-result.html"><strong aria-hidden="true">9.2.</strong> 用 Result 处理可恢复的错误</a></li><li class="chapter-item expanded "><a href="ch09-03-to-panic-or-not-to-panic.html"><strong aria-hidden="true">9.3.</strong> 要不要 panic!</a></li></ol></li><li class="chapter-item expanded "><a href="ch10-00-generics.html"><strong aria-hidden="true">10.</strong> 泛型、Trait 和生命周期</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch10-01-syntax.html"><strong aria-hidden="true">10.1.</strong> 泛型数据类型</a></li><li class="chapter-item expanded "><a href="ch10-02-traits.html"><strong aria-hidden="true">10.2.</strong> Trait定义共同行为</a></li><li class="chapter-item expanded "><a href="ch10-03-lifetime-syntax.html"><strong aria-hidden="true">10.3.</strong> 生命周期确保引用有效</a></li></ol></li><li class="chapter-item expanded "><a href="ch11-00-testing.html"><strong aria-hidden="true">11.</strong> 编写自动化测试</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch11-01-writing-tests.html"><strong aria-hidden="true">11.1.</strong> 如何编写测试</a></li><li class="chapter-item expanded "><a href="ch11-02-running-tests.html"><strong aria-hidden="true">11.2.</strong> 控制测试如何运行</a></li><li class="chapter-item expanded "><a href="ch11-03-test-organization.html"><strong aria-hidden="true">11.3.</strong> 测试的组织结构</a></li></ol></li><li class="chapter-item expanded "><a href="ch12-00-an-io-project.html"><strong aria-hidden="true">12.</strong> 一个 I/O 项目:构建命令行程序</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch12-01-accepting-command-line-arguments.html"><strong aria-hidden="true">12.1.</strong> 接受命令行参数</a></li><li class="chapter-item expanded "><a href="ch12-02-reading-a-file.html"><strong aria-hidden="true">12.2.</strong> 读取文件</a></li><li class="chapter-item expanded "><a href="ch12-03-improving-error-handling-and-modularity.html"><strong aria-hidden="true">12.3.</strong> 重构以改进模块化与错误处理</a></li><li class="chapter-item expanded "><a href="ch12-04-testing-the-librarys-functionality.html"><strong aria-hidden="true">12.4.</strong> 采用测试驱动开发完善库的功能</a></li><li class="chapter-item expanded "><a href="ch12-05-working-with-environment-variables.html"><strong aria-hidden="true">12.5.</strong> 处理环境变量</a></li><li class="chapter-item expanded "><a href="ch12-06-writing-to-stderr-instead-of-stdout.html"><strong aria-hidden="true">12.6.</strong> 将错误信息输出到标准错误而不是标准输出</a></li></ol></li><li class="chapter-item expanded "><a href="ch13-00-functional-features.html"><strong aria-hidden="true">13.</strong> Rust 中的函数式语言功能:迭代器与闭包</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch13-01-closures.html"><strong aria-hidden="true">13.1.</strong> 闭包:可以捕获其环境的匿名函数</a></li><li class="chapter-item expanded "><a href="ch13-02-iterators.html"><strong aria-hidden="true">13.2.</strong> 使用迭代器处理元素序列</a></li><li class="chapter-item expanded "><a href="ch13-03-improving-our-io-project.html"><strong aria-hidden="true">13.3.</strong> 改进之前的 I/O 项目</a></li><li class="chapter-item expanded "><a href="ch13-04-performance.html"><strong aria-hidden="true">13.4.</strong> 性能比较:循环对迭代器</a></li></ol></li><li class="chapter-item expanded "><a href="ch14-00-more-about-cargo.html"><strong aria-hidden="true">14.</strong> 更多关于 Cargo 和 Crates.io 的内容</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch14-01-release-profiles.html"><strong aria-hidden="true">14.1.</strong> 采用发布配置自定义构建</a></li><li class="chapter-item expanded "><a href="ch14-02-publishing-to-crates-io.html"><strong aria-hidden="true">14.2.</strong> 将 crate 发布到 Crates.io</a></li><li class="chapter-item expanded "><a href="ch14-03-cargo-workspaces.html"><strong aria-hidden="true">14.3.</strong> Cargo 工作空间</a></li><li class="chapter-item expanded "><a href="ch14-04-installing-binaries.html"><strong aria-hidden="true">14.4.</strong> 使用 cargo install 安装二进制文件</a></li><li class="chapter-item expanded "><a href="ch14-05-extending-cargo.html"><strong aria-hidden="true">14.5.</strong> Cargo 自定义扩展命令</a></li></ol></li><li class="chapter-item expanded "><a href="ch15-00-smart-pointers.html"><strong aria-hidden="true">15.</strong> 智能指针</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch15-01-box.html"><strong aria-hidden="true">15.1.</strong> 使用 Box&lt;T&gt; 指向堆上数据</a></li><li class="chapter-item expanded "><a href="ch15-02-deref.html"><strong aria-hidden="true">15.2.</strong> 使用 Deref Trait 将智能指针当作常规引用处理</a></li><li class="chapter-item expanded "><a href="ch15-03-drop.html"><strong aria-hidden="true">15.3.</strong> 使用 Drop Trait 运行清理代码</a></li><li class="chapter-item expanded "><a href="ch15-04-rc.html"><strong aria-hidden="true">15.4.</strong> Rc&lt;T&gt; 引用计数智能指针</a></li><li class="chapter-item expanded "><a href="ch15-05-interior-mutability.html"><strong aria-hidden="true">15.5.</strong> RefCell&lt;T&gt; 与内部可变性模式</a></li><li class="chapter-item expanded "><a href="ch15-06-reference-cycles.html"><strong aria-hidden="true">15.6.</strong> 引用循环会导致内存泄漏</a></li></ol></li><li class="chapter-item expanded "><a href="ch16-00-concurrency.html"><strong aria-hidden="true">16.</strong> 无畏并发</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch16-01-threads.html"><strong aria-hidden="true">16.1.</strong> 使用线程同时地运行代码</a></li><li class="chapter-item expanded "><a href="ch16-02-message-passing.html"><strong aria-hidden="true">16.2.</strong> 使用消息传递在线程间通信</a></li><li class="chapter-item expanded "><a href="ch16-03-shared-state.html"><strong aria-hidden="true">16.3.</strong> 共享状态并发</a></li><li class="chapter-item expanded "><a href="ch16-04-extensible-concurrency-sync-and-send.html"><strong aria-hidden="true">16.4.</strong> 使用 Sync 与 Send Traits 的可扩展并发</a></li></ol></li><li class="chapter-item expanded "><a href="ch17-00-oop.html"><strong aria-hidden="true">17.</strong> Rust 的面向对象编程特性</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch17-01-what-is-oo.html"><strong aria-hidden="true">17.1.</strong> 面向对象语言的特点</a></li><li class="chapter-item expanded "><a href="ch17-02-trait-objects.html"><strong aria-hidden="true">17.2.</strong> 顾及不同类型值的 trait 对象</a></li><li class="chapter-item expanded "><a href="ch17-03-oo-design-patterns.html"><strong aria-hidden="true">17.3.</strong> 面向对象设计模式的实现</a></li></ol></li><li class="chapter-item expanded "><a href="ch18-00-patterns.html"><strong aria-hidden="true">18.</strong> 模式与模式匹配</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch18-01-all-the-places-for-patterns.html"><strong aria-hidden="true">18.1.</strong> 所有可能会用到模式的位置</a></li><li class="chapter-item expanded "><a href="ch18-02-refutability.html"><strong aria-hidden="true">18.2.</strong> Refutability可反驳性: 模式是否会匹配失效</a></li><li class="chapter-item expanded "><a href="ch18-03-pattern-syntax.html"><strong aria-hidden="true">18.3.</strong> 模式语法</a></li></ol></li><li class="chapter-item expanded "><a href="ch19-00-advanced-features.html"><strong aria-hidden="true">19.</strong> 高级特征</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch19-01-unsafe-rust.html"><strong aria-hidden="true">19.1.</strong> 不安全的 Rust</a></li><li class="chapter-item expanded "><a href="ch19-03-advanced-traits.html"><strong aria-hidden="true">19.2.</strong> 高级 trait</a></li><li class="chapter-item expanded "><a href="ch19-04-advanced-types.html"><strong aria-hidden="true">19.3.</strong> 高级类型</a></li><li class="chapter-item expanded "><a href="ch19-05-advanced-functions-and-closures.html"><strong aria-hidden="true">19.4.</strong> 高级函数与闭包</a></li><li class="chapter-item expanded "><a href="ch19-06-macros.html"><strong aria-hidden="true">19.5.</strong></a></li></ol></li><li class="chapter-item expanded "><a href="ch20-00-final-project-a-web-server.html"><strong aria-hidden="true">20.</strong> 最后的项目:构建多线程 web server</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch20-01-single-threaded.html"><strong aria-hidden="true">20.1.</strong> 建立单线程 web server</a></li><li class="chapter-item expanded "><a href="ch20-02-multithreaded.html"><strong aria-hidden="true">20.2.</strong> 将单线程 server 变为多线程 server</a></li><li class="chapter-item expanded "><a href="ch20-03-graceful-shutdown-and-cleanup.html"><strong aria-hidden="true">20.3.</strong> 优雅停机与清理</a></li></ol></li><li class="chapter-item expanded "><a href="appendix-00.html"><strong aria-hidden="true">21.</strong> 附录</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="appendix-01-keywords.html"><strong aria-hidden="true">21.1.</strong> A - 关键字</a></li><li class="chapter-item expanded "><a href="appendix-02-operators.html"><strong aria-hidden="true">21.2.</strong> B - 运算符与符号</a></li><li class="chapter-item expanded "><a href="appendix-03-derivable-traits.html"><strong aria-hidden="true">21.3.</strong> C - 可派生的 trait</a></li><li class="chapter-item expanded "><a href="appendix-04-useful-development-tools.html"><strong aria-hidden="true">21.4.</strong> D - 实用开发工具</a></li><li class="chapter-item expanded "><a href="appendix-05-editions.html"><strong aria-hidden="true">21.5.</strong> E - 版本</a></li><li class="chapter-item expanded "><a href="appendix-06-translation.html"><strong aria-hidden="true">21.6.</strong> F - 本书译本</a></li><li class="chapter-item expanded "><a href="appendix-07-nightly-rust.html"><strong aria-hidden="true">21.7.</strong> G - Rust 是如何开发的与 “Nightly Rust”</a></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<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="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 程序设计语言 简体中文版</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/KaiserY/trpl-zh-cn/tree/main" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/KaiserY/trpl-zh-cn/edit/main/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.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>
<h2 id="使用-use-关键字将路径引入作用域"><a class="header" href="#使用-use-关键字将路径引入作用域">使用 <code>use</code> 关键字将路径引入作用域</a></h2>
<blockquote>
<p><a href="https://github.com/rust-lang/book/blob/main/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md">ch07-04-bringing-paths-into-scope-with-the-use-keyword.md</a>
<br>
commit c77d7a1279dbc7a9d76e80c5ac9d742dd529538c</p>
</blockquote>
<p>不得不编写路径来调用函数显得不便且重复。在示例 7-7 中,无论我们选择 <code>add_to_waitlist</code> 函数的绝对路径还是相对路径,每次我们想要调用 <code>add_to_waitlist</code> 时,都必须指定<code>front_of_house</code><code>hosting</code>。幸运的是,有一种方法可以简化这个过程。我们可以使用 <code>use</code> 关键字创建一个短路径,然后就可以在作用域中的任何地方使用这个更短的名字。</p>
<p>在示例 7-11 中,我们将 <code>crate::front_of_house::hosting</code> 模块引入了 <code>eat_at_restaurant</code> 函数的作用域,而我们只需要指定 <code>hosting::add_to_waitlist</code> 即可在 <code>eat_at_restaurant</code> 中调用 <code>add_to_waitlist</code> 函数。</p>
<p><span class="filename">文件名src/lib.rs</span></p>
<pre><code class="language-rust noplayground test_harness">mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}</code></pre>
<p><span class="caption">示例 7-11: 使用 <code>use</code> 将模块引入作用域</span></p>
<p>在作用域中增加 <code>use</code> 和路径类似于在文件系统中创建软连接符号连接symbolic link。通过在 crate 根增加 <code>use crate::front_of_house::hosting</code>,现在 <code>hosting</code> 在作用域中就是有效的名称了,如同 <code>hosting</code> 模块被定义于 crate 根一样。通过 <code>use</code> 引入作用域的路径也会检查私有性,同其它路径一样。</p>
<p>注意 <code>use</code> 只能创建 <code>use</code> 所在的特定作用域内的短路径。示例 7-12 将 <code>eat_at_restaurant</code> 函数移动到了一个叫 <code>customer</code> 的子模块,这又是一个不同于 <code>use</code> 语句的作用域,所以函数体不能编译。</p>
<p><span class="filename">文件名src/lib.rs</span></p>
<pre><code class="language-rust noplayground test_harness does_not_compile ignore">mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
mod customer {
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
}</code></pre>
<p><span class="caption">示例 7-12: <code>use</code> 语句只适用于其所在的作用域</span></p>
<p>编译器错误显示短路径不再适用于 <code>customer</code> 模块中:</p>
<pre><code class="language-console">$ cargo build
Compiling restaurant v0.1.0 (file:///projects/restaurant)
error[E0433]: failed to resolve: use of undeclared crate or module `hosting`
--&gt; src/lib.rs:11:9
|
11 | hosting::add_to_waitlist();
| ^^^^^^^ use of undeclared crate or module `hosting`
|
help: consider importing this module through its public re-export
|
10 + use crate::hosting;
|
warning: unused import: `crate::front_of_house::hosting`
--&gt; src/lib.rs:7:5
|
7 | use crate::front_of_house::hosting;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
For more information about this error, try `rustc --explain E0433`.
warning: `restaurant` (lib) generated 1 warning
error: could not compile `restaurant` (lib) due to 1 previous error; 1 warning emitted
</code></pre>
<p>注意这里还有一个警告说 <code>use</code> 在其作用域内不再被使用!为了修复这个问题,可以将 <code>use</code> 移动到 <code>customer</code> 模块内,或者在子模块 <code>customer</code> 内通过 <code>super::hosting</code> 引用父模块中的这个短路径。</p>
<h3 id="创建惯用的-use-路径"><a class="header" href="#创建惯用的-use-路径">创建惯用的 <code>use</code> 路径</a></h3>
<p>在示例 7-11 中,你可能会比较疑惑,为什么我们是指定 <code>use crate::front_of_house::hosting</code> ,然后在 <code>eat_at_restaurant</code> 中调用 <code>hosting::add_to_waitlist</code> ,而不是通过指定一直到 <code>add_to_waitlist</code> 函数的 <code>use</code> 路径来得到相同的结果,如示例 7-13 所示。</p>
<p><span class="filename">文件名src/lib.rs</span></p>
<pre><code class="language-rust noplayground test_harness">mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting::add_to_waitlist;
pub fn eat_at_restaurant() {
add_to_waitlist();
}</code></pre>
<p><span class="caption">示例 7-13: 使用 <code>use</code><code>add_to_waitlist</code> 函数引入作用域,这并不符合习惯</span></p>
<p>虽然示例 7-11 和 7-13 都完成了相同的任务,但示例 7-11 是使用 <code>use</code> 将函数引入作用域的习惯用法。要想使用 <code>use</code> 将函数的父模块引入作用域,我们必须在调用函数时指定父模块,这样可以清晰地表明函数不是在本地定义的,同时使完整路径的重复度最小化。示例 7-13 中的代码不清楚 <code>add_to_waitlist</code> 是在哪里被定义的。</p>
<p>另一方面,使用 <code>use</code> 引入结构体、枚举和其他项时,习惯是指定它们的完整路径。示例 7-14 展示了将 <code>HashMap</code> 结构体引入二进制 crate 作用域的习惯用法。</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust">use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(1, 2);
}</code></pre></pre>
<p><span class="caption">示例 7-14: 将 <code>HashMap</code> 引入作用域的习惯用法</span></p>
<p>这种习惯用法背后没有什么硬性要求:它只是一种惯例,人们已经习惯了以这种方式阅读和编写 Rust 代码。</p>
<p>这个习惯用法有一个例外,那就是我们想使用 <code>use</code> 语句将两个具有相同名称的项带入作用域,因为 Rust 不允许这样做。示例 7-15 展示了如何将两个具有相同名称但不同父模块的 <code>Result</code> 类型引入作用域,以及如何引用它们。</p>
<p><span class="filename">文件名src/lib.rs</span></p>
<pre><code class="language-rust noplayground">use std::fmt;
use std::io;
fn function1() -&gt; fmt::Result {
// --snip--
<span class="boring"> Ok(())
</span>}
fn function2() -&gt; io::Result&lt;()&gt; {
// --snip--
<span class="boring"> Ok(())
</span>}</code></pre>
<p><span class="caption">示例 7-15: 使用父模块将两个具有相同名称的类型引入同一作用域</span></p>
<p>如你所见,使用父模块可以区分这两个 <code>Result</code> 类型。如果我们是指定 <code>use std::fmt::Result</code><code>use std::io::Result</code>,我们将在同一作用域拥有了两个 <code>Result</code> 类型,当我们使用 <code>Result</code>Rust 则不知道我们要用的是哪个。</p>
<h3 id="使用-as-关键字提供新的名称"><a class="header" href="#使用-as-关键字提供新的名称">使用 <code>as</code> 关键字提供新的名称</a></h3>
<p>使用 <code>use</code> 将两个同名类型引入同一作用域这个问题还有另一个解决办法:在这个类型的路径后面,我们使用 <code>as</code> 指定一个新的本地名称或者别名。示例 7-16 展示了另一个编写示例 7-15 中代码的方法,通过 <code>as</code> 重命名其中一个 <code>Result</code> 类型。</p>
<p><span class="filename">文件名src/lib.rs</span></p>
<pre><code class="language-rust noplayground">use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -&gt; Result {
// --snip--
<span class="boring"> Ok(())
</span>}
fn function2() -&gt; IoResult&lt;()&gt; {
// --snip--
<span class="boring"> Ok(())
</span>}</code></pre>
<p><span class="caption">示例 7-16: 使用 <code>as</code> 关键字重命名引入作用域的类型</span></p>
<p>在第二个 <code>use</code> 语句中,我们选择 <code>IoResult</code> 作为 <code>std::io::Result</code> 的新名称,它与从 <code>std::fmt</code> 引入作用域的 <code>Result</code> 并不冲突。示例 7-15 和示例 7-16 都是惯用的,如何选择都取决于你!</p>
<h3 id="使用-pub-use-重导出名称"><a class="header" href="#使用-pub-use-重导出名称">使用 <code>pub use</code> 重导出名称</a></h3>
<p>使用 <code>use</code> 关键字,将某个名称导入当前作用域后,这个名称在此作用域中就可以使用了,但它对此作用域之外还是私有的。如果想让其他人调用我们的代码时,也能够正常使用这个名称,就好像它本来就在当前作用域一样,那我们可以将 <code>pub</code><code>use</code> 合起来使用。这种技术被称为 “<em>重导出</em><em>re-exporting</em>)”:我们不仅将一个名称导入了当前作用域,还允许别人把它导入他们自己的作用域。</p>
<p>示例 7-17 将示例 7-11 根模块中的 <code>use</code> 改为 <code>pub use</code></p>
<p><span class="filename">文件名src/lib.rs</span></p>
<pre><code class="language-rust noplayground test_harness">mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}</code></pre>
<p><span class="caption">示例 7-17: 通过 <code>pub use</code> 使名称可从新作用域中被导入至任何代码</span></p>
<p>在这个修改之前,外部代码需要使用路径 <code>restaurant::front_of_house::hosting::add_to_waitlist()</code> 来调用 <code>add_to_waitlist</code> 函数。现在这个 <code>pub use</code> 从根模块重导出了 <code>hosting</code> 模块,外部代码现在可以使用路径 <code>restaurant::hosting::add_to_waitlist</code></p>
<p>当你代码的内部结构与调用你代码的程序员所想象的结构不同时,重导出会很有用。例如,在这个餐馆的比喻中,经营餐馆的人会想到“前台”和“后台”。但顾客在光顾一家餐馆时,可能不会以这些术语来考虑餐馆的各个部分。使用 <code>pub use</code>,我们可以使用一种结构编写代码,却将不同的结构形式暴露出来。这样做使我们的库井井有条,也使开发这个库的程序员和调用这个库的程序员都更加方便。在<a href="ch14-02-publishing-to-crates-io.html#%E4%BD%BF%E7%94%A8-pub-use-%E5%AF%BC%E5%87%BA%E5%90%88%E9%80%82%E7%9A%84%E5%85%AC%E6%9C%89-api">“使用 <code>pub use</code> 导出合适的公有 API”</a>部分让我们再看另一个 <code>pub use</code> 的例子来了解这如何影响 crate 的文档。</p>
<h3 id="使用外部包"><a class="header" href="#使用外部包">使用外部包</a></h3>
<p>在第二章中我们编写了一个猜猜看游戏。那个项目使用了一个外部包,<code>rand</code>,来生成随机数。为了在项目中使用 <code>rand</code>,在 <em>Cargo.toml</em> 中加入了如下行:</p>
<p><span class="filename">文件名Cargo.toml</span></p>
<pre><code class="language-toml">rand = &quot;0.8.5&quot;
</code></pre>
<p><em>Cargo.toml</em> 中加入 <code>rand</code> 依赖告诉了 Cargo 要从 <a href="https://crates.io">crates.io</a> 下载 <code>rand</code> 和其依赖,并使其可在项目代码中使用。</p>
<p>接着,为了将 <code>rand</code> 定义引入项目包的作用域,我们加入一行 <code>use</code> 起始的包名,它以 <code>rand</code> 包名开头并列出了需要引入作用域的项。回忆一下第二章的 “生成一个随机数” 部分,我们曾将 <code>Rng</code> trait 引入作用域并调用了 <code>rand::thread_rng</code> 函数:</p>
<pre><code class="language-rust ignore"><span class="boring">use std::io;
</span>use rand::Rng;
fn main() {
<span class="boring"> println!(&quot;Guess the number!&quot;);
</span><span class="boring">
</span> let secret_number = rand::thread_rng().gen_range(1..=100);
<span class="boring">
</span><span class="boring"> println!(&quot;The secret number is: {secret_number}&quot;);
</span><span class="boring">
</span><span class="boring"> println!(&quot;Please input your guess.&quot;);
</span><span class="boring">
</span><span class="boring"> let mut guess = String::new();
</span><span class="boring">
</span><span class="boring"> io::stdin()
</span><span class="boring"> .read_line(&amp;mut guess)
</span><span class="boring"> .expect(&quot;Failed to read line&quot;);
</span><span class="boring">
</span><span class="boring"> println!(&quot;You guessed: {guess}&quot;);
</span>}</code></pre>
<p><a href="https://crates.io">crates.io</a> 上有很多 Rust 社区成员发布的包,将其引入你自己的项目都需要一道相同的步骤:在 <em>Cargo.toml</em> 列出它们并通过 <code>use</code> 将其中定义的项引入项目包的作用域中。</p>
<p>注意 <code>std</code> 标准库对于你的包来说也是外部 crate。因为标准库随 Rust 语言一同分发,无需修改 <em>Cargo.toml</em> 来引入 <code>std</code>,不过需要通过 <code>use</code> 将标准库中定义的项引入项目包的作用域中来引用它们,比如我们使用的 <code>HashMap</code></p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use std::collections::HashMap;
<span class="boring">}</span></code></pre></pre>
<p>这是一个以标准库 crate 名 <code>std</code> 开头的绝对路径。</p>
<h3 id="嵌套路径来消除大量的-use-行"><a class="header" href="#嵌套路径来消除大量的-use-行">嵌套路径来消除大量的 <code>use</code></a></h3>
<p>当需要引入很多定义于相同包或相同模块的项时,为每一项单独列出一行会占用源码很大的空间。例如猜猜看章节示例 2-4 中有两行 <code>use</code> 语句都从 <code>std</code> 引入项到作用域:</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre><code class="language-rust ignore"><span class="boring">use rand::Rng;
</span>// --snip--
use std::cmp::Ordering;
use std::io;
// --snip--
<span class="boring">
</span><span class="boring">fn main() {
</span><span class="boring"> println!(&quot;Guess the number!&quot;);
</span><span class="boring">
</span><span class="boring"> let secret_number = rand::thread_rng().gen_range(1..=100);
</span><span class="boring">
</span><span class="boring"> println!(&quot;The secret number is: {secret_number}&quot;);
</span><span class="boring">
</span><span class="boring"> println!(&quot;Please input your guess.&quot;);
</span><span class="boring">
</span><span class="boring"> let mut guess = String::new();
</span><span class="boring">
</span><span class="boring"> io::stdin()
</span><span class="boring"> .read_line(&amp;mut guess)
</span><span class="boring"> .expect(&quot;Failed to read line&quot;);
</span><span class="boring">
</span><span class="boring"> println!(&quot;You guessed: {guess}&quot;);
</span><span class="boring">
</span><span class="boring"> match guess.cmp(&amp;secret_number) {
</span><span class="boring"> Ordering::Less =&gt; println!(&quot;Too small!&quot;),
</span><span class="boring"> Ordering::Greater =&gt; println!(&quot;Too big!&quot;),
</span><span class="boring"> Ordering::Equal =&gt; println!(&quot;You win!&quot;),
</span><span class="boring"> }
</span><span class="boring">}</span></code></pre>
<p>相反,我们可以使用嵌套路径将相同的项在一行中引入作用域。这么做需要指定路径的相同部分,接着是两个冒号,接着是大括号中的各自不同的路径部分,如示例 7-18 所示。</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre><code class="language-rust ignore"><span class="boring">use rand::Rng;
</span>// --snip--
use std::{cmp::Ordering, io};
// --snip--
<span class="boring">
</span><span class="boring">fn main() {
</span><span class="boring"> println!(&quot;Guess the number!&quot;);
</span><span class="boring">
</span><span class="boring"> let secret_number = rand::thread_rng().gen_range(1..=100);
</span><span class="boring">
</span><span class="boring"> println!(&quot;The secret number is: {secret_number}&quot;);
</span><span class="boring">
</span><span class="boring"> println!(&quot;Please input your guess.&quot;);
</span><span class="boring">
</span><span class="boring"> let mut guess = String::new();
</span><span class="boring">
</span><span class="boring"> io::stdin()
</span><span class="boring"> .read_line(&amp;mut guess)
</span><span class="boring"> .expect(&quot;Failed to read line&quot;);
</span><span class="boring">
</span><span class="boring"> let guess: u32 = guess.trim().parse().expect(&quot;Please type a number!&quot;);
</span><span class="boring">
</span><span class="boring"> println!(&quot;You guessed: {guess}&quot;);
</span><span class="boring">
</span><span class="boring"> match guess.cmp(&amp;secret_number) {
</span><span class="boring"> Ordering::Less =&gt; println!(&quot;Too small!&quot;),
</span><span class="boring"> Ordering::Greater =&gt; println!(&quot;Too big!&quot;),
</span><span class="boring"> Ordering::Equal =&gt; println!(&quot;You win!&quot;),
</span><span class="boring"> }
</span><span class="boring">}</span></code></pre>
<p><span class="caption">示例 7-18: 指定嵌套的路径在一行中将多个带有相同前缀的项引入作用域</span></p>
<p>在较大的程序中,使用嵌套路径从相同包或模块中引入很多项,可以显著减少所需的独立 <code>use</code> 语句的数量!</p>
<p>我们可以在路径的任何层级使用嵌套路径,这在组合两个共享子路径的 <code>use</code> 语句时非常有用。例如,示例 7-19 中展示了两个 <code>use</code> 语句:一个将 <code>std::io</code> 引入作用域,另一个将 <code>std::io::Write</code> 引入作用域:</p>
<p><span class="filename">文件名src/lib.rs</span></p>
<pre><code class="language-rust noplayground">use std::io;
use std::io::Write;</code></pre>
<p><span class="caption">示例 7-19: 通过两行 <code>use</code> 语句引入两个路径,其中一个是另一个的子路径</span></p>
<p>两个路径的相同部分是 <code>std::io</code>,这正是第一个路径。为了在一行 <code>use</code> 语句中引入这两个路径,可以在嵌套路径中使用 <code>self</code>,如示例 7-20 所示。</p>
<p><span class="filename">文件名src/lib.rs</span></p>
<pre><code class="language-rust noplayground">use std::io::{self, Write};</code></pre>
<p><span class="caption">示例 7-20: 将示例 7-19 中部分重复的路径合并为一个 <code>use</code> 语句</span></p>
<p>这一行便将 <code>std::io</code><code>std::io::Write</code> 同时引入作用域。</p>
<h3 id="通过-glob-运算符将所有的公有定义引入作用域"><a class="header" href="#通过-glob-运算符将所有的公有定义引入作用域">通过 glob 运算符将所有的公有定义引入作用域</a></h3>
<p>如果希望将一个路径下 <strong>所有</strong> 公有项引入作用域,可以指定路径后跟 <code>*</code>glob 运算符:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use std::collections::*;
<span class="boring">}</span></code></pre></pre>
<p>这个 <code>use</code> 语句将 <code>std::collections</code> 中定义的所有公有项引入当前作用域。使用 glob 运算符时请多加小心Glob 会使得我们难以推导作用域中有什么名称和它们是在何处定义的。</p>
<p>glob 运算符经常用于测试模块 <code>tests</code> 中,这时会将所有内容引入作用域;我们将在第十一章 “如何编写测试” 部分讲解。glob 运算符有时也用于 prelude 模式;查看 <a href="https://doc.rust-lang.org/std/prelude/index.html#other-preludes">标准库中的文档</a> 了解这个模式的更多细节。</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="ch07-03-paths-for-referring-to-an-item-in-the-module-tree.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="ch07-05-separating-modules-into-different-files.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="ch07-03-paths-for-referring-to-an-item-in-the-module-tree.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="ch07-05-separating-modules-into-different-files.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="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="ferris.js"></script>
</div>
</body>
</html>