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.

305 lines
18 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>包 Crate - 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/basic/crate-module/crate.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="包和-package"><a class="header" href="#包和-package">包和 Package</a></h1>
<p>当读者按照章节顺序读到本章时,意味着你已经几乎具备了参与真实项目开发的能力。但是真实项目远比我们之前的 <code>cargo new</code> 的默认目录结构要复杂好在Rust 为我们提供了强大的包管理工具:</p>
<ul>
<li><strong>项目(Package)</strong>:可以用来构建、测试和分享包</li>
<li><strong>工作空间(WorkSpace)</strong>:对于大型项目,可以进一步将多个包联合在一起,组织成工作空间</li>
<li><strong>包(Crate)</strong>:一个由多个模块组成的树形结构,可以作为三方库进行分发,也可以生成可执行文件进行运行</li>
<li><strong>模块(Module)</strong>:可以一个文件多个模块,也可以一个文件一个模块,模块可以被认为是真实项目中的代码组织单元</li>
</ul>
<h2 id="定义"><a class="header" href="#定义">定义</a></h2>
<p>其实项目 <code>Package</code> 和包 <code>Crate</code> 很容易被搞混,甚至在很多书中,这两者都是不分的,但是由于官方对此做了明确的区分,因此我们会在本章节中试图(挣扎着)理清这个概念。</p>
<h4 id="包-crate"><a class="header" href="#包-crate">包 Crate</a></h4>
<p>对于 Rust 而言,包是一个独立的可编译单元,它编译后会生成一个可执行文件或者一个库。</p>
<p>一个包会将相关联的功能打包在一起,使得该功能可以很方便的在多个项目中分享。例如标准库中没有提供但是在三方库中提供的 <code>rand</code> 包,它提供了随机数生成的功能,我们只需要将该包通过 <code>use rand;</code> 引入到当前项目的作用域中,就可以在项目中使用 <code>rand</code> 的功能:<code>rand::XXX</code></p>
<p>同一个包中不能有同名的类型,但是在不同包中就可以。例如,虽然 <code>rand</code> 包中,有一个 <code>Rng</code> 特征,可是我们依然可以在自己的项目中定义一个 <code>Rng</code>,前者通过 <code>rand::Rng</code> 访问,后者通过 <code>Rng</code> 访问,对于编译器而言,这两者的边界非常清晰,不会存在引用歧义。</p>
<h2 id="项目-package"><a class="header" href="#项目-package">项目 Package</a></h2>
<p>鉴于 Rust 团队标新立异的起名传统,以及包的名称被 <code>crate</code> 占用,库的名称被 <code>library</code> 占用,经过斟酌, 我们决定将 <code>Package</code> 翻译成项目,你也可以理解为工程、软件包。</p>
<p>由于 <code>Package</code> 就是一个项目,因此它包含有独立的 <code>Cargo.toml</code> 文件,以及因为功能性被组织在一起的一个或多个包。一个 <code>Package</code> 只能包含<strong>一个</strong>库(library)类型的包,但是可以包含<strong>多个</strong>二进制可执行类型的包。</p>
<h4 id="二进制-package"><a class="header" href="#二进制-package">二进制 Package</a></h4>
<p>让我们来创建一个二进制 <code>Package</code></p>
<pre><code class="language-console">$ cargo new my-project
Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs
</code></pre>
<p>这里Cargo 为我们创建了一个名称是 <code>my-project</code><code>Package</code>,同时在其中创建了 <code>Cargo.toml</code> 文件,可以看一下该文件,里面并没有提到 <code>src/main.rs</code> 作为程序的入口,原因是 Cargo 有一个惯例:<strong><code>src/main.rs</code> 是二进制包的根文件,该二进制包的包名跟所属 <code>Package</code> 相同,在这里都是 <code>my-project</code></strong>,所有的代码执行都从该文件中的 <code>fn main()</code> 函数开始。</p>
<p>使用 <code>cargo run</code> 可以运行该项目,输出:<code>Hello, world!</code></p>
<h4 id="库-package"><a class="header" href="#库-package">库 Package</a></h4>
<p>再来创建一个库类型的 <code>Package</code></p>
<pre><code class="language-console">$ cargo new my-lib --lib
Created library `my-lib` package
$ ls my-lib
Cargo.toml
src
$ ls my-lib/src
lib.rs
</code></pre>
<p>首先,如果你试图运行 <code>my-lib</code>,会报错:</p>
<pre><code class="language-console">$ cargo run
error: a bin target must be available for `cargo run`
</code></pre>
<p>原因是库类型的 <code>Package</code> 只能作为三方库被其它项目引用,而不能独立运行,只有之前的二进制 <code>Package</code> 才可以运行。</p>
<p><code>src/main.rs</code> 一样Cargo 知道,如果一个 <code>Package</code> 包含有 <code>src/lib.rs</code>,意味它包含有一个库类型的同名包 <code>my-lib</code>,该包的根文件是 <code>src/lib.rs</code></p>
<h4 id="易混淆的-package-和包"><a class="header" href="#易混淆的-package-和包">易混淆的 Package 和包</a></h4>
<p>看完上面,相信大家看出来为何 <code>Package</code> 和包容易被混淆了吧?因为你用 <code>cargo new</code> 创建的 <code>Package</code> 和它其中包含的包是同名的!</p>
<p>不过,只要你牢记 <code>Package</code> 是一个项目工程,而包只是一个编译单元,也就不会再混淆这两个概念:<code>src/main.rs</code><code>src/lib.rs</code> 都是编译单元,因此它们都是包。</p>
<h4 id="典型的-package-结构"><a class="header" href="#典型的-package-结构">典型的 <code>Package</code> 结构</a></h4>
<p>上面创建的 <code>Package</code> 中仅包含 <code>src/main.rs</code> 文件,意味着它仅包含一个二进制同名包 <code>my-project</code>。如果一个 <code>Package</code> 同时拥有 <code>src/main.rs</code><code>src/lib.rs</code>,那就意味着它包含两个包:库包和二进制包,这两个包名也都是 <code>my-project</code> —— 都与 <code>Package</code> 同名。</p>
<p>一个真实项目中典型的 <code>Package</code>,会包含多个二进制包,这些包文件被放在 <code>src/bin</code> 目录下,每一个文件都是独立的二进制包,同时也会包含一个库包,该包只能存在一个 <code>src/lib.rs</code></p>
<pre><code class="language-css">.
├── Cargo.toml
├── Cargo.lock
├── src
│ ├── main.rs
│ ├── lib.rs
│ └── bin
│ └── main1.rs
│ └── main2.rs
├── tests
│ └── some_integration_tests.rs
├── benches
│ └── simple_bench.rs
└── examples
└── simple_example.rs
</code></pre>
<ul>
<li>唯一库包:<code>src/lib.rs</code></li>
<li>默认二进制包:<code>src/main.rs</code>,编译后生成的可执行文件与 <code>Package</code> 同名</li>
<li>其余二进制包:<code>src/bin/main1.rs</code><code>src/bin/main2.rs</code>,它们会分别生成一个文件同名的二进制可执行文件</li>
<li>集成测试文件:<code>tests</code> 目录下</li>
<li>基准性能测试 <code>benchmark</code> 文件:<code>benches</code> 目录下</li>
<li>项目示例:<code>examples</code> 目录下</li>
</ul>
<p>这种目录结构基本上是 Rust 的标准目录结构,在 <code>GitHub</code> 的大多数项目上,你都将看到它的身影。</p>
<p>理解了包的概念,我们再来看看构成包的基本单元:模块。</p>
<h2 id="课后练习"><a class="header" href="#课后练习">课后练习</a></h2>
<blockquote>
<p><a href="https://practice-zh.course.rs/crate-module/crate.html">Rust By Practice</a>,支持代码在线编辑和运行,并提供详细的<a href="https://github.com/sunface/rust-by-practice/blob/master/solutions/crate-module/crate.md">习题解答</a></p>
</blockquote>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../../basic/crate-module/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="../../basic/crate-module/module.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="../../basic/crate-module/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="../../basic/crate-module/module.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>