New upstream version 1.28.0~beta.14+dfsg1

This commit is contained in:
Ximin Luo 2018-07-25 02:49:57 -07:00
parent 5d61e2aca7
commit 94b46f3498
2658 changed files with 168551 additions and 67588 deletions

View File

@ -48,7 +48,7 @@ always work, and sometimes it's hard to know what to search for, so consider thi
extra credit. We won't mind if you accidentally file a duplicate report.
Similarly, to help others who encountered the bug find your issue,
consider filing an issue with with a descriptive title, which contains information that might be unique to it.
consider filing an issue with a descriptive title, which contains information that might be unique to it.
This can be the language or compiler feature used, the conditions that trigger the bug,
or part of the error message if there is any.
An example could be: **"impossible case reached" on lifetime inference for impl Trait in return position**.
@ -142,7 +142,7 @@ file. If you still have a `config.mk` file in your directory - from
### Building
[building]: #building
A default configuration shall use around 3.5 GB of disk space, whereas building a debug configuration may require more than 30 GB.
A default configuration requires around 3.5 GB of disk space, whereas building a debug configuration may require more than 30 GB.
Dependencies
- [build dependencies](README.md#building-from-source)

View File

@ -38,6 +38,7 @@ Read ["Installation"] from [The Book].
3. Build and install:
```sh
$ git submodule update --init --recursive --progress
$ ./x.py build && sudo ./x.py install
```
@ -119,7 +120,7 @@ shell with:
> python x.py build
```
Currently building Rust only works with some known versions of Visual Studio. If
Currently, building Rust only works with some known versions of Visual Studio. If
you have a more recent version installed the build system doesn't understand
then you may need to force rustbuild to use an older version. This can be done
by manually calling the appropriate vcvars file before running the bootstrap.
@ -133,7 +134,7 @@ python x.py build
[specifying-an-abi]: #specifying-an-abi
Each specific ABI can also be used from either environment (for example, using
the GNU ABI in powershell) by using an explicit build triple. The available
the GNU ABI in PowerShell) by using an explicit build triple. The available
Windows build triples are:
- GNU ABI (using GCC)
- `i686-pc-windows-gnu`
@ -179,7 +180,7 @@ the ABI used. I.e., if the ABI was `x86_64-pc-windows-msvc`, the directory will
[notes]: #notes
Since the Rust compiler is written in Rust, it must be built by a
precompiled "snapshot" version of itself (made in an earlier state of
precompiled "snapshot" version of itself (made in an earlier stage of
development). As such, source builds require a connection to the Internet, to
fetch snapshots, and an OS that can execute the available snapshot binaries.

View File

@ -1,13 +1,144 @@
Version 1.27.2 (2018-07-20)
Version 1.28.0 (2018-08-02)
===========================
Language
--------
- [The `#[repr(transparent)]` attribute is now stable.][51562] This attribute
allows a Rust newtype wrapper (`struct NewType<T>(T);`) to be represented as
the inner type across Foreign Function Interface (FFI) boundaries.
- [The keywords `pure`, `sizeof`, `alignof`, and `offsetof` have been unreserved
and can now be used as identifiers.][51196]
- [The `GlobalAlloc` trait and `#[global_allocator]` attribute are now
stable.][51241] This will allow users to specify a global allocator for
their program.
- [Unit test functions marked with the `#[test]` attribute can now return
`Result<(), E: Debug>` in addition to `()`.][51298]
- [The `lifetime` specifier for `macro_rules!` is now stable.][50385] This
allows macros to easily target lifetimes.
Compiler
--------
- [The `s` and `z` optimisation levels are now stable.][50265] These optimisations
prioritise making smaller binary sizes. `z` is the same as `s` with the
exception that it does not vectorise loops, which typically results in an even
smaller binary.
- [The short error format is now stable.][49546] Specified with
`--error-format=short` this option will provide a more compressed output of
rust error messages.
- [Added a lint warning when you have duplicated `macro_export`s.][50143]
- [Reduced the number of allocations in the macro parser.][50855] This can
improve compile times of macro heavy crates on average by 5%.
Libraries
---------
- [Implemented `Default` for `&mut str`.][51306]
- [Implemented `From<bool>` for all integer and unsigned number types.][50554]
- [Implemented `Extend` for `()`.][50234]
- [The `Debug` implementation of `time::Duration` should now be more easily
human readable.][50364] Previously a `Duration` of one second would printed as
`Duration { secs: 1, nanos: 0 }` and will now be printed as `1s`.
- [Implemented `From<&String>` for `Cow<str>`, `From<&Vec<T>>` for `Cow<[T]>`,
`From<Cow<CStr>>` for `CString`, `From<CString>, From<CStr>, From<&CString>`
for `Cow<CStr>`, `From<OsString>, From<OsStr>, From<&OsString>` for
`Cow<OsStr>`, `From<&PathBuf>` for `Cow<Path>`, and `From<Cow<Path>>`
for `PathBuf`.][50170]
- [Implemented `Shl` and `Shr` for `Wrapping<u128>`
and `Wrapping<i128>`.][50465]
- [`DirEntry::metadata` now uses `fstatat` instead of `lstat` when
possible.][51050] This can provide up to a 40% speed increase.
- [Improved error messages when using `format!`.][50610]
Stabilized APIs
---------------
- [`Iterator::step_by`]
- [`Path::ancestors`]
- [`btree_map::Entry::or_default`]
- [`fmt::Alignment`]
- [`hash_map::Entry::or_default`]
- [`iter::repeat_with`]
- [`num::NonZeroUsize`]
- [`num::NonZeroU128`]
- [`num::NonZeroU16`]
- [`num::NonZeroU32`]
- [`num::NonZeroU64`]
- [`num::NonZeroU8`]
- [`ops::RangeBounds`]
- [`slice::SliceIndex`]
- [`slice::from_mut`]
- [`slice::from_ref`]
- [`{Any + Send + Sync}::downcast_mut`]
- [`{Any + Send + Sync}::downcast_ref`]
- [`{Any + Send + Sync}::is`]
Cargo
-----
- [Cargo will now no longer allow you to publish crates with build scripts that
modify the `src` directory.][cargo/5584] The `src` directory in a crate should be
considered to be immutable.
Misc
----
- [The `suggestion_applicability` field in `rustc`'s json output is now
stable.][50486] This will allow dev tools to check whether a code suggestion
would apply to them.
Compatibility Notes
-------------------
- [Rust will no longer consider trait objects with duplicated constraints to
have implementations.][51276] For example the below code will now fail
to compile.
```rust
trait Trait {}
- The borrow checker was fixed to avoid potential unsoundness when using
match ergonomics: [#52213][52213].
impl Trait + Send {
fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test`
}
[52213]: https://github.com/rust-lang/rust/issues/52213
impl Trait + Send + Send {
fn test(&self) { println!("two"); }
}
```
[49546]: https://github.com/rust-lang/rust/pull/49546/
[50143]: https://github.com/rust-lang/rust/pull/50143/
[50170]: https://github.com/rust-lang/rust/pull/50170/
[50234]: https://github.com/rust-lang/rust/pull/50234/
[50265]: https://github.com/rust-lang/rust/pull/50265/
[50364]: https://github.com/rust-lang/rust/pull/50364/
[50385]: https://github.com/rust-lang/rust/pull/50385/
[50465]: https://github.com/rust-lang/rust/pull/50465/
[50486]: https://github.com/rust-lang/rust/pull/50486/
[50554]: https://github.com/rust-lang/rust/pull/50554/
[50610]: https://github.com/rust-lang/rust/pull/50610/
[50855]: https://github.com/rust-lang/rust/pull/50855/
[51050]: https://github.com/rust-lang/rust/pull/51050/
[51196]: https://github.com/rust-lang/rust/pull/51196/
[51200]: https://github.com/rust-lang/rust/pull/51200/
[51241]: https://github.com/rust-lang/rust/pull/51241/
[51276]: https://github.com/rust-lang/rust/pull/51276/
[51298]: https://github.com/rust-lang/rust/pull/51298/
[51306]: https://github.com/rust-lang/rust/pull/51306/
[51562]: https://github.com/rust-lang/rust/pull/51562/
[cargo/5584]: https://github.com/rust-lang/cargo/pull/5584/
[`Iterator::step_by`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.step_by
[`Path::ancestors`]: https://doc.rust-lang.org/std/path/struct.Path.html#method.ancestors
[`btree_map::Entry::or_default`]: https://doc.rust-lang.org/std/collections/btree_map/enum.Entry.html#method.or_default
[`fmt::Alignment`]: https://doc.rust-lang.org/std/fmt/enum.Alignment.html
[`hash_map::Entry::or_default`]: https://doc.rust-lang.org/std/collections/btree_map/enum.Entry.html#method.or_default
[`iter::repeat_with`]: https://doc.rust-lang.org/std/iter/fn.repeat_with.html
[`num::NonZeroUsize`]: https://doc.rust-lang.org/std/num/struct.NonZeroUsize.html
[`num::NonZeroU128`]: https://doc.rust-lang.org/std/num/struct.NonZeroU128.html
[`num::NonZeroU16`]: https://doc.rust-lang.org/std/num/struct.NonZeroU16.html
[`num::NonZeroU32`]: https://doc.rust-lang.org/std/num/struct.NonZeroU32.html
[`num::NonZeroU64`]: https://doc.rust-lang.org/std/num/struct.NonZeroU64.html
[`num::NonZeroU8`]: https://doc.rust-lang.org/std/num/struct.NonZeroU8.html
[`ops::RangeBounds`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html
[`slice::SliceIndex`]: https://doc.rust-lang.org/std/slice/trait.SliceIndex.html
[`slice::from_mut`]: https://doc.rust-lang.org/std/slice/fn.from_mut.html
[`slice::from_ref`]: https://doc.rust-lang.org/std/slice/fn.from_ref.html
[`{Any + Send + Sync}::downcast_mut`]: https://doc.rust-lang.org/std/any/trait.Any.html#method.downcast_mut-2
[`{Any + Send + Sync}::downcast_ref`]: https://doc.rust-lang.org/std/any/trait.Any.html#method.downcast_ref-2
[`{Any + Send + Sync}::is`]: https://doc.rust-lang.org/std/any/trait.Any.html#method.is-2
Version 1.27.1 (2018-07-10)
===========================
@ -18,7 +149,7 @@ Security Notes
- rustdoc would execute plugins in the /tmp/rustdoc/plugins directory
when running, which enabled executing code as some other user on a
given machine. This release fixes that vulnerability; you can read
more about this on the [blog][rustdoc-sec].
more about this on the [blog][rustdoc-sec]. The associated CVE is [CVE-2018-1000622].
Thank you to Red Hat for responsibily disclosing this vulnerability to us.
@ -31,6 +162,7 @@ Compatibility Notes
[51415]: https://github.com/rust-lang/rust/issues/51415
[49534]: https://github.com/rust-lang/rust/issues/49534
[rustdoc-sec]: https://blog.rust-lang.org/2018/07/06/security-advisory-for-rustdoc.html
[CVE-2018-1000622]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=%20CVE-2018-1000622
Version 1.27.0 (2018-06-21)
==========================
@ -90,7 +222,6 @@ Stabilized APIs
- [`Take::set_limit`]
- [`hint::unreachable_unchecked`]
- [`os::unix::process::parent_id`]
- [`process::id`]
- [`ptr::swap_nonoverlapping`]
- [`slice::rsplit_mut`]
- [`slice::rsplit`]
@ -100,6 +231,7 @@ Cargo
-----
- [`cargo-metadata` now includes `authors`, `categories`, `keywords`,
`readme`, and `repository` fields.][cargo/5386]
- [`cargo-metadata` now includes a package's `metadata` table.][cargo/5360]
- [Added the `--target-dir` optional argument.][cargo/5393] This allows you to specify
a different directory than `target` for placing compilation artifacts.
- [Cargo will be adding automatic target inference for binaries, benchmarks,
@ -149,6 +281,7 @@ Compatibility Notes
[cargo/5203]: https://github.com/rust-lang/cargo/pull/5203/
[cargo/5335]: https://github.com/rust-lang/cargo/pull/5335/
[cargo/5359]: https://github.com/rust-lang/cargo/pull/5359/
[cargo/5360]: https://github.com/rust-lang/cargo/pull/5360/
[cargo/5386]: https://github.com/rust-lang/cargo/pull/5386/
[cargo/5393]: https://github.com/rust-lang/cargo/pull/5393/
[`DoubleEndedIterator::rfind`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.rfind
@ -165,17 +298,15 @@ Compatibility Notes
[`Option::filter`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.filter
[`String::replace_range`]: https://doc.rust-lang.org/std/string/struct.String.html#method.replace_range
[`Take::set_limit`]: https://doc.rust-lang.org/std/io/struct.Take.html#method.set_limit
[`hint::unreachable_unchecked`]: https://doc.rust-lang.org/std/hint/fn.unreachable_unchecked.html
[`os::unix::process::parent_id`]: https://doc.rust-lang.org/std/os/unix/process/fn.parent_id.html
[`process::id`]: https://doc.rust-lang.org/std/process/fn.id.html
[`ptr::swap_nonoverlapping`]: https://doc.rust-lang.org/std/ptr/fn.swap_nonoverlapping.html
[`slice::rsplit_mut`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rsplit_mut
[`slice::rsplit`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rsplit
[`slice::swap_with_slice`]: https://doc.rust-lang.org/std/primitive.slice.html#method.swap_with_slice
[`arch::x86_64`]: https://doc.rust-lang.org/std/arch/x86_64/index.html
[`arch::x86`]: https://doc.rust-lang.org/std/arch/x86/index.html
[`fs::read`]:
[`fs::write`]:
[`hint::unreachable_unchecked`]: https://doc.rust-lang.org/std/hint/fn.unreachable_unchecked.html
[`os::unix::process::parent_id`]: https://doc.rust-lang.org/std/os/unix/process/fn.parent_id.html
[`ptr::swap_nonoverlapping`]: https://doc.rust-lang.org/std/ptr/fn.swap_nonoverlapping.html
[`process::id`]: https://doc.rust-lang.org/std/process/fn.id.html
[“The Rustc book”]: https://doc.rust-lang.org/rustc
@ -199,6 +330,7 @@ Tools
- [RLS now works on Windows][50646]
- [Rustfmt stopped badly formatting text in some cases][rustfmt/2695]
Compatibility Notes
--------
@ -222,7 +354,7 @@ Language
- [Closures now implement `Copy` and/or `Clone` if all captured variables
implement either or both traits.][49299]
- [The inclusive range syntax e.g. `for x in 0..=10` is now stable.][47813]
- [Stablise `'_`. The underscore lifetime can be used anywhere where a
- [The `'_` lifetime is now stable. The underscore lifetime can be used anywhere where a
lifetime can be elided.][49458]
- [`impl Trait` is now stable allowing you to have abstract types in returns
or in function parameters.][49255] e.g. `fn foo() -> impl Iterator<Item=u8>` or
@ -313,7 +445,6 @@ Cargo
- [Cargo will now output path to custom commands when `-v` is
passed with `--list`][cargo/5041]
- [The Cargo binary version is now the same as the Rust version][cargo/5083]
- [`Cargo.lock` files are now included in published crates.][cargo/5093]
Misc
----
@ -417,7 +548,6 @@ Compatibility Notes
[`String::retain`]: https://doc.rust-lang.org/std/string/struct.String.html#method.retain
[cargo/5041]: https://github.com/rust-lang/cargo/pull/5041
[cargo/5083]: https://github.com/rust-lang/cargo/pull/5083
[cargo/5093]: https://github.com/rust-lang/cargo/pull/5093
Version 1.25.0 (2018-03-29)
@ -425,7 +555,7 @@ Version 1.25.0 (2018-03-29)
Language
--------
- [Stabilised `#[repr(align(x))]`.][47006] [RFC 1358]
- [The `#[repr(align(x))]` attribute is now stable.][47006] [RFC 1358]
- [You can now use nested groups of imports.][47948]
e.g. `use std::{fs::File, io::Read, path::{Path, PathBuf}};`
- [You can now have `|` at the start of a match arm.][47947] e.g.

View File

@ -76,6 +76,10 @@
# passed to prefer linking to shared libraries.
#link-shared = false
# On MSVC you can compile LLVM with clang-cl, but the test suite doesn't pass
# with clang-cl, so this is special in that it only compiles LLVM with clang-cl
#clang-cl = '/path/to/clang-cl.exe'
# =============================================================================
# General build configuration options
# =============================================================================
@ -275,6 +279,9 @@
# Whether or not `panic!`s generate backtraces (RUST_BACKTRACE)
#backtrace = true
# Whether to always use incremental compilation when building rustc
#incremental = false
# Build rustc with experimental parallelization
#experimental-parallel-queries = false
@ -294,9 +301,9 @@
# desired in distributions, for example.
#rpath = true
# Suppresses extraneous output from tests to ensure the output of the test
# harness is relatively clean.
#quiet-tests = false
# Emits extraneous output from tests to ensure that failures of the test
# harness are debuggable just from logfiles.
#verbose-tests = false
# Flag indicating whether tests are compiled with optimizations (the -O flag) or
# with debuginfo (the -g flag)

View File

@ -1 +1 @@
58cc626de3301192d5d8c6dcbde43b5b44211ae2
0aaa819fea00a6bf2b1303b9eb47f142f099cf5a

617
src/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@ members = [
"rustc",
"libstd",
"libtest",
"librustc_trans",
"librustc_codegen_llvm",
"tools/cargotest",
"tools/clippy",
"tools/compiletest",
@ -40,6 +40,13 @@ members = [
"tools/rls/test_data/workspace_symbol",
]
# Curiously, libtest will segfault if compiled with opt-level=3
# with some versions of XCode: https://github.com/rust-lang/rust/issues/50867
[profile.release]
opt-level = 2
[profile.bench]
opt-level = 2
# These options are controlled from our rustc wrapper script, so turn them off
# here and have them controlled elsewhere.
[profile.dev]
@ -57,11 +64,8 @@ debug-assertions = false
[patch."https://github.com/rust-lang/cargo"]
cargo = { path = "tools/cargo" }
[patch.crates-io]
[patch."https://github.com/rust-lang-nursery/rustfmt"]
# Similar to Cargo above we want the RLS to use a vendored version of `rustfmt`
# that we're shipping as well (to ensure that the rustfmt in RLS and the
# `rustfmt` executable are the same exact vesion). Unlike Cargo, however, the
# RLS depends on `rustfmt` from crates.io, so we put this in a `[patch]` section
# for crates.io
# `rustfmt` executable are the same exact vesion).
rustfmt-nightly = { path = "tools/rustfmt" }
clippy_lints = { path = "tools/clippy/clippy_lints" }

View File

@ -6,7 +6,7 @@ This directory contains the source code of the rust project, including:
For more information on how various parts of the compiler work, see the [rustc guide].
Their is also useful content in the following READMEs, which are gradually being moved over to the guide:
- https://github.com/rust-lang/rust/tree/master/src/librustc/ty/maps
- https://github.com/rust-lang/rust/tree/master/src/librustc/ty/query
- https://github.com/rust-lang/rust/tree/master/src/librustc/dep_graph
- https://github.com/rust-lang/rust/blob/master/src/librustc/infer/region_constraints
- https://github.com/rust-lang/rust/tree/master/src/librustc/infer/higher_ranked

View File

@ -28,6 +28,11 @@ name = "sccache-plus-cl"
path = "bin/sccache-plus-cl.rs"
test = false
[[bin]]
name = "llvm-config-wrapper"
path = "bin/llvm-config-wrapper.rs"
test = false
[dependencies]
build_helper = { path = "../build_helper" }
cmake = "0.1.23"

View File

@ -0,0 +1,27 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// The sheer existence of this file is an awful hack. See the comments in
// `src/bootstrap/native.rs` for why this is needed when compiling LLD.
use std::env;
use std::process::{self, Stdio, Command};
use std::io::{self, Write};
fn main() {
let real_llvm_config = env::var_os("LLVM_CONFIG_REAL").unwrap();
let mut cmd = Command::new(real_llvm_config);
cmd.args(env::args().skip(1)).stderr(Stdio::piped());
let output = cmd.output().expect("failed to spawn llvm-config");
let stdout = String::from_utf8_lossy(&output.stdout);
print!("{}", stdout.replace("\\", "/"));
io::stdout().flush().unwrap();
process::exit(output.status.code().unwrap_or(1));
}

View File

@ -268,6 +268,15 @@ fn main() {
if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
cmd.arg(format!("-Clinker={}", host_linker));
}
if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
if s == "true" {
cmd.arg("-C").arg("target-feature=+crt-static");
}
if s == "false" {
cmd.arg("-C").arg("target-feature=-crt-static");
}
}
}
if env::var_os("RUSTC_PARALLEL_QUERIES").is_some() {
@ -288,7 +297,12 @@ fn main() {
}
if verbose > 1 {
eprintln!("rustc command: {:?}", cmd);
eprintln!(
"rustc command: {:?}={:?} {:?}",
bootstrap::util::dylib_path_var(),
env::join_paths(&dylib_path).unwrap(),
cmd,
);
eprintln!("sysroot: {:?}", sysroot);
eprintln!("libdir: {:?}", libdir);
}

View File

@ -16,8 +16,8 @@ use std::process::{self, Command};
fn main() {
let target = env::var("SCCACHE_TARGET").unwrap();
// Locate the actual compiler that we're invoking
env::remove_var("CC");
env::remove_var("CXX");
env::set_var("CC", env::var_os("SCCACHE_CC").unwrap());
env::set_var("CXX", env::var_os("SCCACHE_CXX").unwrap());
let mut cfg = cc::Build::new();
cfg.cargo_metadata(false)
.out_dir("/")
@ -39,6 +39,12 @@ fn main() {
cmd.arg(arg);
}
if let Ok(s) = env::var("SCCACHE_EXTRA_ARGS") {
for s in s.split_whitespace() {
cmd.arg(s);
}
}
let status = cmd.status().expect("failed to spawn");
process::exit(status.code().unwrap_or(2))
}

View File

@ -489,7 +489,7 @@ class RustBuild(object):
"""
return os.path.join(self.build_dir, self.build, "stage0")
def get_toml(self, key):
def get_toml(self, key, section=None):
"""Returns the value of the given key in config.toml, otherwise returns None
>>> rb = RustBuild()
@ -501,12 +501,29 @@ class RustBuild(object):
>>> rb.get_toml("key3") is None
True
Optionally also matches the section the key appears in
>>> rb.config_toml = '[a]\\nkey = "value1"\\n[b]\\nkey = "value2"'
>>> rb.get_toml('key', 'a')
'value1'
>>> rb.get_toml('key', 'b')
'value2'
>>> rb.get_toml('key', 'c') is None
True
"""
cur_section = None
for line in self.config_toml.splitlines():
section_match = re.match(r'^\s*\[(.*)\]\s*$', line)
if section_match is not None:
cur_section = section_match.group(1)
match = re.match(r'^{}\s*=(.*)$'.format(key), line)
if match is not None:
value = match.group(1)
return self.get_string(value) or value.strip()
if section is None or section == cur_section:
return self.get_string(value) or value.strip()
return None
def cargo(self):
@ -589,7 +606,17 @@ class RustBuild(object):
env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
(os.pathsep + env["LIBRARY_PATH"]) \
if "LIBRARY_PATH" in env else ""
env["RUSTFLAGS"] = "-Cdebuginfo=2"
env["RUSTFLAGS"] = "-Cdebuginfo=2 "
build_section = "target.{}".format(self.build_triple())
target_features = []
if self.get_toml("crt-static", build_section) == "true":
target_features += ["+crt-static"]
elif self.get_toml("crt-static", build_section) == "false":
target_features += ["-crt-static"]
if target_features:
env["RUSTFLAGS"] += "-C target-feature=" + (",".join(target_features)) + " "
env["PATH"] = os.path.join(self.bin_root(), "bin") + \
os.pathsep + env["PATH"]
if not os.path.isfile(self.cargo()):

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,7 @@ use Build;
use config::Config;
// The version number
pub const CFG_RELEASE_NUM: &str = "1.27.2";
pub const CFG_RELEASE_NUM: &str = "1.28.0";
pub struct GitInfo {
inner: Option<Info>,

View File

@ -40,10 +40,10 @@ impl Step for Std {
let target = self.target;
let compiler = builder.compiler(0, builder.config.build);
let out_dir = builder.stage_out(compiler, Mode::Libstd);
let out_dir = builder.stage_out(compiler, Mode::Std);
builder.clear_if_dirty(&out_dir, &builder.rustc(compiler));
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "check");
let mut cargo = builder.cargo(compiler, Mode::Std, target, "check");
std_cargo(builder, &compiler, target, &mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage));
@ -87,11 +87,11 @@ impl Step for Rustc {
let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
let stage_out = builder.stage_out(compiler, Mode::Librustc);
let stage_out = builder.stage_out(compiler, Mode::Rustc);
builder.clear_if_dirty(&stage_out, &libstd_stamp(builder, compiler, target));
builder.clear_if_dirty(&stage_out, &libtest_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check");
let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "check");
rustc_cargo(builder, &mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage));
@ -118,7 +118,7 @@ impl Step for CodegenBackend {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.all_krates("rustc_trans")
run.all_krates("rustc_codegen_llvm")
}
fn make_run(run: RunConfig) {
@ -137,14 +137,14 @@ impl Step for CodegenBackend {
let target = self.target;
let backend = self.backend;
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check");
let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "check");
let features = builder.rustc_features().to_string();
cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_trans/Cargo.toml"));
cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml"));
rustc_cargo_env(builder, &mut cargo);
// We won't build LLVM if it's not available, as it shouldn't affect `check`.
let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage));
run_cargo(builder,
cargo.arg("--features").arg(features),
&codegen_backend_stamp(builder, compiler, target, backend),
@ -175,10 +175,10 @@ impl Step for Test {
let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
let out_dir = builder.stage_out(compiler, Mode::Libtest);
let out_dir = builder.stage_out(compiler, Mode::Test);
builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "check");
let mut cargo = builder.cargo(compiler, Mode::Test, target, "check");
test_cargo(builder, &compiler, target, &mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage));
@ -219,6 +219,7 @@ impl Step for Rustdoc {
let mut cargo = prepare_tool_cargo(builder,
compiler,
Mode::ToolRustc,
target,
"check",
"src/tools/rustdoc");
@ -236,7 +237,7 @@ impl Step for Rustdoc {
builder.ensure(tool::CleanTools {
compiler,
target,
mode: Mode::Tool,
cause: Mode::Rustc,
});
}
}
@ -244,33 +245,33 @@ impl Step for Rustdoc {
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
pub fn libstd_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Libstd, target).join(".libstd-check.stamp")
builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
}
/// Cargo's output path for libtest in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn libtest_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Libtest, target).join(".libtest-check.stamp")
builder.cargo_out(compiler, Mode::Test, target).join(".libtest-check.stamp")
}
/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Librustc, target).join(".librustc-check.stamp")
builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
}
/// Cargo's output path for librustc_trans in a given stage, compiled by a particular
/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
/// compiler for the specified target and backend.
fn codegen_backend_stamp(builder: &Builder,
compiler: Compiler,
target: Interned<String>,
backend: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Librustc, target)
.join(format!(".librustc_trans-{}-check.stamp", backend))
builder.cargo_out(compiler, Mode::Codegen, target)
.join(format!(".librustc_codegen_llvm-{}-check.stamp", backend))
}
/// Cargo's output path for rustdoc in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn rustdoc_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Tool, target).join(".rustdoc-check.stamp")
builder.cargo_out(compiler, Mode::ToolRustc, target).join(".rustdoc-check.stamp")
}

View File

@ -98,9 +98,9 @@ impl Step for Std {
copy_musl_third_party_objects(builder, target, &libdir);
}
let out_dir = builder.cargo_out(compiler, Mode::Libstd, target);
let out_dir = builder.cargo_out(compiler, Mode::Std, target);
builder.clear_if_dirty(&out_dir, &builder.rustc(compiler));
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "build");
let mut cargo = builder.cargo(compiler, Mode::Std, target, "build");
std_cargo(builder, &compiler, target, &mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage));
@ -240,7 +240,7 @@ impl Step for StdLink {
builder.ensure(tool::CleanTools {
compiler: target_compiler,
target,
mode: Mode::Libstd,
cause: Mode::Std,
});
}
}
@ -368,9 +368,9 @@ impl Step for Test {
return;
}
let out_dir = builder.cargo_out(compiler, Mode::Libtest, target);
let out_dir = builder.cargo_out(compiler, Mode::Test, target);
builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "build");
let mut cargo = builder.cargo(compiler, Mode::Test, target, "build");
test_cargo(builder, &compiler, target, &mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage));
@ -431,7 +431,7 @@ impl Step for TestLink {
builder.ensure(tool::CleanTools {
compiler: target_compiler,
target,
mode: Mode::Libtest,
cause: Mode::Test,
});
}
}
@ -489,11 +489,11 @@ impl Step for Rustc {
compiler: builder.compiler(self.compiler.stage, builder.config.build),
target: builder.config.build,
});
let cargo_out = builder.cargo_out(compiler, Mode::Librustc, target);
let cargo_out = builder.cargo_out(compiler, Mode::Rustc, target);
builder.clear_if_dirty(&cargo_out, &libstd_stamp(builder, compiler, target));
builder.clear_if_dirty(&cargo_out, &libtest_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "build");
rustc_cargo(builder, &mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage));
@ -585,7 +585,7 @@ impl Step for RustcLink {
builder.ensure(tool::CleanTools {
compiler: target_compiler,
target,
mode: Mode::Librustc,
cause: Mode::Rustc,
});
}
}
@ -603,7 +603,7 @@ impl Step for CodegenBackend {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.all_krates("rustc_trans")
run.all_krates("rustc_codegen_llvm")
}
fn make_run(run: RunConfig) {
@ -634,18 +634,18 @@ impl Step for CodegenBackend {
return;
}
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "build");
let mut features = builder.rustc_features().to_string();
cargo.arg("--manifest-path")
.arg(builder.src.join("src/librustc_trans/Cargo.toml"));
.arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml"));
rustc_cargo_env(builder, &mut cargo);
features += &build_codegen_backend(&builder, &mut cargo, &compiler, target, backend);
let tmp_stamp = builder.cargo_out(compiler, Mode::Librustc, target)
let tmp_stamp = builder.cargo_out(compiler, Mode::Codegen, target)
.join(".tmp.stamp");
let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage));
let files = run_cargo(builder,
cargo.arg("--features").arg(features),
&tmp_stamp,
@ -656,7 +656,7 @@ impl Step for CodegenBackend {
let mut files = files.into_iter()
.filter(|f| {
let filename = f.file_name().unwrap().to_str().unwrap();
is_dylib(filename) && filename.contains("rustc_trans-")
is_dylib(filename) && filename.contains("rustc_codegen_llvm-")
});
let codegen_backend = match files.next() {
Some(f) => f,
@ -697,7 +697,7 @@ pub fn build_codegen_backend(builder: &Builder,
compiler.stage, &compiler.host, target, backend));
// Pass down configuration from the LLVM build into the build of
// librustc_llvm and librustc_trans.
// librustc_llvm and librustc_codegen_llvm.
if builder.is_rust_llvm(target) {
cargo.env("LLVM_RUSTLLVM", "1");
}
@ -762,7 +762,7 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder,
t!(t!(File::open(&stamp)).read_to_string(&mut dylib));
let file = Path::new(&dylib);
let filename = file.file_name().unwrap().to_str().unwrap();
// change `librustc_trans-xxxxxx.so` to `librustc_trans-llvm.so`
// change `librustc_codegen_llvm-xxxxxx.so` to `librustc_codegen_llvm-llvm.so`
let target_filename = {
let dash = filename.find("-").unwrap();
let dot = filename.find(".").unwrap();
@ -793,29 +793,29 @@ fn copy_lld_to_sysroot(builder: &Builder,
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
pub fn libstd_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp")
builder.cargo_out(compiler, Mode::Std, target).join(".libstd.stamp")
}
/// Cargo's output path for libtest in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn libtest_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp")
builder.cargo_out(compiler, Mode::Test, target).join(".libtest.stamp")
}
/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp")
builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc.stamp")
}
/// Cargo's output path for librustc_trans in a given stage, compiled by a particular
/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
/// compiler for the specified target and backend.
fn codegen_backend_stamp(builder: &Builder,
compiler: Compiler,
target: Interned<String>,
backend: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Librustc, target)
.join(format!(".librustc_trans-{}.stamp", backend))
builder.cargo_out(compiler, Mode::Codegen, target)
.join(format!(".librustc_codegen_llvm-{}.stamp", backend))
}
pub fn compiler_file(builder: &Builder,
@ -971,8 +971,8 @@ impl Step for Assemble {
}
// Link the compiler binary itself into place
let out_dir = builder.cargo_out(build_compiler, Mode::Librustc, host);
let rustc = out_dir.join(exe("rustc", &*host));
let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host);
let rustc = out_dir.join(exe("rustc_binary", &*host));
let bindir = sysroot.join("bin");
t!(fs::create_dir_all(&bindir));
let compiler = builder.rustc(target_compiler);

View File

@ -82,6 +82,7 @@ pub struct Config {
pub llvm_version_check: bool,
pub llvm_static_stdcpp: bool,
pub llvm_link_shared: bool,
pub llvm_clang_cl: Option<String>,
pub llvm_targets: Option<String>,
pub llvm_experimental_targets: String,
pub llvm_link_jobs: Option<u32>,
@ -124,7 +125,7 @@ pub struct Config {
// misc
pub low_priority: bool,
pub channel: String,
pub quiet_tests: bool,
pub verbose_tests: bool,
pub test_miri: bool,
pub save_toolstates: Option<PathBuf>,
pub print_step_timings: bool,
@ -250,6 +251,7 @@ struct Llvm {
experimental_targets: Option<String>,
link_jobs: Option<u32>,
link_shared: Option<bool>,
clang_cl: Option<String>
}
#[derive(Deserialize, Default, Clone)]
@ -299,8 +301,9 @@ struct Rust {
ignore_git: Option<bool>,
debug: Option<bool>,
dist_src: Option<bool>,
quiet_tests: Option<bool>,
verbose_tests: Option<bool>,
test_miri: Option<bool>,
incremental: Option<bool>,
save_toolstates: Option<String>,
codegen_backends: Option<Vec<String>>,
codegen_backends_dir: Option<String>,
@ -504,6 +507,7 @@ impl Config {
config.llvm_experimental_targets = llvm.experimental_targets.clone()
.unwrap_or("WebAssembly".to_string());
config.llvm_link_jobs = llvm.link_jobs;
config.llvm_clang_cl = llvm.clang_cl.clone();
}
if let Some(ref rust) = toml.rust {
@ -524,8 +528,12 @@ impl Config {
set(&mut config.backtrace, rust.backtrace);
set(&mut config.channel, rust.channel.clone());
set(&mut config.rust_dist_src, rust.dist_src);
set(&mut config.quiet_tests, rust.quiet_tests);
set(&mut config.verbose_tests, rust.verbose_tests);
set(&mut config.test_miri, rust.test_miri);
// in the case "false" is set explicitly, do not overwrite the command line args
if let Some(true) = rust.incremental {
config.incremental = true;
}
set(&mut config.wasm_syscall, rust.wasm_syscall);
set(&mut config.lld_enabled, rust.lld);
config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false);

View File

@ -47,7 +47,7 @@ o("optimize-tests", "rust.optimize-tests", "build tests with optimizations")
o("experimental-parallel-queries", "rust.experimental-parallel-queries", "build rustc with experimental parallelization")
o("test-miri", "rust.test-miri", "run miri's test suite")
o("debuginfo-tests", "rust.debuginfo-tests", "build tests with debugger metadata")
o("quiet-tests", "rust.quiet-tests", "enable quieter output when running tests")
o("verbose-tests", "rust.verbose-tests", "enable verbose output when running tests")
o("ccache", "llvm.ccache", "invoke gcc/clang via ccache to reuse object files between builds")
o("sccache", None, "invoke gcc/clang via sccache to reuse object files between builds")
o("local-rust", None, "use an installed rustc rather than downloading a snapshot")

View File

@ -722,7 +722,7 @@ impl Step for Analysis {
let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
let src = builder.stage_out(compiler, Mode::Libstd)
let src = builder.stage_out(compiler, Mode::Std)
.join(target).join(builder.cargo_dir()).join("deps");
let image_src = src.join("save-analysis");
@ -951,13 +951,16 @@ impl Step for PlainSourceTarball {
has_cargo_vendor |= line.starts_with("cargo-vendor ");
}
if !has_cargo_vendor {
let mut cmd = Command::new(&builder.initial_cargo);
cmd.arg("install")
.arg("--force")
let mut cmd = builder.cargo(
builder.compiler(0, builder.config.build),
Mode::ToolRustc,
builder.config.build,
"install"
);
cmd.arg("--force")
.arg("--debug")
.arg("--vers").arg(CARGO_VENDOR_VERSION)
.arg("cargo-vendor")
.env("RUSTC", &builder.initial_rustc);
.arg("cargo-vendor");
if let Some(dir) = builder.openssl_install_dir(builder.config.build) {
builder.ensure(native::Openssl {
target: builder.config.build,

View File

@ -28,7 +28,7 @@ use build_helper::up_to_date;
use util::symlink_dir;
use builder::{Builder, Compiler, RunConfig, ShouldRun, Step};
use tool::Tool;
use tool::{self, prepare_tool_cargo, Tool};
use compile;
use cache::{INTERNER, Interned};
use config::Config;
@ -70,7 +70,7 @@ macro_rules! book {
book!(
Nomicon, "src/doc/nomicon", "nomicon";
Reference, "src/doc/reference", "reference";
Rustdoc, "src/doc/rustdoc", "rustdoc";
RustdocBook, "src/doc/rustdoc", "rustdoc";
RustcBook, "src/doc/rustc", "rustc";
RustByExample, "src/doc/rust-by-example", "rust-by-example";
);
@ -272,6 +272,12 @@ impl Step for TheBook {
name: INTERNER.intern_string(format!("{}/second-edition", name)),
});
// build book 2018 edition
builder.ensure(Rustbook {
target,
name: INTERNER.intern_string(format!("{}/2018-edition", name)),
});
// build the version info page and CSS
builder.ensure(Standalone {
compiler,
@ -457,7 +463,7 @@ impl Step for Std {
};
builder.ensure(compile::Std { compiler, target });
let out_dir = builder.stage_out(compiler, Mode::Libstd)
let out_dir = builder.stage_out(compiler, Mode::Std)
.join(target).join("doc");
// Here what we're doing is creating a *symlink* (directory junction on
@ -477,7 +483,7 @@ impl Step for Std {
builder.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "doc");
let mut cargo = builder.cargo(compiler, Mode::Std, target, "doc");
compile::std_cargo(builder, &compiler, target, &mut cargo);
// Keep a whitelist so we do not build internal stdlib crates, these will be
@ -540,7 +546,7 @@ impl Step for Test {
builder.ensure(Std { stage, target });
builder.ensure(compile::Test { compiler, target });
let out_dir = builder.stage_out(compiler, Mode::Libtest)
let out_dir = builder.stage_out(compiler, Mode::Test)
.join(target).join("doc");
// See docs in std above for why we symlink
@ -548,7 +554,7 @@ impl Step for Test {
builder.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "doc");
let mut cargo = builder.cargo(compiler, Mode::Test, target, "doc");
compile::test_cargo(builder, &compiler, target, &mut cargo);
cargo.arg("--no-deps").arg("-p").arg("test");
@ -608,7 +614,7 @@ impl Step for WhitelistedRustc {
builder.ensure(Std { stage, target });
builder.ensure(compile::Rustc { compiler, target });
let out_dir = builder.stage_out(compiler, Mode::Librustc)
let out_dir = builder.stage_out(compiler, Mode::Rustc)
.join(target).join("doc");
// See docs in std above for why we symlink
@ -616,7 +622,7 @@ impl Step for WhitelistedRustc {
builder.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc");
compile::rustc_cargo(builder, &mut cargo);
// We don't want to build docs for internal compiler dependencies in this
@ -665,8 +671,12 @@ impl Step for Rustc {
let stage = self.stage;
let target = self.target;
builder.info(&format!("Documenting stage{} compiler ({})", stage, target));
// This is the intended out directory for compiler documentation.
let out = builder.compiler_doc_out(target);
t!(fs::create_dir_all(&out));
// Get the correct compiler for this stage.
let compiler = builder.compiler(stage, builder.config.build);
let rustdoc = builder.rustdoc(compiler.host);
let compiler = if builder.force_use_stage1(compiler, target) {
@ -676,22 +686,24 @@ impl Step for Rustc {
};
if !builder.config.compiler_docs {
builder.info(&format!("\tskipping - compiler docs disabled"));
builder.info(&format!("\tskipping - compiler/librustdoc docs disabled"));
return;
}
// Build libstd docs so that we generate relative links
// Build libstd docs so that we generate relative links.
builder.ensure(Std { stage, target });
// Build rustc.
builder.ensure(compile::Rustc { compiler, target });
let out_dir = builder.stage_out(compiler, Mode::Librustc)
.join(target).join("doc");
// We do not symlink to the same shared folder that already contains std library
// documentation from previous steps as we do not want to include that.
let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target).join("doc");
builder.clear_if_dirty(&out, &rustdoc);
t!(symlink_dir_force(&builder.config, &out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
// Build cargo command.
let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc");
cargo.env("RUSTDOCFLAGS", "--document-private-items");
compile::rustc_cargo(builder, &mut cargo);
@ -729,6 +741,78 @@ fn find_compiler_crates(
}
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Rustdoc {
stage: u32,
target: Interned<String>,
}
impl Step for Rustdoc {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.krate("rustdoc-tool")
}
fn make_run(run: RunConfig) {
run.builder.ensure(Rustdoc {
stage: run.builder.top_stage,
target: run.target,
});
}
/// Generate compiler documentation.
///
/// This will generate all documentation for compiler and dependencies.
/// Compiler documentation is distributed separately, so we make sure
/// we do not merge it with the other documentation from std, test and
/// proc_macros. This is largely just a wrapper around `cargo doc`.
fn run(self, builder: &Builder) {
let stage = self.stage;
let target = self.target;
builder.info(&format!("Documenting stage{} rustdoc ({})", stage, target));
// This is the intended out directory for compiler documentation.
let out = builder.compiler_doc_out(target);
t!(fs::create_dir_all(&out));
// Get the correct compiler for this stage.
let compiler = builder.compiler(stage, builder.config.build);
let rustdoc = builder.rustdoc(compiler.host);
let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
compiler
};
if !builder.config.compiler_docs {
builder.info(&format!("\tskipping - compiler/librustdoc docs disabled"));
return;
}
// Build libstd docs so that we generate relative links.
builder.ensure(Std { stage, target });
// Build rustdoc.
builder.ensure(tool::Rustdoc { host: compiler.host });
// Symlink compiler docs to the output directory of rustdoc documentation.
let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target).join("doc");
t!(fs::create_dir_all(&out_dir));
builder.clear_if_dirty(&out, &rustdoc);
t!(symlink_dir_force(&builder.config, &out, &out_dir));
// Build cargo command.
let mut cargo = prepare_tool_cargo(
builder, compiler, Mode::ToolRustc, target, "doc", "src/tools/rustdoc");
cargo.env("RUSTDOCFLAGS", "--document-private-items");
builder.run(&mut cargo);
}
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct ErrorIndex {
target: Interned<String>,

View File

@ -19,10 +19,10 @@ use std::process;
use getopts::Options;
use {Build, DocTests};
use builder::Builder;
use config::Config;
use metadata;
use builder::Builder;
use {Build, DocTests};
use cache::{Interned, INTERNER};
@ -59,6 +59,9 @@ pub enum Subcommand {
},
Test {
paths: Vec<PathBuf>,
/// Whether to automatically update stderr/stdout files
bless: bool,
compare_mode: Option<String>,
test_args: Vec<String>,
rustc_args: Vec<String>,
fail_fast: bool,
@ -90,7 +93,8 @@ impl Default for Subcommand {
impl Flags {
pub fn parse(args: &[String]) -> Flags {
let mut extra_help = String::new();
let mut subcommand_help = format!("\
let mut subcommand_help = format!(
"\
Usage: x.py <subcommand> [options] [<paths>...]
Subcommands:
@ -103,7 +107,8 @@ Subcommands:
dist Build distribution artifacts
install Install distribution artifacts
To learn more about a subcommand, run `./x.py <subcommand> -h`");
To learn more about a subcommand, run `./x.py <subcommand> -h`"
);
let mut opts = Options::new();
// Options common to all subcommands
@ -121,33 +126,39 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
opts.optflag("h", "help", "print this help message");
opts.optopt("", "warnings", "if value is deny, will deny warnings, otherwise use default",
"VALUE");
opts.optopt(
"",
"warnings",
"if value is deny, will deny warnings, otherwise use default",
"VALUE",
);
opts.optopt("", "error-format", "rustc error format", "FORMAT");
// fn usage()
let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! {
println!("{}", opts.usage(subcommand_help));
if !extra_help.is_empty() {
println!("{}", extra_help);
}
process::exit(exit_code);
};
let usage =
|exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! {
println!("{}", opts.usage(subcommand_help));
if !extra_help.is_empty() {
println!("{}", extra_help);
}
process::exit(exit_code);
};
// We can't use getopt to parse the options until we have completed specifying which
// options are valid, but under the current implementation, some options are conditional on
// the subcommand. Therefore we must manually identify the subcommand first, so that we can
// complete the definition of the options. Then we can use the getopt::Matches object from
// there on out.
let subcommand = args.iter().find(|&s|
let subcommand = args.iter().find(|&s| {
(s == "build")
|| (s == "check")
|| (s == "test")
|| (s == "bench")
|| (s == "doc")
|| (s == "clean")
|| (s == "dist")
|| (s == "install"));
|| (s == "check")
|| (s == "test")
|| (s == "bench")
|| (s == "doc")
|| (s == "clean")
|| (s == "dist")
|| (s == "install")
});
let subcommand = match subcommand {
Some(s) => s,
None => {
@ -162,7 +173,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
// Some subcommands get extra options
match subcommand.as_str() {
"test" => {
"test" => {
opts.optflag("", "no-fail-fast", "Run all tests regardless of failure");
opts.optmulti("", "test-args", "extra arguments", "ARGS");
opts.optmulti(
@ -173,10 +184,25 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
);
opts.optflag("", "no-doc", "do not run doc tests");
opts.optflag("", "doc", "only run doc tests");
},
"bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
"clean" => { opts.optflag("", "all", "clean all build artifacts"); },
_ => { },
opts.optflag(
"",
"bless",
"update all stderr/stdout files of failing ui tests",
);
opts.optopt(
"",
"compare-mode",
"mode describing what file the actual ui output will be compared to",
"COMPARE MODE",
);
}
"bench" => {
opts.optmulti("", "test-args", "extra arguments", "ARGS");
}
"clean" => {
opts.optflag("", "all", "clean all build artifacts");
}
_ => {}
};
// Done specifying what options are possible, so do the getopts parsing
@ -196,21 +222,24 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
if check_subcommand != subcommand {
pass_sanity_check = false;
}
},
}
None => {
pass_sanity_check = false;
}
}
if !pass_sanity_check {
println!("{}\n", subcommand_help);
println!("Sorry, I couldn't figure out which subcommand you were trying to specify.\n\
You may need to move some options to after the subcommand.\n");
println!(
"Sorry, I couldn't figure out which subcommand you were trying to specify.\n\
You may need to move some options to after the subcommand.\n"
);
process::exit(1);
}
// Extra help text for some commands
match subcommand.as_str() {
"build" => {
subcommand_help.push_str("\n
subcommand_help.push_str(
"\n
Arguments:
This subcommand accepts a number of paths to directories to the crates
and/or artifacts to compile. For example:
@ -232,10 +261,12 @@ Arguments:
This will first build everything once (like --stage 0 without further
arguments would), and then use the compiler built in stage 0 to build
src/libtest and its dependencies.
Once this is done, build/$ARCH/stage1 contains a usable compiler.");
Once this is done, build/$ARCH/stage1 contains a usable compiler.",
);
}
"check" => {
subcommand_help.push_str("\n
subcommand_help.push_str(
"\n
Arguments:
This subcommand accepts a number of paths to directories to the crates
and/or artifacts to compile. For example:
@ -247,10 +278,12 @@ Arguments:
also that since we use `cargo check`, by default this will automatically enable incremental
compilation, so there's no need to pass it separately, though it won't hurt. We also completely
ignore the stage passed, as there's no way to compile in non-stage 0 without actually building
the compiler.");
the compiler.",
);
}
"test" => {
subcommand_help.push_str("\n
subcommand_help.push_str(
"\n
Arguments:
This subcommand accepts a number of paths to directories to tests that
should be compiled and run. For example:
@ -258,15 +291,19 @@ Arguments:
./x.py test src/test/run-pass
./x.py test src/libstd --test-args hash_map
./x.py test src/libstd --stage 0
./x.py test src/test/ui --bless
./x.py test src/test/ui --compare-mode nll
If no arguments are passed then the complete artifacts for that stage are
compiled and tested.
./x.py test
./x.py test --stage 1");
./x.py test --stage 1",
);
}
"doc" => {
subcommand_help.push_str("\n
subcommand_help.push_str(
"\n
Arguments:
This subcommand accepts a number of paths to directories of documentation
to build. For example:
@ -278,12 +315,16 @@ Arguments:
If no arguments are passed then everything is documented:
./x.py doc
./x.py doc --stage 1");
./x.py doc --stage 1",
);
}
_ => { }
_ => {}
};
// Get any optional paths which occur after the subcommand
let paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
let paths = matches.free[1..]
.iter()
.map(|p| p.into())
.collect::<Vec<PathBuf>>();
let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| {
if fs::metadata("config.toml").is_ok() {
@ -302,9 +343,12 @@ Arguments:
let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
} else if subcommand.as_str() != "clean" {
extra_help.push_str(format!(
"Run `./x.py {} -h -v` to see a list of available paths.",
subcommand).as_str());
extra_help.push_str(
format!(
"Run `./x.py {} -h -v` to see a list of available paths.",
subcommand
).as_str(),
);
}
// User passed in -h/--help?
@ -313,36 +357,28 @@ Arguments:
}
let cmd = match subcommand.as_str() {
"build" => {
Subcommand::Build { paths: paths }
}
"check" => {
Subcommand::Check { paths: paths }
}
"test" => {
Subcommand::Test {
paths,
test_args: matches.opt_strs("test-args"),
rustc_args: matches.opt_strs("rustc-args"),
fail_fast: !matches.opt_present("no-fail-fast"),
doc_tests: if matches.opt_present("doc") {
DocTests::Only
} else if matches.opt_present("no-doc") {
DocTests::No
} else {
DocTests::Yes
}
}
}
"bench" => {
Subcommand::Bench {
paths,
test_args: matches.opt_strs("test-args"),
}
}
"doc" => {
Subcommand::Doc { paths: paths }
}
"build" => Subcommand::Build { paths: paths },
"check" => Subcommand::Check { paths: paths },
"test" => Subcommand::Test {
paths,
bless: matches.opt_present("bless"),
compare_mode: matches.opt_str("compare-mode"),
test_args: matches.opt_strs("test-args"),
rustc_args: matches.opt_strs("rustc-args"),
fail_fast: !matches.opt_present("no-fail-fast"),
doc_tests: if matches.opt_present("doc") {
DocTests::Only
} else if matches.opt_present("no-doc") {
DocTests::No
} else {
DocTests::Yes
},
},
"bench" => Subcommand::Bench {
paths,
test_args: matches.opt_strs("test-args"),
},
"doc" => Subcommand::Doc { paths: paths },
"clean" => {
if paths.len() > 0 {
println!("\nclean does not take a path argument\n");
@ -353,22 +389,13 @@ Arguments:
all: matches.opt_present("all"),
}
}
"dist" => {
Subcommand::Dist {
paths,
}
}
"install" => {
Subcommand::Install {
paths,
}
}
"dist" => Subcommand::Dist { paths },
"install" => Subcommand::Install { paths },
_ => {
usage(1, &opts, &subcommand_help, &extra_help);
}
};
Flags {
verbose: matches.opt_count("verbose"),
stage: matches.opt_str("stage").map(|j| j.parse().unwrap()),
@ -377,15 +404,21 @@ Arguments:
rustc_error_format: matches.opt_str("error-format"),
keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()),
host: split(matches.opt_strs("host"))
.into_iter().map(|x| INTERNER.intern_string(x)).collect::<Vec<_>>(),
.into_iter()
.map(|x| INTERNER.intern_string(x))
.collect::<Vec<_>>(),
target: split(matches.opt_strs("target"))
.into_iter().map(|x| INTERNER.intern_string(x)).collect::<Vec<_>>(),
.into_iter()
.map(|x| INTERNER.intern_string(x))
.collect::<Vec<_>>(),
config: cfg_file,
jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()),
cmd,
incremental: matches.opt_present("incremental"),
exclude: split(matches.opt_strs("exclude"))
.into_iter().map(|p| p.into()).collect::<Vec<_>>(),
.into_iter()
.map(|p| p.into())
.collect::<Vec<_>>(),
warnings: matches.opt_str("warnings").map(|v| v == "deny"),
}
}
@ -394,9 +427,11 @@ Arguments:
impl Subcommand {
pub fn test_args(&self) -> Vec<&str> {
match *self {
Subcommand::Test { ref test_args, .. } |
Subcommand::Bench { ref test_args, .. } => {
test_args.iter().flat_map(|s| s.split_whitespace()).collect()
Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
test_args
.iter()
.flat_map(|s| s.split_whitespace())
.collect()
}
_ => Vec::new(),
}
@ -404,9 +439,10 @@ impl Subcommand {
pub fn rustc_args(&self) -> Vec<&str> {
match *self {
Subcommand::Test { ref rustc_args, .. } => {
rustc_args.iter().flat_map(|s| s.split_whitespace()).collect()
}
Subcommand::Test { ref rustc_args, .. } => rustc_args
.iter()
.flat_map(|s| s.split_whitespace())
.collect(),
_ => Vec::new(),
}
}
@ -424,8 +460,27 @@ impl Subcommand {
_ => DocTests::Yes,
}
}
pub fn bless(&self) -> bool {
match *self {
Subcommand::Test { bless, .. } => bless,
_ => false,
}
}
pub fn compare_mode(&self) -> Option<&str> {
match *self {
Subcommand::Test {
ref compare_mode, ..
} => compare_mode.as_ref().map(|s| &s[..]),
_ => None,
}
}
}
fn split(s: Vec<String>) -> Vec<String> {
s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect()
s.iter()
.flat_map(|s| s.split(','))
.map(|s| s.to_string())
.collect()
}

View File

@ -280,7 +280,8 @@ pub struct Build {
struct Crate {
name: Interned<String>,
version: String,
deps: Vec<Interned<String>>,
deps: HashSet<Interned<String>>,
id: String,
path: PathBuf,
doc_step: String,
build_step: String,
@ -307,16 +308,30 @@ impl Crate {
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Mode {
/// Build the standard library, placing output in the "stageN-std" directory.
Libstd,
Std,
/// Build libtest, placing output in the "stageN-test" directory.
Libtest,
Test,
/// Build librustc and compiler libraries, placing output in the "stageN-rustc" directory.
Librustc,
/// Build librustc, and compiler libraries, placing output in the "stageN-rustc" directory.
Rustc,
/// Build some tool, placing output in the "stageN-tools" directory.
Tool,
/// Build codegen libraries, placing output in the "stageN-codegen" directory
Codegen,
/// Build some tools, placing output in the "stageN-tools" directory.
ToolStd,
ToolTest,
ToolRustc,
}
impl Mode {
pub fn is_tool(&self) -> bool {
match self {
Mode::ToolStd | Mode::ToolTest | Mode::ToolRustc => true,
_ => false
}
}
}
impl Build {
@ -517,10 +532,11 @@ impl Build {
/// The mode indicates what the root directory is for.
fn stage_out(&self, compiler: Compiler, mode: Mode) -> PathBuf {
let suffix = match mode {
Mode::Libstd => "-std",
Mode::Libtest => "-test",
Mode::Tool => "-tools",
Mode::Librustc => "-rustc",
Mode::Std => "-std",
Mode::Test => "-test",
Mode::Codegen => "-rustc",
Mode::Rustc => "-rustc",
Mode::ToolStd | Mode::ToolTest | Mode::ToolRustc => "-tools",
};
self.out.join(&*compiler.host)
.join(format!("stage{}{}", compiler.stage, suffix))
@ -592,12 +608,20 @@ impl Build {
Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target))
} else {
let base = self.llvm_out(self.config.build).join("build");
let exe = exe("FileCheck", &*target);
if !self.config.ninja && self.config.build.contains("msvc") {
base.join("Release/bin").join(exe)
let base = if !self.config.ninja && self.config.build.contains("msvc") {
if self.config.llvm_optimize {
if self.config.llvm_release_debuginfo {
base.join("RelWithDebInfo")
} else {
base.join("Release")
}
} else {
base.join("Debug")
}
} else {
base.join("bin").join(exe)
}
base
};
base.join("bin").join(exe("FileCheck", &*target))
}
}

View File

@ -11,6 +11,7 @@
use std::collections::HashMap;
use std::process::Command;
use std::path::PathBuf;
use std::collections::HashSet;
use build_helper::output;
use serde_json;
@ -45,45 +46,17 @@ struct ResolveNode {
}
pub fn build(build: &mut Build) {
build_krate(build, "src/libstd");
build_krate(build, "src/libtest");
build_krate(build, "src/rustc");
}
let mut resolves = Vec::new();
build_krate(&build.std_features(), build, &mut resolves, "src/libstd");
build_krate("", build, &mut resolves, "src/libtest");
build_krate(&build.rustc_features(), build, &mut resolves, "src/rustc");
fn build_krate(build: &mut Build, krate: &str) {
// Run `cargo metadata` to figure out what crates we're testing.
//
// Down below we're going to call `cargo test`, but to test the right set
// of packages we're going to have to know what `-p` arguments to pass it
// to know what crates to test. Here we run `cargo metadata` to learn about
// the dependency graph and what `-p` arguments there are.
let mut cargo = Command::new(&build.initial_cargo);
cargo.arg("metadata")
.arg("--format-version").arg("1")
.arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml"));
let output = output(&mut cargo);
let output: Output = serde_json::from_str(&output).unwrap();
let mut id2name = HashMap::new();
for package in output.packages {
if package.source.is_none() {
let name = INTERNER.intern_string(package.name);
id2name.insert(package.id, name);
let mut path = PathBuf::from(package.manifest_path);
path.pop();
build.crates.insert(name, Crate {
build_step: format!("build-crate-{}", name),
doc_step: format!("doc-crate-{}", name),
test_step: format!("test-crate-{}", name),
bench_step: format!("bench-crate-{}", name),
name,
version: package.version,
deps: Vec::new(),
path,
});
}
for (name, krate) in build.crates.iter() {
id2name.insert(krate.id.clone(), name.clone());
}
for node in output.resolve.nodes {
for node in resolves {
let name = match id2name.get(&node.id) {
Some(name) => name,
None => continue,
@ -95,7 +68,42 @@ fn build_krate(build: &mut Build, krate: &str) {
Some(dep) => dep,
None => continue,
};
krate.deps.push(*dep);
krate.deps.insert(*dep);
}
}
}
fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec<ResolveNode>, krate: &str) {
// Run `cargo metadata` to figure out what crates we're testing.
//
// Down below we're going to call `cargo test`, but to test the right set
// of packages we're going to have to know what `-p` arguments to pass it
// to know what crates to test. Here we run `cargo metadata` to learn about
// the dependency graph and what `-p` arguments there are.
let mut cargo = Command::new(&build.initial_cargo);
cargo.arg("metadata")
.arg("--format-version").arg("1")
.arg("--features").arg(features)
.arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml"));
let output = output(&mut cargo);
let output: Output = serde_json::from_str(&output).unwrap();
for package in output.packages {
if package.source.is_none() {
let name = INTERNER.intern_string(package.name);
let mut path = PathBuf::from(package.manifest_path);
path.pop();
build.crates.insert(name, Crate {
build_step: format!("build-crate-{}", name),
doc_step: format!("doc-crate-{}", name),
test_step: format!("test-crate-{}", name),
bench_step: format!("bench-crate-{}", name),
name,
version: package.version,
id: package.id,
deps: HashSet::new(),
path,
});
}
}
resolves.extend(output.resolve.nodes);
}

View File

@ -275,21 +275,53 @@ fn configure_cmake(builder: &Builder,
return
}
let cc = builder.cc(target);
let cxx = builder.cxx(target).unwrap();
let (cc, cxx) = match builder.config.llvm_clang_cl {
Some(ref cl) => (cl.as_ref(), cl.as_ref()),
None => (builder.cc(target), builder.cxx(target).unwrap()),
};
// Handle msvc + ninja + ccache specially (this is what the bots use)
if target.contains("msvc") &&
builder.config.ninja &&
builder.config.ccache.is_some() {
let mut cc = env::current_exe().expect("failed to get cwd");
cc.set_file_name("sccache-plus-cl.exe");
builder.config.ccache.is_some()
{
let mut wrap_cc = env::current_exe().expect("failed to get cwd");
wrap_cc.set_file_name("sccache-plus-cl.exe");
cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc))
.define("CMAKE_CXX_COMPILER", sanitize_cc(&cc));
cfg.define("CMAKE_C_COMPILER", sanitize_cc(&wrap_cc))
.define("CMAKE_CXX_COMPILER", sanitize_cc(&wrap_cc));
cfg.env("SCCACHE_PATH",
builder.config.ccache.as_ref().unwrap())
.env("SCCACHE_TARGET", target);
.env("SCCACHE_TARGET", target)
.env("SCCACHE_CC", &cc)
.env("SCCACHE_CXX", &cxx);
// Building LLVM on MSVC can be a little ludicrous at times. We're so far
// off the beaten path here that I'm not really sure this is even half
// supported any more. Here we're trying to:
//
// * Build LLVM on MSVC
// * Build LLVM with `clang-cl` instead of `cl.exe`
// * Build a project with `sccache`
// * Build for 32-bit as well
// * Build with Ninja
//
// For `cl.exe` there are different binaries to compile 32/64 bit which
// we use but for `clang-cl` there's only one which internally
// multiplexes via flags. As a result it appears that CMake's detection
// of a compiler's architecture and such on MSVC **doesn't** pass any
// custom flags we pass in CMAKE_CXX_FLAGS below. This means that if we
// use `clang-cl.exe` it's always diagnosed as a 64-bit compiler which
// definitely causes problems since all the env vars are pointing to
// 32-bit libraries.
//
// To hack aroudn this... again... we pass an argument that's
// unconditionally passed in the sccache shim. This'll get CMake to
// correctly diagnose it's doing a 32-bit compilation and LLVM will
// internally configure itself appropriately.
if builder.config.llvm_clang_cl.is_some() && target.contains("i686") {
cfg.env("SCCACHE_EXTRA_ARGS", "-m32");
}
// If ccache is configured we inform the build a little differently hwo
// to invoke ccache while also invoking our compilers.
@ -368,9 +400,27 @@ impl Step for Lld {
let mut cfg = cmake::Config::new(builder.src.join("src/tools/lld"));
configure_cmake(builder, target, &mut cfg, true);
// This is an awful, awful hack. Discovered when we migrated to using
// clang-cl to compile LLVM/LLD it turns out that LLD, when built out of
// tree, will execute `llvm-config --cmakedir` and then tell CMake about
// that directory for later processing. Unfortunately if this path has
// forward slashes in it (which it basically always does on Windows)
// then CMake will hit a syntax error later on as... something isn't
// escaped it seems?
//
// Instead of attempting to fix this problem in upstream CMake and/or
// LLVM/LLD we just hack around it here. This thin wrapper will take the
// output from llvm-config and replace all instances of `\` with `/` to
// ensure we don't hit the same bugs with escaping. It means that you
// can't build on a system where your paths require `\` on Windows, but
// there's probably a lot of reasons you can't do that other than this.
let llvm_config_shim = env::current_exe()
.unwrap()
.with_file_name("llvm-config-wrapper");
cfg.out_dir(&out_dir)
.profile("Release")
.define("LLVM_CONFIG_PATH", llvm_config)
.env("LLVM_CONFIG_REAL", llvm_config)
.define("LLVM_CONFIG_PATH", llvm_config_shim)
.define("LLVM_INCLUDE_TESTS", "OFF");
cfg.build();
@ -546,8 +596,10 @@ impl Step for Openssl {
"arm-linux-androideabi" => "android",
"arm-unknown-linux-gnueabi" => "linux-armv4",
"arm-unknown-linux-gnueabihf" => "linux-armv4",
"armv6-unknown-netbsd-eabihf" => "BSD-generic32",
"armv7-linux-androideabi" => "android-armv7",
"armv7-unknown-linux-gnueabihf" => "linux-armv4",
"armv7-unknown-netbsd-eabihf" => "BSD-generic32",
"i586-unknown-linux-gnu" => "linux-elf",
"i586-unknown-linux-musl" => "linux-elf",
"i686-apple-darwin" => "darwin-i386-cc",

View File

@ -15,25 +15,26 @@
use std::env;
use std::ffi::OsString;
use std::iter;
use std::fmt;
use std::fs::{self, File};
use std::path::{PathBuf, Path};
use std::process::Command;
use std::io::Read;
use std::iter;
use std::path::{Path, PathBuf};
use std::process::Command;
use build_helper::{self, output};
use builder::{Kind, RunConfig, ShouldRun, Builder, Compiler, Step};
use Crate as CargoCrate;
use cache::{INTERNER, Interned};
use builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
use cache::{Interned, INTERNER};
use compile;
use dist;
use flags::Subcommand;
use native;
use tool::{self, Tool};
use util::{self, dylib_path, dylib_path_var};
use {Mode, DocTests};
use toolstate::ToolState;
use util::{self, dylib_path, dylib_path_var};
use Crate as CargoCrate;
use {DocTests, Mode};
const ADB_TEST_DIR: &str = "/data/tmp/work";
@ -46,6 +47,16 @@ pub enum TestKind {
Bench,
}
impl From<Kind> for TestKind {
fn from(kind: Kind) -> Self {
match kind {
Kind::Test => TestKind::Test,
Kind::Bench => TestKind::Bench,
_ => panic!("unexpected kind in crate: {:?}", kind),
}
}
}
impl TestKind {
// Return the cargo subcommand for this test kind
fn subcommand(self) -> &'static str {
@ -113,13 +124,18 @@ impl Step for Linkcheck {
builder.default_doc(None);
let _time = util::timeit(&builder);
try_run(builder, builder.tool_cmd(Tool::Linkchecker)
.arg(builder.out.join(host).join("doc")));
try_run(
builder,
builder
.tool_cmd(Tool::Linkchecker)
.arg(builder.out.join(host).join("doc")),
);
}
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.path("src/tools/linkchecker").default_condition(builder.config.docs)
run.path("src/tools/linkchecker")
.default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
@ -154,7 +170,10 @@ impl Step for Cargotest {
/// test` to ensure that we don't regress the test suites there.
fn run(self, builder: &Builder) {
let compiler = builder.compiler(self.stage, self.host);
builder.ensure(compile::Rustc { compiler, target: compiler.host });
builder.ensure(compile::Rustc {
compiler,
target: compiler.host,
});
// Note that this is a short, cryptic, and not scoped directory name. This
// is currently to minimize the length of path on Windows where we otherwise
@ -164,10 +183,13 @@ impl Step for Cargotest {
let _time = util::timeit(&builder);
let mut cmd = builder.tool_cmd(Tool::CargoTest);
try_run(builder, cmd.arg(&builder.initial_cargo)
.arg(&out_dir)
.env("RUSTC", builder.rustc(compiler))
.env("RUSTDOC", builder.rustdoc(compiler.host)));
try_run(
builder,
cmd.arg(&builder.initial_cargo)
.arg(&out_dir)
.env("RUSTC", builder.rustc(compiler))
.env("RUSTDOC", builder.rustdoc(compiler.host)),
);
}
}
@ -196,9 +218,14 @@ impl Step for Cargo {
fn run(self, builder: &Builder) {
let compiler = builder.compiler(self.stage, self.host);
builder.ensure(tool::Cargo { compiler, target: self.host });
let mut cargo = builder.cargo(compiler, Mode::Tool, self.host, "test");
cargo.arg("--manifest-path").arg(builder.src.join("src/tools/cargo/Cargo.toml"));
builder.ensure(tool::Cargo {
compiler,
target: self.host,
});
let mut cargo = builder.cargo(compiler, Mode::ToolRustc, self.host, "test");
cargo
.arg("--manifest-path")
.arg(builder.src.join("src/tools/cargo/Cargo.toml"));
if !builder.fail_fast {
cargo.arg("--no-fail-fast");
}
@ -210,7 +237,10 @@ impl Step for Cargo {
// available.
cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
try_run(builder, cargo.env("PATH", &path_for_cargo(builder, compiler)));
try_run(
builder,
cargo.env("PATH", &path_for_cargo(builder, compiler)),
);
}
}
@ -253,6 +283,7 @@ impl Step for Rls {
let mut cargo = tool::prepare_tool_cargo(builder,
compiler,
Mode::ToolRustc,
host,
"test",
"src/tools/rls");
@ -307,6 +338,7 @@ impl Step for Rustfmt {
let mut cargo = tool::prepare_tool_cargo(builder,
compiler,
Mode::ToolRustc,
host,
"test",
"src/tools/rustfmt");
@ -360,8 +392,10 @@ impl Step for Miri {
extra_features: Vec::new(),
});
if let Some(miri) = miri {
let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
cargo.arg("--manifest-path").arg(builder.src.join("src/tools/miri/Cargo.toml"));
let mut cargo = builder.cargo(compiler, Mode::ToolRustc, host, "test");
cargo
.arg("--manifest-path")
.arg(builder.src.join("src/tools/miri/Cargo.toml"));
// Don't build tests dynamically, just a pain to work with
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
@ -416,8 +450,10 @@ impl Step for Clippy {
extra_features: Vec::new(),
});
if let Some(clippy) = clippy {
let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
cargo.arg("--manifest-path").arg(builder.src.join("src/tools/clippy/Cargo.toml"));
let mut cargo = builder.cargo(compiler, Mode::ToolRustc, host, "test");
cargo
.arg("--manifest-path")
.arg(builder.src.join("src/tools/clippy/Cargo.toml"));
// Don't build tests dynamically, just a pain to work with
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
@ -425,7 +461,9 @@ impl Step for Clippy {
cargo.env("SYSROOT", builder.sysroot(compiler));
cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
let host_libs = builder.stage_out(compiler, Mode::Tool).join(builder.cargo_dir());
let host_libs = builder
.stage_out(compiler, Mode::ToolRustc)
.join(builder.cargo_dir());
cargo.env("HOST_LIBS", host_libs);
// clippy tests need to find the driver
cargo.env("CLIPPY_DRIVER_PATH", clippy);
@ -467,23 +505,30 @@ impl Step for RustdocTheme {
fn make_run(run: RunConfig) {
let compiler = run.builder.compiler(run.builder.top_stage, run.host);
run.builder.ensure(RustdocTheme {
compiler: compiler,
});
run.builder.ensure(RustdocTheme { compiler: compiler });
}
fn run(self, builder: &Builder) {
let rustdoc = builder.out.join("bootstrap/debug/rustdoc");
let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
cmd.arg(rustdoc.to_str().unwrap())
.arg(builder.src.join("src/librustdoc/html/static/themes").to_str().unwrap())
.env("RUSTC_STAGE", self.compiler.stage.to_string())
.env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
.env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host))
.env("CFG_RELEASE_CHANNEL", &builder.config.channel)
.env("RUSTDOC_REAL", builder.rustdoc(self.compiler.host))
.env("RUSTDOC_CRATE_VERSION", builder.rust_version())
.env("RUSTC_BOOTSTRAP", "1");
.arg(
builder
.src
.join("src/librustdoc/html/static/themes")
.to_str()
.unwrap(),
)
.env("RUSTC_STAGE", self.compiler.stage.to_string())
.env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
.env(
"RUSTDOC_LIBDIR",
builder.sysroot_libdir(self.compiler, self.compiler.host),
)
.env("CFG_RELEASE_CHANNEL", &builder.config.channel)
.env("RUSTDOC_REAL", builder.rustdoc(self.compiler.host))
.env("RUSTDOC_CRATE_VERSION", builder.rust_version())
.env("RUSTC_BOOTSTRAP", "1");
if let Some(linker) = builder.linker(self.compiler.host) {
cmd.env("RUSTC_TARGET_LINKER", linker);
}
@ -523,7 +568,9 @@ impl Step for RustdocJS {
});
builder.run(&mut command);
} else {
builder.info(&format!("No nodejs found, skipping \"src/test/rustdoc-js\" tests"));
builder.info(&format!(
"No nodejs found, skipping \"src/test/rustdoc-js\" tests"
));
}
}
}
@ -559,6 +606,7 @@ impl Step for RustdocUi {
target: self.target,
mode: "ui",
suite: "rustdoc-ui",
path: None,
compare_mode: None,
})
}
@ -584,7 +632,7 @@ impl Step for Tidy {
if !builder.config.vendor {
cmd.arg("--no-vendor");
}
if builder.config.quiet_tests {
if !builder.config.verbose_tests {
cmd.arg("--quiet");
}
@ -663,7 +711,7 @@ macro_rules! test_definitions {
const ONLY_HOSTS: bool = $host;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path($path)
run.suite_path($path)
}
fn make_run(run: RunConfig) {
@ -681,6 +729,7 @@ macro_rules! test_definitions {
target: self.target,
mode: $mode,
suite: $suite,
path: Some($path),
compare_mode: $compare_mode,
})
}
@ -835,7 +884,7 @@ test!(RunFailFullDepsPretty {
host: true
});
host_test!(RunMake {
default_test!(RunMake {
path: "src/test/run-make",
mode: "run-make",
suite: "run-make"
@ -853,6 +902,7 @@ struct Compiletest {
target: Interned<String>,
mode: &'static str,
suite: &'static str,
path: Option<&'static str>,
compare_mode: Option<&'static str>,
}
@ -873,7 +923,9 @@ impl Step for Compiletest {
let target = self.target;
let mode = self.mode;
let suite = self.suite;
let compare_mode = self.compare_mode;
// Path for test suite
let suite_path = self.path.unwrap_or("");
// Skip codegen tests if they aren't enabled in configuration.
if !builder.config.codegen_tests && suite == "codegen" {
@ -902,15 +954,15 @@ impl Step for Compiletest {
builder.ensure(dist::DebuggerScripts {
sysroot: builder.sysroot(compiler),
host: target
host: target,
});
}
if suite.ends_with("fulldeps") ||
// FIXME: Does pretty need librustc compiled? Note that there are
// fulldeps test suites with mode = pretty as well.
mode == "pretty" ||
mode == "rustdoc" {
mode == "pretty"
{
builder.ensure(compile::Rustc { compiler, target });
}
@ -923,26 +975,40 @@ impl Step for Compiletest {
// compiletest currently has... a lot of arguments, so let's just pass all
// of them!
cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(compiler));
cmd.arg("--run-lib-path").arg(builder.sysroot_libdir(compiler, target));
cmd.arg("--compile-lib-path")
.arg(builder.rustc_libdir(compiler));
cmd.arg("--run-lib-path")
.arg(builder.sysroot_libdir(compiler, target));
cmd.arg("--rustc-path").arg(builder.rustc(compiler));
let is_rustdoc_ui = suite.ends_with("rustdoc-ui");
// Avoid depending on rustdoc when we don't need it.
if mode == "rustdoc" ||
(mode == "run-make" && suite.ends_with("fulldeps")) ||
(mode == "ui" && is_rustdoc_ui) {
cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host));
if mode == "rustdoc"
|| (mode == "run-make" && suite.ends_with("fulldeps"))
|| (mode == "ui" && is_rustdoc_ui)
{
cmd.arg("--rustdoc-path")
.arg(builder.rustdoc(compiler.host));
}
cmd.arg("--src-base").arg(builder.src.join("src/test").join(suite));
cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite));
cmd.arg("--stage-id").arg(format!("stage{}-{}", compiler.stage, target));
cmd.arg("--src-base")
.arg(builder.src.join("src/test").join(suite));
cmd.arg("--build-base")
.arg(testdir(builder, compiler.host).join(suite));
cmd.arg("--stage-id")
.arg(format!("stage{}-{}", compiler.stage, target));
cmd.arg("--mode").arg(mode);
cmd.arg("--target").arg(target);
cmd.arg("--host").arg(&*compiler.host);
cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
cmd.arg("--llvm-filecheck")
.arg(builder.llvm_filecheck(builder.config.build));
if builder.config.cmd.bless() {
cmd.arg("--bless");
}
let compare_mode = builder.config.cmd.compare_mode().or(self.compare_mode);
if let Some(ref nodejs) = builder.config.nodejs {
cmd.arg("--nodejs").arg(nodejs);
@ -972,8 +1038,10 @@ impl Step for Compiletest {
cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
let mut targetflags = flags.clone();
targetflags.push(format!("-Lnative={}",
builder.test_helpers_out(target).display()));
targetflags.push(format!(
"-Lnative={}",
builder.test_helpers_out(target).display()
));
cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
cmd.arg("--docck-python").arg(builder.python());
@ -997,13 +1065,28 @@ impl Step for Compiletest {
cmd.arg("--lldb-python-dir").arg(dir);
}
cmd.args(&builder.config.cmd.test_args());
// Get paths from cmd args
let paths = match &builder.config.cmd {
Subcommand::Test { ref paths, .. } => &paths[..],
_ => &[],
};
// Get test-args by striping suite path
let mut test_args: Vec<&str> = paths
.iter()
.filter(|p| p.starts_with(suite_path) && p.is_file())
.map(|p| p.strip_prefix(suite_path).unwrap().to_str().unwrap())
.collect();
test_args.append(&mut builder.config.cmd.test_args());
cmd.args(&test_args);
if builder.is_verbose() {
cmd.arg("--verbose");
}
if builder.config.quiet_tests {
if !builder.config.verbose_tests {
cmd.arg("--quiet");
}
@ -1022,35 +1105,47 @@ impl Step for Compiletest {
// Only pass correct values for these flags for the `run-make` suite as it
// requires that a C++ compiler was configured which isn't always the case.
if !builder.config.dry_run && mode == "run-make" {
if !builder.config.dry_run && suite == "run-make-fulldeps" {
let llvm_components = output(Command::new(&llvm_config).arg("--components"));
let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
cmd.arg("--cc").arg(builder.cc(target))
.arg("--cxx").arg(builder.cxx(target).unwrap())
.arg("--cflags").arg(builder.cflags(target).join(" "))
.arg("--llvm-components").arg(llvm_components.trim())
.arg("--llvm-cxxflags").arg(llvm_cxxflags.trim());
cmd.arg("--cc")
.arg(builder.cc(target))
.arg("--cxx")
.arg(builder.cxx(target).unwrap())
.arg("--cflags")
.arg(builder.cflags(target).join(" "))
.arg("--llvm-components")
.arg(llvm_components.trim())
.arg("--llvm-cxxflags")
.arg(llvm_cxxflags.trim());
if let Some(ar) = builder.ar(target) {
cmd.arg("--ar").arg(ar);
}
}
}
if mode == "run-make" && !builder.config.llvm_enabled {
builder.info(
&format!("Ignoring run-make test suite as they generally don't work without LLVM"));
if suite == "run-make-fulldeps" && !builder.config.llvm_enabled {
builder.info(&format!(
"Ignoring run-make test suite as they generally don't work without LLVM"
));
return;
}
if mode != "run-make" {
cmd.arg("--cc").arg("")
.arg("--cxx").arg("")
.arg("--cflags").arg("")
.arg("--llvm-components").arg("")
.arg("--llvm-cxxflags").arg("");
if suite != "run-make-fulldeps" {
cmd.arg("--cc")
.arg("")
.arg("--cxx")
.arg("")
.arg("--cflags")
.arg("")
.arg("--llvm-components")
.arg("")
.arg("--llvm-cxxflags")
.arg("");
}
if builder.remote_tested(target) {
cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
cmd.arg("--remote-test-client")
.arg(builder.tool_exe(Tool::RemoteTestClient));
}
// Running a C compiler on MSVC requires a few env vars to be set, to be
@ -1083,7 +1178,7 @@ impl Step for Compiletest {
if target.contains("android") {
// Assume that cc for this target comes from the android sysroot
cmd.arg("--android-cross-path")
.arg(builder.cc(target).parent().unwrap().parent().unwrap());
.arg(builder.cc(target).parent().unwrap().parent().unwrap());
} else {
cmd.arg("--android-cross-path").arg("");
}
@ -1091,16 +1186,20 @@ impl Step for Compiletest {
builder.ci_env.force_coloring_in_ci(&mut cmd);
let _folder = builder.fold_output(|| format!("test_{}", suite));
builder.info(&format!("Check compiletest suite={} mode={} ({} -> {})",
suite, mode, &compiler.host, target));
builder.info(&format!(
"Check compiletest suite={} mode={} ({} -> {})",
suite, mode, &compiler.host, target
));
let _time = util::timeit(&builder);
try_run(builder, &mut cmd);
if let Some(compare_mode) = compare_mode {
cmd.arg("--compare-mode").arg(compare_mode);
let _folder = builder.fold_output(|| format!("test_{}_{}", suite, compare_mode));
builder.info(&format!("Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
suite, mode, compare_mode, &compiler.host, target));
builder.info(&format!(
"Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
suite, mode, compare_mode, &compiler.host, target
));
let _time = util::timeit(&builder);
try_run(builder, &mut cmd);
}
@ -1131,7 +1230,10 @@ impl Step for DocTest {
fn run(self, builder: &Builder) {
let compiler = self.compiler;
builder.ensure(compile::Test { compiler, target: compiler.host });
builder.ensure(compile::Test {
compiler,
target: compiler.host,
});
// Do a breadth-first traversal of the `src/doc` directory and just run
// tests for all files that end in `*.md`
@ -1143,7 +1245,7 @@ impl Step for DocTest {
while let Some(p) = stack.pop() {
if p.is_dir() {
stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
continue
continue;
}
if p.extension().and_then(|s| s.to_str()) != Some("md") {
@ -1250,7 +1352,10 @@ impl Step for ErrorIndex {
fn run(self, builder: &Builder) {
let compiler = self.compiler;
builder.ensure(compile::Std { compiler, target: compiler.host });
builder.ensure(compile::Std {
compiler,
target: compiler.host,
});
let dir = testdir(builder, compiler.host);
t!(fs::create_dir_all(&dir));
@ -1262,7 +1367,6 @@ impl Step for ErrorIndex {
.env("CFG_BUILD", &builder.config.build)
.env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir());
let _folder = builder.fold_output(|| "test_error_index");
builder.info(&format!("Testing error-index stage{}", compiler.stage));
let _time = util::timeit(&builder);
@ -1280,7 +1384,7 @@ fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool
return true;
}
}
Err(_) => {},
Err(_) => {}
}
builder.info(&format!("doc tests for: {}", markdown.display()));
@ -1293,10 +1397,10 @@ fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool
let test_args = builder.config.cmd.test_args().join(" ");
cmd.arg("--test-args").arg(test_args);
if builder.config.quiet_tests {
try_run_quiet(builder, &mut cmd)
} else {
if builder.config.verbose_tests {
try_run(builder, &mut cmd)
} else {
try_run_quiet(builder, &mut cmd)
}
}
@ -1323,13 +1427,7 @@ impl Step for CrateLibrustc {
for krate in builder.in_tree_crates("rustc-main") {
if run.path.ends_with(&krate.path) {
let test_kind = if builder.kind == Kind::Test {
TestKind::Test
} else if builder.kind == Kind::Bench {
TestKind::Bench
} else {
panic!("unexpected builder.kind in crate: {:?}", builder.kind);
};
let test_kind = builder.kind.into();
builder.ensure(CrateLibrustc {
compiler,
@ -1345,7 +1443,7 @@ impl Step for CrateLibrustc {
builder.ensure(Crate {
compiler: self.compiler,
target: self.target,
mode: Mode::Librustc,
mode: Mode::Rustc,
test_kind: self.test_kind,
krate: self.krate,
});
@ -1375,13 +1473,7 @@ impl Step for CrateNotDefault {
let builder = run.builder;
let compiler = builder.compiler(builder.top_stage, run.host);
let test_kind = if builder.kind == Kind::Test {
TestKind::Test
} else if builder.kind == Kind::Bench {
TestKind::Bench
} else {
panic!("unexpected builder.kind in crate: {:?}", builder.kind);
};
let test_kind = builder.kind.into();
builder.ensure(CrateNotDefault {
compiler,
@ -1402,14 +1494,13 @@ impl Step for CrateNotDefault {
builder.ensure(Crate {
compiler: self.compiler,
target: self.target,
mode: Mode::Libstd,
mode: Mode::Std,
test_kind: self.test_kind,
krate: INTERNER.intern_str(self.krate),
});
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Crate {
pub compiler: Compiler,
@ -1427,10 +1518,11 @@ impl Step for Crate {
let builder = run.builder;
run = run.krate("test");
for krate in run.builder.in_tree_crates("std") {
if krate.is_local(&run.builder) &&
!krate.name.contains("jemalloc") &&
!(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) &&
krate.name != "dlmalloc" {
if krate.is_local(&run.builder)
&& !krate.name.contains("jemalloc")
&& !(krate.name.starts_with("rustc_") && krate.name.ends_with("san"))
&& krate.name != "dlmalloc"
{
run = run.path(krate.local_path(&builder).to_str().unwrap());
}
}
@ -1442,13 +1534,7 @@ impl Step for Crate {
let compiler = builder.compiler(builder.top_stage, run.host);
let make = |mode: Mode, krate: &CargoCrate| {
let test_kind = if builder.kind == Kind::Test {
TestKind::Test
} else if builder.kind == Kind::Bench {
TestKind::Bench
} else {
panic!("unexpected builder.kind in crate: {:?}", builder.kind);
};
let test_kind = builder.kind.into();
builder.ensure(Crate {
compiler,
@ -1461,12 +1547,12 @@ impl Step for Crate {
for krate in builder.in_tree_crates("std") {
if run.path.ends_with(&krate.local_path(&builder)) {
make(Mode::Libstd, krate);
make(Mode::Std, krate);
}
}
for krate in builder.in_tree_crates("test") {
if run.path.ends_with(&krate.local_path(&builder)) {
make(Mode::Libtest, krate);
make(Mode::Test, krate);
}
}
}
@ -1501,13 +1587,13 @@ impl Step for Crate {
let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand());
match mode {
Mode::Libstd => {
Mode::Std => {
compile::std_cargo(builder, &compiler, target, &mut cargo);
}
Mode::Libtest => {
Mode::Test => {
compile::test_cargo(builder, &compiler, target, &mut cargo);
}
Mode::Librustc => {
Mode::Rustc => {
builder.ensure(compile::Rustc { compiler, target });
compile::rustc_cargo(builder, &mut cargo);
}
@ -1546,43 +1632,64 @@ impl Step for Crate {
cargo.arg("--");
cargo.args(&builder.config.cmd.test_args());
if builder.config.quiet_tests {
if !builder.config.verbose_tests {
cargo.arg("--quiet");
}
if target.contains("emscripten") {
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
builder.config.nodejs.as_ref().expect("nodejs not configured"));
cargo.env(
format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
builder
.config
.nodejs
.as_ref()
.expect("nodejs not configured"),
);
} else if target.starts_with("wasm32") {
// Warn about running tests without the `wasm_syscall` feature enabled.
// The javascript shim implements the syscall interface so that test
// output can be correctly reported.
if !builder.config.wasm_syscall {
builder.info(&format!("Libstd was built without `wasm_syscall` feature enabled: \
test output may not be visible."));
builder.info(&format!(
"Libstd was built without `wasm_syscall` feature enabled: \
test output may not be visible."
));
}
// On the wasm32-unknown-unknown target we're using LTO which is
// incompatible with `-C prefer-dynamic`, so disable that here
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
let node = builder.config.nodejs.as_ref()
let node = builder
.config
.nodejs
.as_ref()
.expect("nodejs not configured");
let runner = format!("{} {}/src/etc/wasm32-shim.js",
node.display(),
builder.src.display());
let runner = format!(
"{} {}/src/etc/wasm32-shim.js",
node.display(),
builder.src.display()
);
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner);
} else if builder.remote_tested(target) {
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
format!("{} run",
builder.tool_exe(Tool::RemoteTestClient).display()));
cargo.env(
format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
format!("{} run", builder.tool_exe(Tool::RemoteTestClient).display()),
);
}
let _folder = builder.fold_output(|| {
format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate)
format!(
"{}_stage{}-{}",
test_kind.subcommand(),
compiler.stage,
krate
)
});
builder.info(&format!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage,
&compiler.host, target));
builder.info(&format!(
"{} {} stage{} ({} -> {})",
test_kind, krate, compiler.stage, &compiler.host, target
));
let _time = util::timeit(&builder);
try_run(builder, &mut cargo);
}
@ -1606,13 +1713,7 @@ impl Step for CrateRustdoc {
fn make_run(run: RunConfig) {
let builder = run.builder;
let test_kind = if builder.kind == Kind::Test {
TestKind::Test
} else if builder.kind == Kind::Bench {
TestKind::Bench
} else {
panic!("unexpected builder.kind in crate: {:?}", builder.kind);
};
let test_kind = builder.kind.into();
builder.ensure(CrateRustdoc {
host: run.host,
@ -1628,6 +1729,7 @@ impl Step for CrateRustdoc {
let mut cargo = tool::prepare_tool_cargo(builder,
compiler,
Mode::ToolRustc,
target,
test_kind.subcommand(),
"src/tools/rustdoc");
@ -1640,15 +1742,16 @@ impl Step for CrateRustdoc {
cargo.arg("--");
cargo.args(&builder.config.cmd.test_args());
if builder.config.quiet_tests {
if !builder.config.verbose_tests {
cargo.arg("--quiet");
}
let _folder = builder.fold_output(|| {
format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage)
});
builder.info(&format!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage,
&compiler.host, target));
let _folder = builder
.fold_output(|| format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage));
builder.info(&format!(
"{} rustdoc stage{} ({} -> {})",
test_kind, compiler.stage, &compiler.host, target
));
let _time = util::timeit(&builder);
try_run(builder, &mut cargo);
@ -1656,12 +1759,13 @@ impl Step for CrateRustdoc {
}
fn envify(s: &str) -> String {
s.chars().map(|c| {
match c {
s.chars()
.map(|c| match c {
'-' => '_',
c => c,
}
}).flat_map(|c| c.to_uppercase()).collect()
})
.flat_map(|c| c.to_uppercase())
.collect()
}
/// Some test suites are run inside emulators or on remote devices, and most
@ -1690,7 +1794,7 @@ impl Step for RemoteCopyLibs {
let compiler = self.compiler;
let target = self.target;
if !builder.remote_tested(target) {
return
return;
}
builder.ensure(compile::Test { compiler, target });
@ -1704,9 +1808,9 @@ impl Step for RemoteCopyLibs {
let tool = builder.tool_exe(Tool::RemoteTestClient);
let mut cmd = Command::new(&tool);
cmd.arg("spawn-emulator")
.arg(target)
.arg(&server)
.arg(builder.out.join("tmp"));
.arg(target)
.arg(&server)
.arg(builder.out.join("tmp"));
if let Some(rootfs) = builder.qemu_rootfs(target) {
cmd.arg(rootfs);
}
@ -1717,9 +1821,7 @@ impl Step for RemoteCopyLibs {
let f = t!(f);
let name = f.file_name().into_string().unwrap();
if util::is_dylib(&name) {
builder.run(Command::new(&tool)
.arg("push")
.arg(f.path()));
builder.run(Command::new(&tool).arg("push").arg(f.path()));
}
}
}
@ -1752,17 +1854,21 @@ impl Step for Distcheck {
let mut cmd = Command::new("tar");
cmd.arg("-xzf")
.arg(builder.ensure(dist::PlainSourceTarball))
.arg("--strip-components=1")
.current_dir(&dir);
.arg(builder.ensure(dist::PlainSourceTarball))
.arg("--strip-components=1")
.current_dir(&dir);
builder.run(&mut cmd);
builder.run(Command::new("./configure")
.args(&builder.config.configure_args)
.arg("--enable-vendor")
.current_dir(&dir));
builder.run(Command::new(build_helper::make(&builder.config.build))
.arg("check")
.current_dir(&dir));
builder.run(
Command::new("./configure")
.args(&builder.config.configure_args)
.arg("--enable-vendor")
.current_dir(&dir),
);
builder.run(
Command::new(build_helper::make(&builder.config.build))
.arg("check")
.current_dir(&dir),
);
// Now make sure that rust-src has all of libstd's dependencies
builder.info(&format!("Distcheck rust-src"));
@ -1772,17 +1878,19 @@ impl Step for Distcheck {
let mut cmd = Command::new("tar");
cmd.arg("-xzf")
.arg(builder.ensure(dist::Src))
.arg("--strip-components=1")
.current_dir(&dir);
.arg(builder.ensure(dist::Src))
.arg("--strip-components=1")
.current_dir(&dir);
builder.run(&mut cmd);
let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml");
builder.run(Command::new(&builder.initial_cargo)
.arg("generate-lockfile")
.arg("--manifest-path")
.arg(&toml)
.current_dir(&dir));
builder.run(
Command::new(&builder.initial_cargo)
.arg("generate-lockfile")
.arg("--manifest-path")
.arg(&toml)
.current_dir(&dir),
);
}
}
@ -1798,11 +1906,11 @@ impl Step for Bootstrap {
fn run(self, builder: &Builder) {
let mut cmd = Command::new(&builder.initial_cargo);
cmd.arg("test")
.current_dir(builder.src.join("src/bootstrap"))
.env("RUSTFLAGS", "-Cdebuginfo=2")
.env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
.env("RUSTC_BOOTSTRAP", "1")
.env("RUSTC", &builder.initial_rustc);
.current_dir(builder.src.join("src/bootstrap"))
.env("RUSTFLAGS", "-Cdebuginfo=2")
.env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
.env("RUSTC_BOOTSTRAP", "1")
.env("RUSTC", &builder.initial_rustc);
if let Some(flags) = option_env!("RUSTFLAGS") {
// Use the same rustc flags for testing as for "normal" compilation,
// so that Cargo doesnt recompile the entire dependency graph every time:
@ -1813,6 +1921,9 @@ impl Step for Bootstrap {
cmd.arg("--no-fail-fast");
}
cmd.arg("--").args(&builder.config.cmd.test_args());
// rustbuild tests are racy on directory creation so just run them one at a time.
// Since there's not many this shouldn't be a problem.
cmd.arg("--test-threads=1");
try_run(builder, &mut cmd);
}

View File

@ -28,7 +28,7 @@ use toolstate::ToolState;
pub struct CleanTools {
pub compiler: Compiler,
pub target: Interned<String>,
pub mode: Mode,
pub cause: Mode,
}
impl Step for CleanTools {
@ -41,23 +41,23 @@ impl Step for CleanTools {
fn run(self, builder: &Builder) {
let compiler = self.compiler;
let target = self.target;
let mode = self.mode;
let cause = self.cause;
// This is for the original compiler, but if we're forced to use stage 1, then
// std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since
// we copy the libs forward.
let tools_dir = builder.stage_out(compiler, Mode::Tool);
let tools_dir = builder.stage_out(compiler, Mode::ToolRustc);
let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
compiler
};
for &cur_mode in &[Mode::Libstd, Mode::Libtest, Mode::Librustc] {
for &cur_mode in &[Mode::Std, Mode::Test, Mode::Rustc] {
let stamp = match cur_mode {
Mode::Libstd => libstd_stamp(builder, compiler, target),
Mode::Libtest => libtest_stamp(builder, compiler, target),
Mode::Librustc => librustc_stamp(builder, compiler, target),
Mode::Std => libstd_stamp(builder, compiler, target),
Mode::Test => libtest_stamp(builder, compiler, target),
Mode::Rustc => librustc_stamp(builder, compiler, target),
_ => panic!(),
};
@ -67,7 +67,7 @@ impl Step for CleanTools {
// If we are a rustc tool, and std changed, we also need to clear ourselves out -- our
// dependencies depend on std. Therefore, we iterate up until our own mode.
if mode == cur_mode {
if cause == cur_mode {
break;
}
}
@ -104,13 +104,13 @@ impl Step for ToolBuild {
let is_ext_tool = self.is_ext_tool;
match self.mode {
Mode::Libstd => builder.ensure(compile::Std { compiler, target }),
Mode::Libtest => builder.ensure(compile::Test { compiler, target }),
Mode::Librustc => builder.ensure(compile::Rustc { compiler, target }),
Mode::Tool => panic!("unexpected Mode::Tool for tool build")
Mode::ToolStd => builder.ensure(compile::Std { compiler, target }),
Mode::ToolTest => builder.ensure(compile::Test { compiler, target }),
Mode::ToolRustc => builder.ensure(compile::Rustc { compiler, target }),
_ => panic!("unexpected Mode for tool build")
}
let mut cargo = prepare_tool_cargo(builder, compiler, target, "build", path);
let mut cargo = prepare_tool_cargo(builder, compiler, self.mode, target, "build", path);
cargo.arg("--features").arg(self.extra_features.join(" "));
let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
@ -202,7 +202,7 @@ impl Step for ToolBuild {
return None;
}
} else {
let cargo_out = builder.cargo_out(compiler, Mode::Tool, target)
let cargo_out = builder.cargo_out(compiler, self.mode, target)
.join(exe(tool, &compiler.host));
let bin = builder.tools_dir(compiler).join(exe(tool, &compiler.host));
builder.copy(&cargo_out, &bin);
@ -214,11 +214,12 @@ impl Step for ToolBuild {
pub fn prepare_tool_cargo(
builder: &Builder,
compiler: Compiler,
mode: Mode,
target: Interned<String>,
command: &'static str,
path: &'static str,
) -> Command {
let mut cargo = builder.cargo(compiler, Mode::Tool, target, command);
let mut cargo = builder.cargo(compiler, mode, target, command);
let dir = builder.src.join(path);
cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
@ -253,7 +254,7 @@ pub fn prepare_tool_cargo(
}
macro_rules! tool {
($($name:ident, $path:expr, $tool_name:expr, $mode:expr;)+) => {
($($name:ident, $path:expr, $tool_name:expr, $mode:expr $(,llvm_tools = $llvm:expr)*;)+) => {
#[derive(Copy, Clone)]
pub enum Tool {
$(
@ -261,6 +262,22 @@ macro_rules! tool {
)+
}
impl Tool {
pub fn get_mode(&self) -> Mode {
let mode = match self {
$(Tool::$name => $mode,)+
};
mode
}
/// Whether this tool requires LLVM to run
pub fn uses_llvm_tools(&self) -> bool {
match self {
$(Tool::$name => false $(|| $llvm)*,)+
}
}
}
impl<'a> Builder<'a> {
pub fn tool_exe(&self, tool: Tool) -> PathBuf {
let stage = self.tool_default_stage(tool);
@ -324,17 +341,17 @@ macro_rules! tool {
}
tool!(
Rustbook, "src/tools/rustbook", "rustbook", Mode::Librustc;
ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::Librustc;
UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::Libstd;
Tidy, "src/tools/tidy", "tidy", Mode::Libstd;
Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::Libstd;
CargoTest, "src/tools/cargotest", "cargotest", Mode::Libstd;
Compiletest, "src/tools/compiletest", "compiletest", Mode::Libtest;
BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::Libstd;
RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::Libstd;
RustInstaller, "src/tools/rust-installer", "fabricate", Mode::Libstd;
RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes", Mode::Libstd;
Rustbook, "src/tools/rustbook", "rustbook", Mode::ToolRustc;
ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::ToolRustc;
UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::ToolStd;
Tidy, "src/tools/tidy", "tidy", Mode::ToolStd;
Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::ToolStd;
CargoTest, "src/tools/cargotest", "cargotest", Mode::ToolStd;
Compiletest, "src/tools/compiletest", "compiletest", Mode::ToolTest, llvm_tools = true;
BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::ToolStd;
RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::ToolStd;
RustInstaller, "src/tools/rust-installer", "fabricate", Mode::ToolStd;
RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes", Mode::ToolStd;
);
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
@ -362,7 +379,7 @@ impl Step for RemoteTestServer {
compiler: self.compiler,
target: self.target,
tool: "remote-test-server",
mode: Mode::Libstd,
mode: Mode::ToolStd,
path: "src/tools/remote-test-server",
is_ext_tool: false,
extra_features: Vec::new(),
@ -414,6 +431,7 @@ impl Step for Rustdoc {
let mut cargo = prepare_tool_cargo(builder,
build_compiler,
Mode::ToolRustc,
target,
"build",
"src/tools/rustdoc");
@ -430,8 +448,8 @@ impl Step for Rustdoc {
// Cargo adds a number of paths to the dylib search path on windows, which results in
// the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
// rustdoc a different name.
let tool_rustdoc = builder.cargo_out(build_compiler, Mode::Tool, target)
.join(exe("rustdoc-tool-binary", &target_compiler.host));
let tool_rustdoc = builder.cargo_out(build_compiler, Mode::ToolRustc, target)
.join(exe("rustdoc_tool_binary", &target_compiler.host));
// don't create a stage0-sysroot/bin directory.
if target_compiler.stage > 0 {
@ -485,7 +503,7 @@ impl Step for Cargo {
compiler: self.compiler,
target: self.target,
tool: "cargo",
mode: Mode::Librustc,
mode: Mode::ToolRustc,
path: "src/tools/cargo",
is_ext_tool: false,
extra_features: Vec::new(),
@ -533,7 +551,7 @@ macro_rules! tool_extended {
compiler: $sel.compiler,
target: $sel.target,
tool: $tool_name,
mode: Mode::Librustc,
mode: Mode::ToolRustc,
path: $path,
extra_features: $sel.extra_features,
is_ext_tool: true,
@ -575,7 +593,7 @@ impl<'a> Builder<'a> {
pub fn tool_cmd(&self, tool: Tool) -> Command {
let mut cmd = Command::new(self.tool_exe(tool));
let compiler = self.compiler(self.tool_default_stage(tool), self.config.build);
self.prepare_tool_cmd(compiler, &mut cmd);
self.prepare_tool_cmd(compiler, tool, &mut cmd);
cmd
}
@ -583,11 +601,11 @@ impl<'a> Builder<'a> {
///
/// Notably this munges the dynamic library lookup path to point to the
/// right location to run `compiler`.
fn prepare_tool_cmd(&self, compiler: Compiler, cmd: &mut Command) {
fn prepare_tool_cmd(&self, compiler: Compiler, tool: Tool, cmd: &mut Command) {
let host = &compiler.host;
let mut lib_paths: Vec<PathBuf> = vec![
PathBuf::from(&self.sysroot_libdir(compiler, compiler.host)),
self.cargo_out(compiler, Mode::Tool, *host).join("deps"),
self.cargo_out(compiler, tool.get_mode(), *host).join("deps"),
];
// On MSVC a tool may invoke a C compiler (e.g. compiletest in run-make
@ -610,17 +628,19 @@ impl<'a> Builder<'a> {
// Add the llvm/bin directory to PATH since it contains lots of
// useful, platform-independent tools
if let Some(llvm_bin_path) = self.llvm_bin_path() {
if host.contains("windows") {
// On Windows, PATH and the dynamic library path are the same,
// so we just add the LLVM bin path to lib_path
lib_paths.push(llvm_bin_path);
} else {
let old_path = env::var_os("PATH").unwrap_or_default();
let new_path = env::join_paths(iter::once(llvm_bin_path)
.chain(env::split_paths(&old_path)))
.expect("Could not add LLVM bin path to PATH");
cmd.env("PATH", new_path);
if tool.uses_llvm_tools() {
if let Some(llvm_bin_path) = self.llvm_bin_path() {
if host.contains("windows") {
// On Windows, PATH and the dynamic library path are the same,
// so we just add the LLVM bin path to lib_path
lib_paths.push(llvm_bin_path);
} else {
let old_path = env::var_os("PATH").unwrap_or_default();
let new_path = env::join_paths(iter::once(llvm_bin_path)
.chain(env::split_paths(&old_path)))
.expect("Could not add LLVM bin path to PATH");
cmd.env("PATH", new_path);
}
}
}

View File

@ -0,0 +1,36 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
sudo \
xz-utils \
bzip2 \
libssl-dev \
pkg-config
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
ENV BASE_URL=https://releases.linaro.org/components/toolchain/binaries/latest/armeb-eabi/
ENV GCC_LINARO=gcc-linaro-7.2.1-2017.11-x86_64_armeb-eabi
RUN curl -sL $BASE_URL/$GCC_LINARO.tar.xz | tar -xJ
ENV PATH=$PATH:/$GCC_LINARO/bin
ENV TARGET=armebv7r-none-eabihf
ENV CC_armebv7r_none_eabihf=armeb-eabi-gcc \
CFLAGS_armebv7r_none_eabihf="-march=armv7-r"
ENV RUST_CONFIGURE_ARGS --disable-docs
ENV SCRIPT python2.7 ../x.py dist --target $TARGET

View File

@ -0,0 +1,26 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
make \
file \
curl \
ca-certificates \
python2.7 \
git \
cmake \
sudo \
gdb \
xz-utils \
g++-sparc64-linux-gnu \
libssl-dev \
pkg-config
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
ENV HOSTS=sparc64-unknown-linux-gnu
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS

View File

@ -29,13 +29,13 @@ ENV PATH=/rustroot/bin:$PATH
ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib
ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
WORKDIR /tmp
COPY dist-i686-linux/shared.sh dist-i686-linux/build-binutils.sh /tmp/
COPY dist-x86_64-linux/shared.sh /tmp/
# We need a build of openssl which supports SNI to download artifacts from
# static.rust-lang.org. This'll be used to link into libcurl below (and used
# later as well), so build a copy of OpenSSL with dynamic libraries into our
# generic root.
COPY dist-i686-linux/build-openssl.sh /tmp/
COPY dist-x86_64-linux/build-openssl.sh /tmp/
RUN ./build-openssl.sh
# The `curl` binary on CentOS doesn't support SNI which is needed for fetching
@ -44,36 +44,43 @@ RUN ./build-openssl.sh
#
# Note that we also disable a bunch of optional features of curl that we don't
# really need.
COPY dist-i686-linux/build-curl.sh /tmp/
COPY dist-x86_64-linux/build-curl.sh /tmp/
RUN ./build-curl.sh
# binutils < 2.22 has a bug where the 32-bit executables it generates
# immediately segfault in Rust, so we need to install our own binutils.
#
# See https://github.com/rust-lang/rust/issues/20440 for more info
COPY dist-x86_64-linux/build-binutils.sh /tmp/
RUN ./build-binutils.sh
# Need a newer version of gcc than centos has to compile LLVM nowadays
COPY dist-i686-linux/build-gcc.sh /tmp/
RUN ./build-gcc.sh
# CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+
COPY dist-i686-linux/build-python.sh /tmp/
RUN ./build-python.sh
# Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for
# cloning, so download and build it here.
COPY dist-i686-linux/build-git.sh /tmp/
RUN ./build-git.sh
# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS
# only has 2.6.4, so build our own
COPY dist-i686-linux/build-cmake.sh /tmp/
COPY dist-x86_64-linux/build-cmake.sh /tmp/
RUN ./build-cmake.sh
# Need a newer version of gcc than centos has to compile LLVM nowadays
COPY dist-x86_64-linux/build-gcc.sh /tmp/
RUN ./build-gcc.sh
# CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+
COPY dist-x86_64-linux/build-python.sh /tmp/
RUN ./build-python.sh
# Now build LLVM+Clang 6, afterwards configuring further compilations to use the
# clang/clang++ compilers.
COPY dist-x86_64-linux/build-clang.sh /tmp/
RUN ./build-clang.sh
ENV CC=clang CXX=clang++
# Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for
# cloning, so download and build it here.
COPY dist-x86_64-linux/build-git.sh /tmp/
RUN ./build-git.sh
# for sanitizers, we need kernel headers files newer than the ones CentOS ships
# with so we install newer ones here
COPY dist-i686-linux/build-headers.sh /tmp/
COPY dist-x86_64-linux/build-headers.sh /tmp/
RUN ./build-headers.sh
COPY scripts/sccache.sh /scripts/
@ -84,11 +91,21 @@ ENV HOSTS=i686-unknown-linux-gnu
ENV RUST_CONFIGURE_ARGS \
--enable-full-tools \
--enable-sanitizers \
--enable-profiler
--enable-profiler \
--set target.i686-unknown-linux-gnu.linker=clang \
--build=i686-unknown-linux-gnu
ENV SCRIPT python2.7 ../x.py dist --build $HOSTS --host $HOSTS --target $HOSTS
ENV CARGO_TARGET_I686_UNKNOWN_LINUX_GNU_LINKER=clang
# This is the only builder which will create source tarballs
ENV DIST_SRC 1
# This was added when we switched from gcc to clang. It's not clear why this is
# needed unfortunately, but without this the stage1 bootstrap segfaults
# somewhere inside of a build script. The build ends up just hanging instead of
# actually killing the process that segfaulted, but if the process is run
# manually in a debugger the segfault is immediately seen as well as the
# misaligned stack access.
#
# Added in #50200 there's some more logs there
ENV CFLAGS -mstackrealign
# When we build cargo in this container, we don't want it to use the system
# libcurl, instead it should compile its own.

View File

@ -1,26 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
set -ex
source shared.sh
curl https://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.bz2 | tar xfj -
mkdir binutils-build
cd binutils-build
hide_output ../binutils-2.25.1/configure --prefix=/rustroot
hide_output make -j10
hide_output make install
cd ..
rm -rf binutils-build
rm -rf binutils-2.25.1

View File

@ -1,25 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
set -ex
source shared.sh
curl https://cmake.org/files/v3.6/cmake-3.6.3.tar.gz | tar xzf -
mkdir cmake-build
cd cmake-build
hide_output ../cmake-3.6.3/configure --prefix=/rustroot
hide_output make -j10
hide_output make install
cd ..
rm -rf cmake-build
rm -rf cmake-3.6.3

View File

@ -1,43 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
set -ex
source shared.sh
VERSION=7.51.0
curl http://cool.haxx.se/download/curl-$VERSION.tar.bz2 | tar xjf -
mkdir curl-build
cd curl-build
hide_output ../curl-$VERSION/configure \
--prefix=/rustroot \
--with-ssl=/rustroot \
--disable-sspi \
--disable-gopher \
--disable-smtp \
--disable-smb \
--disable-imap \
--disable-pop3 \
--disable-tftp \
--disable-telnet \
--disable-manual \
--disable-dict \
--disable-rtsp \
--disable-ldaps \
--disable-ldap
hide_output make -j10
hide_output make install
cd ..
rm -rf curl-build
rm -rf curl-$VERSION
yum erase -y curl

View File

@ -1,50 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
set -ex
source shared.sh
GCC=4.8.5
curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf -
cd gcc-$GCC
# FIXME(#49246): Remove the `sed` below.
#
# On 2018 March 21st, two Travis builders' cache for Docker are suddenly invalidated. Normally this
# is fine, because we just need to rebuild the Docker image. However, it reveals a network issue:
# downloading from `ftp://gcc.gnu.org/` from Travis (using passive mode) often leads to "Connection
# timed out" error, and even when the download completed, the file is usually corrupted. This causes
# nothing to be landed that day.
#
# We observed that the `gcc-4.8.5.tar.bz2` above can be downloaded successfully, so as a stability
# improvement we try to download from the HTTPS mirror instead. Turns out this uncovered the third
# bug: the host `gcc.gnu.org` and `cygwin.com` share the same IP, and the TLS certificate of the
# latter host is presented to `wget`! Therefore, we choose to download from the insecure HTTP server
# instead here.
#
sed -i'' 's|ftp://gcc\.gnu\.org/|http://gcc.gnu.org/|g' ./contrib/download_prerequisites
./contrib/download_prerequisites
mkdir ../gcc-build
cd ../gcc-build
hide_output ../gcc-$GCC/configure \
--prefix=/rustroot \
--enable-languages=c,c++
hide_output make -j10
hide_output make install
ln -nsf gcc /rustroot/bin/cc
cd ..
rm -rf gcc-build
rm -rf gcc-$GCC
yum erase -y gcc gcc-c++ binutils

View File

@ -1,24 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
set -ex
source shared.sh
curl -L https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf -
cd git-2.10.0
make configure
hide_output ./configure --prefix=/rustroot
hide_output make -j10
hide_output make install
cd ..
rm -rf git-2.10.0

View File

@ -1,25 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
set -ex
source shared.sh
curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x
cd linux-3.2.84
hide_output make mrproper
hide_output make INSTALL_HDR_PATH=dest headers_install
find dest/include \( -name .install -o -name ..install.cmd \) -delete
yes | cp -fr dest/include/* /usr/include
cd ..
rm -rf linux-3.2.84

View File

@ -1,28 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
set -ex
source shared.sh
VERSION=1.0.2k
URL=https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/openssl-$VERSION.tar.gz
curl $URL | tar xzf -
cd openssl-$VERSION
hide_output ./config --prefix=/rustroot shared -fPIC
hide_output make -j10
hide_output make install
cd ..
rm -rf openssl-$VERSION
# Make the system cert collection available to the new install.
ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/

View File

@ -1,30 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
set -ex
source shared.sh
curl https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz | \
tar xzf -
mkdir python-build
cd python-build
# Gotta do some hackery to tell python about our custom OpenSSL build, but other
# than that fairly normal.
CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \
hide_output ../Python-2.7.12/configure --prefix=/rustroot
hide_output make -j10
hide_output make install
cd ..
rm -rf python-build
rm -rf Python-2.7.12

View File

@ -1,25 +0,0 @@
# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
hide_output() {
set +x
on_err="
echo ERROR: An error was encountered with the build.
cat /tmp/build.log
exit 1
"
trap "$on_err" ERR
bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
PING_LOOP_PID=$!
$@ &> /tmp/build.log
trap - ERR
kill $PING_LOOP_PID
set -x
}

View File

@ -29,7 +29,7 @@ ENV PATH=/rustroot/bin:$PATH
ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib
ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
WORKDIR /tmp
COPY dist-x86_64-linux/shared.sh dist-x86_64-linux/build-binutils.sh /tmp/
COPY dist-x86_64-linux/shared.sh /tmp/
# We need a build of openssl which supports SNI to download artifacts from
# static.rust-lang.org. This'll be used to link into libcurl below (and used
@ -51,9 +51,15 @@ RUN ./build-curl.sh
# immediately segfault in Rust, so we need to install our own binutils.
#
# See https://github.com/rust-lang/rust/issues/20440 for more info
COPY dist-x86_64-linux/build-binutils.sh /tmp/
RUN ./build-binutils.sh
# Need a newer version of gcc than centos has to compile LLVM nowadays
# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS
# only has 2.6.4, so build our own
COPY dist-x86_64-linux/build-cmake.sh /tmp/
RUN ./build-cmake.sh
# Build a version of gcc capable of building LLVM 6
COPY dist-x86_64-linux/build-gcc.sh /tmp/
RUN ./build-gcc.sh
@ -61,16 +67,17 @@ RUN ./build-gcc.sh
COPY dist-x86_64-linux/build-python.sh /tmp/
RUN ./build-python.sh
# Now build LLVM+Clang 6, afterwards configuring further compilations to use the
# clang/clang++ compilers.
COPY dist-x86_64-linux/build-clang.sh /tmp/
RUN ./build-clang.sh
ENV CC=clang CXX=clang++
# Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for
# cloning, so download and build it here.
COPY dist-x86_64-linux/build-git.sh /tmp/
RUN ./build-git.sh
# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS
# only has 2.6.4, so build our own
COPY dist-x86_64-linux/build-cmake.sh /tmp/
RUN ./build-cmake.sh
# for sanitizers, we need kernel headers files newer than the ones CentOS ships
# with so we install newer ones here
COPY dist-x86_64-linux/build-headers.sh /tmp/
@ -85,8 +92,10 @@ ENV RUST_CONFIGURE_ARGS \
--enable-full-tools \
--enable-sanitizers \
--enable-profiler \
--enable-compiler-docs
--enable-compiler-docs \
--set target.x86_64-unknown-linux-gnu.linker=clang
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang
# This is the only builder which will create source tarballs
ENV DIST_SRC 1

View File

@ -0,0 +1,64 @@
#!/usr/bin/env bash
# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
set -ex
source shared.sh
LLVM=6.0.0
mkdir clang
cd clang
curl https://releases.llvm.org/$LLVM/llvm-$LLVM.src.tar.xz | \
xz -d | \
tar xf -
cd llvm-$LLVM.src
mkdir -p tools/clang
curl https://releases.llvm.org/$LLVM/cfe-$LLVM.src.tar.xz | \
xz -d | \
tar xf - -C tools/clang --strip-components=1
mkdir ../clang-build
cd ../clang-build
# For whatever reason the default set of include paths for clang is different
# than that of gcc. As a result we need to manually include our sysroot's
# include path, /rustroot/include, to clang's default include path.
#
# Alsow there's this weird oddity with gcc where there's an 'include-fixed'
# directory that it generates. It turns out [1] that Centos 5's headers are so
# old that they're incompatible with modern C semantics. While gcc automatically
# fixes that clang doesn't account for this. Tell clang to manually include the
# fixed headers so we can successfully compile code later on.
#
# [1]: https://sourceware.org/ml/crossgcc/2008-11/msg00028.html
INC="/rustroot/include"
INC="$INC:/rustroot/lib/gcc/x86_64-unknown-linux-gnu/4.8.5/include-fixed"
INC="$INC:/usr/include"
hide_output \
cmake ../llvm-$LLVM.src \
-DCMAKE_C_COMPILER=/rustroot/bin/gcc \
-DCMAKE_CXX_COMPILER=/rustroot/bin/g++ \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/rustroot \
-DLLVM_TARGETS_TO_BUILD=X86 \
-DC_INCLUDE_DIRS="$INC"
hide_output make -j10
hide_output make install
cd ../..
rm -rf clang

View File

@ -42,7 +42,6 @@ hide_output ../gcc-$GCC/configure \
--enable-languages=c,c++
hide_output make -j10
hide_output make install
ln -nsf gcc /rustroot/bin/cc
cd ..
rm -rf gcc-build

View File

@ -36,8 +36,10 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
s3url="s3://$SCCACHE_BUCKET/docker/$cksum"
url="https://s3-us-west-1.amazonaws.com/$SCCACHE_BUCKET/docker/$cksum"
echo "Attempting to download $s3url"
rm -f /tmp/rustci_docker_cache
set +e
loaded_images=$(curl $url | docker load | sed 's/.* sha/sha/')
retry curl -f -L -C - -o /tmp/rustci_docker_cache "$url"
loaded_images=$(docker load -i /tmp/rustci_docker_cache | sed 's/.* sha/sha/')
set -e
echo "Downloaded containers:\n$loaded_images"
fi
@ -116,6 +118,10 @@ fi
# goes ahead and sets it for all builders.
args="$args --privileged"
if [ "$CI" != "" ]; then
args="$args --dns 8.8.8.8 --dns 8.8.4.4 --dns 1.1.1.1 --dns 1.0.0.1"
fi
exec docker \
run \
--volume "$root_dir:/checkout:ro" \

View File

@ -18,6 +18,7 @@ if __name__ == '__main__':
os_name = sys.argv[1]
toolstate_file = sys.argv[2]
current_state = sys.argv[3]
verb = sys.argv[4] # 'regressed' or 'changed'
with open(toolstate_file, 'r') as f:
toolstate = json.load(f)
@ -29,10 +30,17 @@ if __name__ == '__main__':
tool = cur['tool']
state = cur[os_name]
new_state = toolstate.get(tool, '')
if new_state < state:
if verb == 'regressed':
updated = new_state < state
elif verb == 'changed':
updated = new_state != state
else:
print('Unknown verb {}'.format(updated))
sys.exit(2)
if updated:
print(
'Error: The state of "{}" has regressed from "{}" to "{}"'
.format(tool, state, new_state)
'The state of "{}" has {} from "{}" to "{}"'
.format(tool, verb, state, new_state)
)
regressed = True

View File

@ -23,6 +23,8 @@ SIX_WEEK_CYCLE="$(( ($(date +%s) / 604800 - 3) % 6 ))"
touch "$TOOLSTATE_FILE"
# Try to test all the tools and store the build/test success in the TOOLSTATE_FILE
set +e
python2.7 "$X_PY" test --no-fail-fast \
src/doc/book \
@ -30,12 +32,15 @@ python2.7 "$X_PY" test --no-fail-fast \
src/doc/reference \
src/doc/rust-by-example \
src/tools/rls \
src/tools/rustfmt
src/tools/rustfmt \
src/tools/miri \
src/tools/clippy
set -e
cat "$TOOLSTATE_FILE"
echo
# This function checks that if a tool's submodule changed, the tool's state must improve
verify_status() {
echo "Verifying status of $1..."
if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then
@ -55,33 +60,61 @@ verify_status() {
fi
}
# deduplicates the submodule check and the assertion that on beta some tools MUST be passing
check_dispatch() {
if [ "$1" = submodule_changed ]; then
# ignore $2 (branch id)
verify_status $3 $4
elif [ "$2" = beta ]; then
echo "Requiring test passing for $3..."
if grep -q '"'"$3"'":"\(test\|build\)-fail"' "$TOOLSTATE_FILE"; then
exit 4
fi
fi
}
# list all tools here
status_check() {
check_dispatch $1 beta book src/doc/book
check_dispatch $1 beta nomicon src/doc/nomicon
check_dispatch $1 beta reference src/doc/reference
check_dispatch $1 beta rust-by-example src/doc/rust-by-example
check_dispatch $1 beta rls src/tool/rls
check_dispatch $1 beta rustfmt src/tool/rustfmt
# these tools are not required for beta to successfully branch
check_dispatch $1 nightly clippy-driver src/tool/clippy
check_dispatch $1 nightly miri src/tool/miri
}
# If this PR is intended to update one of these tools, do not let the build pass
# when they do not test-pass.
verify_status book src/doc/book
verify_status nomicon src/doc/nomicon
verify_status reference src/doc/reference
verify_status rust-by-example src/doc/rust-by-example
verify_status rls src/tool/rls
verify_status rustfmt src/tool/rustfmt
status_check "submodule_changed"
CHECK_NOT="$(readlink -f "$(dirname $0)/checkregression.py")"
change_toolstate() {
# only update the history
if python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" changed; then
echo 'Toolstate is not changed. Not updating.'
else
if [ $SIX_WEEK_CYCLE -eq 5 ]; then
python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" regressed
fi
sed -i "1 a\\
$COMMIT\t$(cat "$TOOLSTATE_FILE")
" "history/$OS.tsv"
fi
}
if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then
. "$(dirname $0)/repo.sh"
MESSAGE_FILE=$(mktemp -t msg.XXXXXX)
echo "($OS CI update)" > "$MESSAGE_FILE"
commit_toolstate_change "$MESSAGE_FILE" \
sed -i "1 a\\
$COMMIT\t$(cat "$TOOLSTATE_FILE")
" "history/$OS.tsv"
# if we are at the last week in the 6-week release cycle, reject any kind of regression.
if [ $SIX_WEEK_CYCLE -eq 5 ]; then
python2.7 "$(dirname $0)/checkregression.py" \
"$OS" "$TOOLSTATE_FILE" "rust-toolstate/_data/latest.json"
fi
commit_toolstate_change "$MESSAGE_FILE" change_toolstate
rm -f "$MESSAGE_FILE"
exit 0
fi
if grep -q fail "$TOOLSTATE_FILE"; then
exit 4
fi
# abort compilation if an important tool doesn't build
# (this code is reachable if not on the nightly channel)
status_check "beta_required"

View File

@ -60,7 +60,7 @@ commit_toolstate_change() {
OLDFLAGS="$-"
set -eu
git config --global user.email '34210020+rust-toolstate-update@users.noreply.github.com'
git config --global user.email '7378925+rust-toolstate-update@users.noreply.github.com'
git config --global user.name 'Rust Toolstate Update'
git config --global credential.helper store
printf 'https://%s:x-oauth-basic@github.com\n' "$TOOLSTATE_REPO_ACCESS_TOKEN" \

View File

@ -27,10 +27,8 @@ fi
ci_dir=`cd $(dirname $0) && pwd`
source "$ci_dir/shared.sh"
if [ "$TRAVIS" == "true" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests"
else
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings"
if [ "$TRAVIS" != "true" ] || [ "$TRAVIS_BRANCH" == "auto" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
fi
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache"
@ -48,7 +46,7 @@ fi
#
# FIXME: need a scheme for changing this `nightly` value to `beta` and `stable`
# either automatically or manually.
export RUST_RELEASE_CHANNEL=stable
export RUST_RELEASE_CHANNEL=beta
if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"

View File

@ -21,11 +21,12 @@ function retry {
while true; do
"$@" && break || {
if [[ $n -lt $max ]]; then
sleep $n # don't retry immediately
((n++))
echo "Command failed. Attempt $n/$max:"
else
echo "The command has failed after $n attempts."
exit 1
return 1
fi
}
done

View File

@ -9,18 +9,9 @@ This version of the book is under development, please file issues liberally!
### Second edition
For the second edition, we are currently working with No Starch Press to bring
it to print. Chapters go through a number of stages in the editing process, and
once they've gotten to the layout stage, they're effectively frozen.
For chapters that have gotten to the layout stage, we will likely only be
accepting changes that correct factual errors or major problems and not, for
example, minor wording changes.
Scroll all the way to the right on https://github.com/rust-lang/book/projects/1
to see which chapters have been frozen.
Please see CONTRIBUTING.md for more details.
No Starch Press has brought the second edition to print. Bugs containing
factual errors will be documented as errata; bugs for wording changes or
other small corrections should be filed against the 2018 edition.
### First edition

View File

@ -11,18 +11,9 @@ ultimately wouldn't accept.
### Second edition
For the second edition, we are currently working with No Starch Press to bring
it to print. Chapters go through a number of stages in the editing process, and
once they've gotten to the layout stage, they're effectively frozen.
For chapters that have gotten to the layout stage, we will likely only be
accepting changes that correct factual errors or major problems and not, for
example, minor wording changes.
Scroll all the way to the right on https://github.com/rust-lang/book/projects/1
to see which chapters have been frozen.
Please see CONTRIBUTING.md for more details.
No Starch Press has brought the second edition to print. Pull requests fixing
factual errors will be accepted and documented as errata; pull requests changing
wording or other small corrections should be made against the 2018 edition instead.
### First edition

View File

@ -1,502 +0,0 @@
personal_ws-1.1 en 0 utf-8
abcabcabc
abcd
abcdefghijklmnopqrstuvwxyz
adaptor
adaptors
AddAssign
Addr
aggregator
AGraph
aliasability
alignof
alloc
allocator
Amir
anotherusername
APIs
app's
aren
args
associativity
async
atomics
AveragedCollection
backend
backported
backtrace
backtraces
BACKTRACE
Backtraces
Bazs
benchmarking
bioinformatics
bitand
BitAnd
BitAndAssign
bitor
BitOr
BitOrAssign
bitwise
Bitwise
bitxor
BitXor
BitXorAssign
Bjarne
Boehm
bool
Boolean
Booleans
Bors
BorrowMutError
BTreeSet
BuildHasher
Cacher
Cagain
callsite
CamelCase
cargodoc
ChangeColor
ChangeColorMessage
charset
choo
chXX
chYY
coercions
combinator
ConcreteType
config
Config
const
constant's
copyeditor
couldn
CPUs
cratesio
CRLF
cryptocurrencies
cryptographic
cryptographically
CStr
CString
ctrl
Ctrl
customizable
CustomSmartPointer
CustomSmartPointers
datas
deallocate
deallocated
deallocating
deallocation
debuginfo
decrementing
deps
deref
Deref
dereference
Dereference
dereferenced
dereferences
dereferencing
DerefMut
DeriveInput
destructor
destructure
destructured
destructures
destructuring
Destructuring
deterministically
DevOps
didn
Dobrý
doccargo
doccratesio
DOCTYPE
doesn
disambiguating
DivAssign
DraftPost
DSTs
ebooks
Edsger
egular
else's
emoji
encodings
enum
Enum
enums
enum's
Enums
eprintln
Erlang
ErrorKind
Executables
expr
extern
favicon
FFFD
FFFF
figcaption
fieldname
filename
Filename
filesystem
Filesystem
filesystems
Firefox
FnBox
FnMut
FnOnce
formatter
formatters
FrenchToast
FromIterator
frontend
getter
GGraph
GitHub
gitignore
grapheme
Grapheme
growable
gzip
hardcode
hardcoded
hardcoding
hasher
hashers
HashMap
HashSet
Haskell
hasn
HelloMacro
helloworld
HelloWorld
HelloWorldName
Hmmm
Hoare
Hola
homogenous
html
hyperoptimize
Iceburgh
ident
IDE
IDEs
IDE's
IEEE
impl
implementor
implementors
ImportantExcerpt
incrementing
IndexMut
indices
init
initializer
inline
instantiation
internet
IntoIterator
InvalidDigit
invariants
ioerror
iokind
ioresult
iostdin
IpAddr
IpAddrKind
irst
isize
iter
iterator's
JavaScript
JoinHandle
Kay's
kinded
lang
latin
liballoc
libc
libcollections
libcore
libpanic
librarys
libreoffice
libstd
lifecycle
LimitTracker
LLVM
lobally
locators
LockResult
login
lookup
loopback
lossy
lval
macOS
Matsakis
mathematic
memoization
metadata
Metadata
metaprogramming
mibbit
Mibbit
millis
minigrep
mixup
mkdir
MockMessenger
modifiability
modularity
monomorphization
Monomorphization
monomorphized
MoveMessage
Mozilla
mpsc
msvc
MulAssign
multibyte
multithreaded
mutex
mutex's
Mutex
mutexes
Mutexes
MutexGuard
MyBox
namespace
namespaced
namespaces
namespacing
natively
newfound
NewJob
NewsArticle
NewThread
newtype
newtypes
nitty
nocapture
nomicon
nondeterministic
nonequality
nongeneric
NotFound
null's
OCaml
offsetof
online
OpenGL
optimizations
OptionalFloatingPointNumber
OptionalNumber
OsStr
OsString
other's
OutlinePrint
overloadable
overread
param
parameterize
ParseIntError
PartialEq
PartialOrd
PendingReview
PendingReviewPost
PlaceholderType
polymorphism
PoolCreationError
portia
powershell
PowerShell
powi
preprocessing
Preprocessing
preprocessor
PrimaryColor
println
priv
proc
pthreads
pushups
QuitMessage
quux
RAII
randcrate
RangeFrom
RangeTo
RangeFull
README
READMEs
rect
recurse
recv
redeclaring
Refactoring
refactor
refactoring
refcell
RefCell
RefMut
refutability
reimplement
RemAssign
repr
representable
request's
resizes
resizing
retweet
rewordings
rint
ripgrep
runnable
runtime
runtimes
Rustacean
Rustaceans
rUsT
rustc
rustdoc
Rustonomicon
rustfmt
rustup
screenshot
searchstring
SecondaryColor
SelectBox
semver
SemVer
serde
ShlAssign
ShrAssign
shouldn
Simula
situps
sizeof
Smalltalk
snuck
someproject
someusername
SPDX
spdx
SpreadsheetCell
sqrt
stackoverflow
startup
StaticRef
stderr
stdin
Stdin
stdlib
stdout
steveklabnik's
stringify
Stroustrup
Stroustrup's
struct
Struct
structs
struct's
Structs
SubAssign
subclasses
subcommand
subcommands
subdirectories
subdirectory
submodule
submodules
Submodules
suboptimal
substring
subteams
subtree
subtyping
supertrait
supertraits
TcpListener
TcpStream
templating
test's
TextField
That'd
there'd
ThreadPool
timestamp
Tiếng
timeline
tlborm
TODO
TokenStream
toml
TOML
toolchain
toolchains
ToString
tradeoff
tradeoffs
TrafficLight
transcoding
trpl
tuesday
tuple
tuples
turbofish
Turon
typeof
TypeName
UFCS
unary
Unary
uncomment
Uncomment
unevaluated
Uninstalling
uninstall
unix
unpopulated
unoptimized
UnsafeCell
unsafety
unsized
unsynchronized
URIs
UsefulType
username
USERPROFILE
usize
UsState
utils
vals
variable's
variant's
vers
versa
Versioning
visualstudio
Vlissides
vtable
wasn
WeatherForecast
WebSocket
whitespace
wildcard
wildcards
workflow
workspace
workspaces
Workspaces
wouldn
writeln
WriteMessage
xpression
yyyy
ZipImpl

View File

@ -128,5 +128,4 @@
- [C - Derivable Traits](appendix-03-derivable-traits.md)
- [D - Macros](appendix-04-macros.md)
- [E - Translations](appendix-05-translation.md)
- [F - Newest Features](appendix-06-newest-features.md)
- [G - How Rust is Made and “Nightly Rust”](appendix-07-nightly-rust.md)
- [F - How Rust is Made and “Nightly Rust”](appendix-06-nightly-rust.md)

View File

@ -1,19 +1,21 @@
## Appendix A: Keywords
The following is a list of keywords that are reserved for current or future use
by the Rust language. As such, these may not be used as identifiers, such as
The following list contains keywords that are reserved for current or future
use by the Rust language. As such, they cannot be used as identifiers, such as
names of functions, variables, parameters, struct fields, modules, crates,
constants, macros, static values, attributes, types, traits, or lifetimes.
### Keywords Currently in Use
* `as` - perform primitive casting, disambiguate the specific trait
containing an item, or rename items in `use` and `extern crate` statements
The following keywords currently have the functionality described.
* `as` - perform primitive casting, disambiguate the specific trait containing
an item, or rename items in `use` and `extern crate` statements
* `break` - exit a loop immediately
* `const` - define constant items or constant raw pointers
* `continue` - continue to the next loop iteration
* `crate` - link an external crate or a macro variable representing the crate
in which the macro is defined
* `crate` - link an external crate or a macro variable representing the crate in
which the macro is defined
* `else` - fallback for `if` and `if let` control flow constructs
* `enum` - define an enumeration
* `extern` - link an external crate, function, or variable
@ -46,20 +48,10 @@ constants, macros, static values, attributes, types, traits, or lifetimes.
* `where` - denote clauses that constrain a type
* `while` - loop conditionally based on the result of an expression
<!-- we should make sure the definitions for each keyword are consistently
phrased, so for example for enum we say "defining an enumeration" but for fn we
passively call it a "function definition" -- perhaps a good medium would be
"define an enumeration" and "define a function"? Can you go through and make
those consistent? I've attempted it for a few, but am wary of changing meaning.
Also, you may decide to go the passive definition route, which is fine by me,
as long as it's consistent-->
<!-- I've tried, I'm not sure how to be active for keywords that are nouns
though. Please let me know if any still seem inconsistent /Carol -->
### Keywords Reserved for Future Use
These keywords do not have any functionality, but are reserved by Rust for
potential future use.
The following keywords do not have any functionality but are reserved by Rust
for potential future use.
* `abstract`
* `alignof`

View File

@ -1,172 +1,204 @@
## Appendix B: Operators and Symbols
<!-- We try not to stack headings even in the appendix, can you add some intro
text about what this appendix contains? Quick example below -->
<!-- Done! /Carol -->
This appendix is a glossary of Rusts syntax, including operators and other
symbols that appear by themselves or in the context of paths, generics, trait
bounds, macros, attributes, comments, tuples, and brackets.
This appendix contains a glossary of Rusts syntax, including operators and
other symbols that appear by themselves or in the context of paths, generics,
trait bounds, macros, attributes, comments, tuples, and brackets.
### Operators
The following lists the operators in Rust, an example of how the operator would
Table B-1 contains the operators in Rust, an example of how the operator would
appear in context, a short explanation, and whether that operator is
overloadable. If an operator is overloadable, the relevant trait to use to
overload that operator is listed.
<!-- PROD: I'm not sure how to handle this, would it be too big for a table? I
think some structure with aligned columns would make it a great reference -->
<span class="caption">Table B-1: Operators</span>
* `!` (`ident!(…)`, `ident!{…}`, `ident![…]`): denotes macro expansion.
* `!` (`!expr`): bitwise or logical complement. Overloadable (`Not`).
* `!=` (`var != expr`): nonequality comparison. Overloadable (`PartialEq`).
* `%` (`expr % expr`): arithmetic remainder. Overloadable (`Rem`).
* `%=` (`var %= expr`): arithmetic remainder and assignment. Overloadable (`RemAssign`).
* `&` (`&expr`, `&mut expr`): borrow.
* `&` (`&type`, `&mut type`, `&'a type`, `&'a mut type`): borrowed pointer type.
* `&` (`expr & expr`): bitwise AND. Overloadable (`BitAnd`).
* `&=` (`var &= expr`): bitwise AND and assignment. Overloadable (`BitAndAssign`).
* `&&` (`expr && expr`): logical AND.
* `*` (`expr * expr`): arithmetic multiplication. Overloadable (`Mul`).
* `*` (`*expr`): dereference.
* `*` (`*const type`, `*mut type`): raw pointer.
* `*=` (`var *= expr`): arithmetic multiplication and assignment. Overloadable (`MulAssign`).
* `+` (`trait + trait`, `'a + trait`): compound type constraint.
* `+` (`expr + expr`): arithmetic addition. Overloadable (`Add`).
* `+=` (`var += expr`): arithmetic addition and assignment. Overloadable (`AddAssign`).
* `,`: argument and element separator.
* `-` (`- expr`): arithmetic negation. Overloadable (`Neg`).
* `-` (`expr - expr`): arithmetic subtraction. Overloadable (`Sub`).
* `-=` (`var -= expr`): arithmetic subtraction and assignment. Overloadable (`SubAssign`).
* `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type.
* `.` (`expr.ident`): member access.
* `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal.
* `..` (`..expr`): struct literal update syntax.
* `..` (`variant(x, ..)`, `struct_type { x, .. }`): “and the rest” pattern binding.
* `...` (`expr...expr`) *in a pattern*: inclusive range pattern.
* `/` (`expr / expr`): arithmetic division. Overloadable (`Div`).
* `/=` (`var /= expr`): arithmetic division and assignment. Overloadable (`DivAssign`).
* `:` (`pat: type`, `ident: type`): constraints.
* `:` (`ident: expr`): struct field initializer.
* `:` (`'a: loop {…}`): loop label.
* `;`: statement and item terminator.
* `;` (`[…; len]`): part of fixed-size array syntax
* `<<` (`expr << expr`): left-shift. Overloadable (`Shl`).
* `<<=` (`var <<= expr`): left-shift and assignment. Overloadable (`ShlAssign`).
* `<` (`expr < expr`): less-than comparison. Overloadable (`PartialOrd`).
* `<=` (`expr <= expr`): less-than or equal-to comparison. Overloadable (`PartialOrd`).
* `=` (`var = expr`, `ident = type`): assignment/equivalence.
* `==` (`expr == expr`): equality comparison. Overloadable (`PartialEq`).
* `=>` (`pat => expr`): part of match arm syntax.
* `>` (`expr > expr`): greater-than comparison. Overloadable (`PartialOrd`).
* `>=` (`expr >= expr`): greater-than or equal-to comparison. Overloadable (`PartialOrd`).
* `>>` (`expr >> expr`): right-shift. Overloadable (`Shr`).
* `>>=` (`var >>= expr`): right-shift and assignment. Overloadable (`ShrAssign`).
* `@` (`ident @ pat`): pattern binding.
* `^` (`expr ^ expr`): bitwise exclusive OR. Overloadable (`BitXor`).
* `^=` (`var ^= expr`): bitwise exclusive OR and assignment. Overloadable (`BitXorAssign`).
* `|` (`pat | pat`): pattern alternatives.
* `|` (`|…| expr`): closures.
* `|` (`expr | expr`): bitwise OR. Overloadable (`BitOr`).
* `|=` (`var |= expr`): bitwise OR and assignment. Overloadable (`BitOrAssign`).
* `||` (`expr || expr`): logical OR.
* `_`: “ignored” pattern binding. Also used to make integer-literals readable.
* `?` (`expr?`): Error propagation.
| Operator | Example | Explanation | Overloadable? |
|----------|---------|-------------|---------------|
| `!` | `ident!(...)`, `ident!{...}`, `ident![...]` | Macro expansion | |
| `!` | `!expr` | Bitwise or logical complement | `Not` |
| `!=` | `var != expr` | Nonequality comparison | `PartialEq` |
| `%` | `expr % expr` | Arithmetic remainder | `Rem` |
| `%=` | `var %= expr` | Arithmetic remainder and assignment | `RemAssign` |
| `&` | `&expr`, `&mut expr` | Borrow | |
| `&` | `&type`, `&mut type`, `&'a type`, `&'a mut type` | Borrowed pointer type | |
| `&` | `expr & expr` | Bitwise AND | `BitAnd` |
| `&=` | `var &= expr` | Bitwise AND and assignment | `BitAndAssign` |
| `&&` | `expr && expr` | Logical AND | |
| `*` | `expr * expr` | Arithmetic multiplication | `Mul` |
| `*=` | `var *= expr` | Arithmetic multiplication and assignment | `MulAssign` |
| `*` | `*expr` | Dereference | |
| `*` | `*const type`, `*mut type` | Raw pointer | |
| `+` | `trait + trait`, `'a + trait` | Compound type constraint | |
| `+` | `expr + expr` | Arithmetic addition | `Add` |
| `+=` | `var += expr` | Arithmetic addition and assignment | `AddAssign` |
| `,` | `expr, expr` | Argument and element separator | |
| `-` | `- expr` | Arithmetic negation | `Neg` |
| `-` | `expr - expr` | Arithmetic subtraction | `Sub` |
| `-=` | `var -= expr` | Arithmetic subtraction and assignment | `SubAssign` |
| `->` | `fn(...) -> type`, <code>\|...\| -> type</code> | Function and closure return type | |
| `.` | `expr.ident` | Member access | |
| `..` | `..`, `expr..`, `..expr`, `expr..expr` | Right-exclusive range literal | |
| `..` | `..expr` | Struct literal update syntax | |
| `..` | `variant(x, ..)`, `struct_type { x, .. }` | “And the rest” pattern binding | |
| `...` | `expr...expr` | In a pattern: inclusive range pattern | |
| `/` | `expr / expr` | Arithmetic division | `Div` |
| `/=` | `var /= expr` | Arithmetic division and assignment | `DivAssign` |
| `:` | `pat: type`, `ident: type` | Constraints | |
| `:` | `ident: expr` | Struct field initializer | |
| `:` | `'a: loop {...}` | Loop label | |
| `;` | `expr;` | Statement and item terminator | |
| `;` | `[...; len]` | Part of fixed-size array syntax | |
| `<<` | `expr << expr` | Left-shift | `Shl` |
| `<<=` | `var <<= expr` | Left-shift and assignment | `ShlAssign` |
| `<` | `expr < expr` | Less than comparison | `PartialOrd` |
| `<=` | `expr <= expr` | Less than or equal to comparison | `PartialOrd` |
| `=` | `var = expr`, `ident = type` | Assignment/equivalence | |
| `==` | `expr == expr` | Equality comparison | `PartialEq` |
| `=>` | `pat => expr` | Part of match arm syntax | |
| `>` | `expr > expr` | Greater than comparison | `PartialOrd` |
| `>=` | `expr >= expr` | Greater than or equal to comparison | `PartialOrd` |
| `>>` | `expr >> expr` | Right-shift | `Shr` |
| `>>=` | `var >>= expr` | Right-shift and assignment | `ShrAssign` |
| `@` | `ident @ pat` | Pattern binding | |
| `^` | `expr ^ expr` | Bitwise exclusive OR | `BitXor` |
| `^=` | `var ^= expr` | Bitwise exclusive OR and assignment | `BitXorAssign` |
| <code>\|</code> | <code>pat \| pat</code> | Pattern alternatives | |
| <code>\|</code> | <code>expr \| expr</code> | Bitwise OR | `BitOr` |
| <code>\|=</code> | <code>var \|= expr</code> | Bitwise OR and assignment | `BitOrAssign` |
| <code>\|\|</code> | <code>expr \|\| expr</code> | Logical OR | |
| `?` | `expr?` | Error propagation | |
### Non-operator Symbols
<!-- And maybe a quick explanation of what you mean by non-operator
symbols/what counts as a non-operator symbol? -->
<!-- I've tried but it's hard to explain, it's the kind of thing you know when
you see it? /Carol -->
The following list contains all non-letters that dont function as operators;
that is, they dont behave like a function or method call.
The following lists all non-letters that dont function as operators; that is,
they dont behave like a function or method call.
Table B-2 shows symbols that appear on their own and are valid in a variety of
locations.
#### Standalone Syntax
<span class="caption">Table B-2: Stand-Alone Syntax</span>
* `'ident`: named lifetime or loop label
* `…u8`, `…i32`, `…f64`, `…usize`, *etc.*: numeric literal of specific type.
* `"…"`: string literal.
* `r"…"`, `r#"…"#`, `r##"…"##`, *etc.*: raw string literal, escape characters are not processed.
* `b"…"`: byte string literal, constructs a `[u8]` instead of a string.
* `br"…"`, `br#"…"#`, `br##"…"##`, *etc.*: raw byte string literal, combination of raw and byte string literal.
* `'…'`: character literal.
* `b'…'`: ASCII byte literal.
* `|…| expr`: closure.
* `!`: always empty bottom type for diverging functions.
| Symbol | Explanation |
|--------|-------------|
| `'ident` | Named lifetime or loop label |
| `...u8`, `...i32`, `...f64`, `...usize`, etc. | Numeric literal of specific type |
| `"..."` | String literal |
| `r"..."`, `r#"..."#`, `r##"..."##`, etc. | Raw string literal, escape characters not processed |
| `b"..."` | Byte string literal; constructs a `[u8]` instead of a string |
| `br"..."`, `br#"..."#`, `br##"..."##`, etc. | Raw byte string literal, combination of raw and byte string literal |
| `'...'` | Character literal |
| `b'...'` | ASCII byte literal |
| <code>\|...\| expr</code> | Closure |
| `!` | Always empty bottom type for diverging functions |
| `_` | “Ignored” pattern binding; also used to make integer literals readable |
#### Path-related Syntax
Table B-3 shows symbols that appear in the context of a path through the module
hierarchy to an item.
* `ident::ident`: namespace path.
* `::path`: path relative to the crate root (*i.e.* an explicitly absolute path).
* `self::path`: path relative to the current module (*i.e.* an explicitly relative path).
* `super::path`: path relative to the parent of the current module.
* `type::ident`, `<type as trait>::ident`: associated constants, functions, and types.
* `<type>::…`: associated item for a type which cannot be directly named (*e.g.* `<&T>::…`, `<[T]>::…`, *etc.*).
* `trait::method(…)`: disambiguating a method call by naming the trait which defines it.
* `type::method(…)`: disambiguating a method call by naming the type for which its defined.
* `<type as trait>::method(…)`: disambiguating a method call by naming the trait *and* type.
<span class="caption">Table B-3: Path-Related Syntax</span>
#### Generics
| Symbol | Explanation |
|--------|-------------|
| `ident::ident` | Namespace path |
| `::path` | Path relative to the crate root (i.e., an explicitly absolute path) |
| `self::path` | Path relative to the current module (i.e., an explicitly relative path).
| `super::path` | Path relative to the parent of the current module |
| `type::ident`, `<type as trait>::ident` | Associated constants, functions, and types |
| `<type>::...` | Associated item for a type that cannot be directly named (e.g., `<&T>::...`, `<[T]>::...`, etc.) |
| `trait::method(...)` | Disambiguating a method call by naming the trait that defines it |
| `type::method(...)` | Disambiguating a method call by naming the type for which its defined |
| `<type as trait>::method(...)` | Disambiguating a method call by naming the trait and type |
* `path<…>` (*e.g.* `Vec<u8>`): specifies parameters to generic type *in a type*.
* `path::<…>`, `method::<…>` (*e.g.* `"42".parse::<i32>()`): specifies parameters to generic type, function, or method *in an expression*. Often referred to as *turbofish*.
* `fn ident<…> …`: define generic function.
* `struct ident<…> …`: define generic structure.
* `enum ident<…> …`: define generic enumeration.
* `impl<…> …`: define generic implementation.
* `for<…> type`: higher-ranked lifetime bounds.
* `type<ident=type>` (*e.g.* `Iterator<Item=T>`): a generic type where one or more associated types have specific assignments.
Table B-4 shows symbols that appear in the context of using generic type
parameters.
#### Trait Bound Constraints
<span class="caption">Table B-4: Generics</span>
* `T: U`: generic parameter `T` constrained to types that implement `U`.
* `T: 'a`: generic type `T` must outlive lifetime `'a`. When we say that a type outlives the lifetime, we mean that it cannot transitively contain any references with lifetimes shorter than `'a`.
* `T : 'static`: The generic type `T` contains no borrowed references other than `'static` ones.
* `'b: 'a`: generic lifetime `'b` must outlive lifetime `'a`.
* `T: ?Sized`: allow generic type parameter to be a dynamically-sized type.
* `'a + trait`, `trait + trait`: compound type constraint.
| Symbol | Explanation |
|--------|-------------|
| `path<...>` | Specifies parameters to generic type in a type (e.g., `Vec<u8>`) |
| `path::<...>`, `method::<...>` | Specifies parameters to generic type, function, or method in an expression; often referred to as turbofish (e.g., `"42".parse::<i32>()`) |
| `fn ident<...> ...` | Define generic function |
| `struct ident<...> ...` | Define generic structure |
| `enum ident<...> ...` | Define generic enumeration |
| `impl<...> ...` | Define generic implementation |
| `for<...> type` | Higher-ranked lifetime bounds |
| `type<ident=type>` | A generic type where one or more associated types have specific assignments (e.g., `Iterator<Item=T>`) |
#### Macros and Attributes
Table B-5 shows symbols that appear in the context of constraining generic type
parameters with trait bounds.
* `#[meta]`: outer attribute.
* `#![meta]`: inner attribute.
* `$ident`: macro substitution.
* `$ident:kind`: macro capture.
* `$(…)…`: macro repetition.
<span class="caption">Table B-5: Trait Bound Constraints</span>
#### Comments
| Symbol | Explanation |
|--------|-------------|
| `T: U` | Generic parameter `T` constrained to types that implement `U` |
| `T: 'a` | Generic type `T` must outlive lifetime `'a` (meaning the type cannot transitively contain any references with lifetimes shorter than `'a`) |
| `T : 'static` | Generic type `T` contains no borrowed references other than `'static` ones |
| `'b: 'a` | Generic lifetime `'b` must outlive lifetime `'a` |
| `T: ?Sized` | Allow generic type parameter to be a dynamically sized type |
| `'a + trait`, `trait + trait` | Compound type constraint |
* `//`: line comment.
* `//!`: inner line doc comment.
* `///`: outer line doc comment.
* `/*…*/`: block comment.
* `/*!…*/`: inner block doc comment.
* `/**…*/`: outer block doc comment.
Table B-6 shows symbols that appear in the context of calling or defining
macros and specifying attributes on an item.
#### Tuples
<span class="caption">Table B-6: Macros and Attributes</span>
* `()`: empty tuple (*a.k.a.* unit), both literal and type.
* `(expr)`: parenthesized expression.
* `(expr,)`: single-element tuple expression.
* `(type,)`: single-element tuple type.
* `(expr, …)`: tuple expression.
* `(type, …)`: tuple type.
* `expr(expr, …)`: function call expression. Also used to initialize tuple `struct`s and tuple `enum` variants.
* `ident!(…)`, `ident!{…}`, `ident![…]`: macro invocation.
* `expr.0`, `expr.1`, …: tuple indexing.
| Symbol | Explanation |
|--------|-------------|
| `#[meta]` | Outer attribute |
| `#![meta]` | Inner attribute |
| `$ident` | Macro substitution |
| `$ident:kind` | Macro capture |
| `$(…)…` | Macro repetition |
#### Curly Brackets
Table B-7 shows symbols that create comments.
* `{…}`: block expression.
* `Type {…}`: `struct` literal.
<span class="caption">Table B-7: Comments</span>
#### Square Brackets
| Symbol | Explanation |
|--------|-------------|
| `//` | Line comment |
| `//!` | Inner line doc comment |
| `///` | Outer line doc comment |
| `/*...*/` | Block comment |
| `/*!...*/` | Inner block doc comment |
| `/**...*/` | Outer block doc comment |
* `[…]`: array literal.
* `[expr; len]`: array literal containing `len` copies of `expr`.
* `[type; len]`: array type containing `len` instances of `type`.
* `expr[expr]`: collection indexing. Overloadable (`Index`, `IndexMut`).
* `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]`: collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, `RangeFull` as the “index”.
Table B-8 shows symbols that appear in the context of using tuples.
<span class="caption">Table B-8: Tuples</span>
| Symbol | Explanation |
|--------|-------------|
| `()` | Empty tuple (aka unit), both literal and type |
| `(expr)` | Parenthesized expression |
| `(expr,)` | Single-element tuple expression |
| `(type,)` | Single-element tuple type |
| `(expr, ...)` | Tuple expression |
| `(type, ...)` | Tuple type |
| `expr(expr, ...)` | Function call expression; also used to initialize tuple `struct`s and tuple `enum` variants |
| `ident!(...)`, `ident!{...}`, `ident![...]` | Macro invocation |
| `expr.0`, `expr.1`, etc. | Tuple indexing |
Table B-9 shows the contexts in which curly braces are used.
<span class="caption">Table B-9: Curly Brackets</span>
| Context | Explanation |
|---------|-------------|
| `{...}` | Block expression |
| `Type {...}` | `struct` literal |
Table B-10 shows the contexts in which square brackets are used.
<span class="caption">Table B-10: Square Brackets</span>
| Context | Explanation |
|---------|-------------|
| `[...]` | Array literal |
| `[expr; len]` | Array literal containing `len` copies of `expr` |
| `[type; len]` | Array type containing `len` instances of `type` |
| `expr[expr]` | Collection indexing. Overloadable (`Index`, `IndexMut`) |
| `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]` | Collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, or `RangeFull` as the “index” |

View File

@ -1,140 +1,104 @@
## C - Derivable Traits
## Appendix C: Derivable Traits
In various places in the book, weve discussed the `derive` attribute
that you can apply to a struct or enum definition.
In various places in the book, weve discussed the `derive` attribute, which
you can apply to a struct or enum definition. The `derive` attribute generates
code that will implement a trait with its own default implementation on the
type youve annotated with the `derive` syntax.
<!-- Above -- I wasn't clear throughout whether the derive attribute is
something passively applied to structs and enums by Rust, or something the
reader applies. I've experimented with making the tone more active, but may
have misinterpreted -- can you make it clear here? Should this be "we've
discussed the `derive` attribute you can apply to a struct or enum"? -->
<!-- Rust never edits your source code file for you. I'm curious to know what
parts of the book have given you that impression... I've tried to clarify here
but now I'm worried about other places in the book... /Carol -->
In this appendix, we provide a reference of all the traits in the standard
library that you can use with `derive`. Each section covers:
<!-- Below -- Can you lay out what it is we're showing them about derivable
traits in this appendix, just showing them some common ones and how to use
them? -->
<!-- No, we're showing *all* of the derivable traits provided by the standard
library. I guess explaining what we mean by "derivable" was too much of a
tangent for the beginning of this section? I'm not sure where that would fit
instead, so I took it out. So now the text that we had under the "standard
library traits that can be derived" section is here where it seems like you
were expecting it to be /Carol -->
The `derive` attribute generates code that will implement a trait with its own
default implementation, on the type you have annotated with the `derive`
syntax. In this appendix, we provide a reference of all of the traits in the
standard library that can be used with `derive`. Each section covers:
- What operators and methods deriving this trait will enable
- What the implementation of the trait provided by `derive` does
- What implementing the trait signifies about the type
- The conditions in which youre allowed or not allowed to implement the trait
- Examples of operations that require the trait
* What operators and methods deriving this trait will enable
* What the implementation of the trait provided by `derive` does
* What implementing the trait signifies about the type
* The conditions in which youre allowed or not allowed to implement the trait
* Examples of operations that require the trait
If you want different behavior than that provided by the `derive` attribute,
consult the standard library documentation for each trait for details of how to
consult the standard library documentation for each trait for details on how to
manually implement them.
<!-- Liz: I've incorporated the small sections that were after the list of
traits here and then moved the section headings out a level, what do you think?
/Carol -->
The rest of the traits defined in the standard library cant be implemented on
your types using `derive`. These traits dont have sensible default behavior,
so its up to you to implement them in the way that makes sense for what youre
trying to accomplish.
An example of a trait that cant be derived is `Display`, which handles
formatting for end users. You should always put thought into the appropriate
way to display a type to an end user: what parts of the type should an end user
be allowed to see? What parts would they find relevant? What format of the data
would be most relevant to them? The Rust compiler doesnt have this insight and
so cant provide appropriate default behavior for you.
formatting for end users. You should always consider the appropriate way to
display a type to an end user. What parts of the type should an end user be
allowed to see? What parts would they find relevant? What format of the data
would be most relevant to them? The Rust compiler doesnt have this insight, so
it cant provide appropriate default behavior for you.
The list of derivable traits provided in this appendix is not comprehensive:
libraries can implement `derive` for their own traits! In this way, the list of
traits you can use `derive` with is truly open-ended. Implementing `derive`
involves using a procedural macro, which is covered in Appendix D, “Macros.
libraries can implement `derive` for their own traits, making the list of
traits you can use `derive` with truly open-ended. Implementing `derive`
involves using a procedural macro, which is covered in Appendix D.
### `Debug` for Programmer Output
The `Debug` trait enables debug formatting in format strings, indicated by
adding `:?` within `{}` placeholders.
The `Debug` trait enables debug formatting in format strings, which you
indicate by adding `:?` within `{}` placeholders.
The `Debug` trait allows you to print instances of a type for debugging
purposes, so you and other programmers using your type can inspect an instance
at a particular point in a programs execution.
`Debug` is required, for example, in use of the `assert_eq!` macro, which
prints the values of instances given as arguments if the equality assertion
fails so programmers can see why the two instances werent equal.
The `Debug` trait is required, for example, in use of the `assert_eq!` macro.
This macro prints the values of instances given as arguments if the equality
assertion fails so programmers can see why the two instances werent equal.
### `PartialEq` and `Eq` for Equality Comparisons
<!-- I've tried to phrase these definitions in a more active way, it seems like
we're saying using these traits gives us this capabilities --- apologies if
I've misunderstood, feel free to change the phrasing back to the "signifies
that..." version -->
<!-- More active is fine. I feel like it lost a tiny bit of meaning-- not only
can we use these capabilities on our own types, but other programmers using our
types can use these capabilities too. I've tried to reinsert that sentiment
occasionally. /Carol -->
The `PartialEq` trait allows you to compare instances of a type to check for
equality, and enables use of the `==` and `!=` operators.
equality and enables use of the `==` and `!=` operators.
Deriving `PartialEq` implements the `eq` method. When `PartialEq` is derived on
structs, two instances are equal only if *all* fields are equal, and not equal
if any fields are not equal. When derived on enums, each variant is equal to
itself and not equal to the other variants.
structs, two instances are equal only if *all* fields are equal, and the
instances are not equal if any fields are not equal. When derived on enums,
each variant is equal to itself and not equal to the other variants.
`PartialEq` is required, for example, with the use of the `assert_eq!` macro,
which needs to be able to compare two instances of a type for equality.
The `PartialEq` trait is required, for example, with the use of the
`assert_eq!` macro, which needs to be able to compare two instances of a type
for equality.
The `Eq` trait has no methods. Its purpose is to signal that for every value of
the annotated type, the value is equal to itself. The `Eq` trait can only be
applied to types that also implement `PartialEq`, though not all types that
applied to types that also implement `PartialEq`, although not all types that
implement `PartialEq` can implement `Eq`. One example of this is floating point
number types: the implementation of floating point numbers says that two
instances of the not-a-number value, `NaN`, are not equal to each other.
number types: the implementation of floating point numbers states that two
instances of the not-a-number (`NaN`) value are not equal to each other.
An example of when `Eq` is required is for keys in a `HashMap` so that the
`HashMap` can tell whether two keys are the same.
An example of when `Eq` is required is for keys in a `HashMap<K, V>` so the
`HashMap<K, V>` can tell whether two keys are the same.
### `PartialOrd` and `Ord` for Ordering Comparisons
The `PartialOrd` trait allows you to compare instances of a type for sorting
purposes. A type that implements `PartialOrd` may be used with the `<`, `>`,
`<=`, and `>=` operators. The `PartialOrd` trait can only be applied to types
purposes. A type that implements `PartialOrd` can be used with the `<`, `>`,
`<=`, and `>=` operators. You can only apply the `PartialOrd` trait to types
that also implement `PartialEq`.
Deriving `PartialOrd` implements the `partial_cmp` method, which returns an
`Option<Ordering>` that will be `None` when the values given do not produce an
`Option<Ordering>` that will be `None` when the values given dont produce an
ordering. An example of a value that doesnt produce an ordering, even though
most values of that type can be compared, is the not-a-number (`NaN`) floating
point value. Calling `partial_cmp` with any floating point number and the `NaN`
floating point value will return `None`.
<!-- Above -- you mean when the values cannot be ordered, for example if they
are of types that can't be compared? -->
<!-- No, if they're *types* that can't be compared, then the PartialOrd trait
doesn't apply at all. I've tried to clarify and added an example /Carol-->
When derived on structs, `PartialOrd` compares two instances by comparing the
value in each field in the order in which the fields appear in the struct
definition. When derived on enums, variants of the enum declared earlier in the
enum definition are considered greater than the variants listed later.
enum definition are considered less than the variants listed later.
`PartialOrd` is required, for example, for the `gen_range` method from the
`rand` crate that generates a random value in the range specified by a low
value and a high value.
The `PartialOrd` trait is required, for example, for the `gen_range` method
from the `rand` crate that generates a random value in the range specified by a
low value and a high value.
The `Ord` trait allows you to know that for any two values of the annotated
type, a valid ordering will exist. The `Ord` trait implements the `cmp` method,
which returns an `Ordering` rather than an `Option<Ordering>` because a valid
ordering will always be possible. The `Ord` trait can only be applied to types
ordering will always be possible. You can only apply the `Ord` trait to types
that also implement `PartialOrd` and `Eq` (and `Eq` requires `PartialEq`). When
derived on structs and enums, `cmp` behaves the same way as the derived
implementation for `partial_cmp` does with `PartialOrd`.
@ -144,22 +108,14 @@ a data structure that stores data based on the sort order of the values.
### `Clone` and `Copy` for Duplicating Values
<!-- Below -- I wasn't clear on the arbitrary code section of this explanation.
Are we saying using Clone (as opposed to copy) risks bringing it arbitrary
code? Why use Clone over copy? (I think we might have covered this in an
earlier chapter, so feel free to cross ref there too if that's an easier
explanation) -->
<!-- Yes, we covered this in chapter 4 and I've added a cross reference. /Carol
-->
The `Clone` trait allows you to explicitly create a deep copy of a value, and
the duplication process might involve running arbitrary code and copying heap
data. See the “Ways Variables and Data Interact: Clone” section in Chapter 4
for more information on `Clone`.
Deriving `Clone` implements the `clone` method which, when implemented for the
whole type, calls `clone` on each of the parts of the type. This means all of
the fields or values in the type must also implement `Clone` to derive `Clone`.
Deriving `Clone` implements the `clone` method, which when implemented for the
whole type, calls `clone` on each of the parts of the type. This means all the
fields or values in the type must also implement `Clone` to derive `Clone`.
An example of when `Clone` is required is when calling the `to_vec` method on a
slice. The slice doesnt own the type instances it contains, but the vector
@ -170,61 +126,49 @@ The `Copy` trait allows you to duplicate a value by only copying bits stored on
the stack; no arbitrary code is necessary. See the “Stack-Only Data: Copy”
section in Chapter 4 for more information on `Copy`.
<!-- I'm not clear on why the clone trait uses arbitrary code but copy doesn't
-- is this important to make clear? -->
<!-- We discussed this in chapter 4; I've added a cross ref. /Carol -->
The `Copy` trait does not define any methods to prevent programmers from
overloading those methods violating the assumption that no arbitrary code is
being run. That way, all programmers can assume that copying a value will be
The `Copy` trait doesnt define any methods to prevent programmers from
overloading those methods and violating the assumption that no arbitrary code
is being run. That way, all programmers can assume that copying a value will be
very fast.
<!-- above -- I couldn't follow this either, what does that mean practically
for the programmer? What does overloading methods that violate the assumption
mean? -->
<!-- I added a sentence at the end of the paragraph, does that clear it up?
/Carol -->
You can derive `Copy` on any type whose parts all implement `Copy`. You can
only apply the `Copy` trait to types that also implement `Clone`, because a
type that implements `Copy` has a trivial implementation of `Clone` that
performs the same task as `Copy`.
You can derive `Copy` on any type whose parts all implement `Copy`. The `Copy`
trait can only be applied to types that also implement `Clone`, as a type that
implements `Copy` has a trivial implementation of `Clone`, doing the same thing
as `Copy`.
The `Copy` trait is rarely required; types that implement `Copy` have
optimizations available, meaning you dont have to call `clone`, which makes
the code more concise.
`Copy` is rarely required; types implement `Copy` have optimizations available
mean you dont have to call `clone`, making the code more concise.
<!-- By "nicer" do you mean more efficient and understandable? -->
<!-- concise, I've changed /Carol -->
Everything possible with `Copy` can also be accomplished with `Clone`, but the
Everything possible with `Copy` you can also accomplish with `Clone`, but the
code might be slower or have to use `clone` in places.
### `Hash` for Mapping a Value to a Value of Fixed Size
The `Hash` trait allows you to take an instance of a type of arbitrary size and
map that instance to a value of fixed size, using a hash function. Deriving
map that instance to a value of fixed size using a hash function. Deriving
`Hash` implements the `hash` method. The derived implementation of the `hash`
method combines the result of calling `hash` on each of the parts of the type,
meaning all fields or values must also implement `Hash` to derive `Hash`.
An example of when `Hash` is required is in storing keys in a `HashMap`, in
order to store data efficiently.
An example of when `Hash` is required is in storing keys in a `HashMap<K, V>`
to store data efficiently.
### `Default` for Default Values
The `Default` trait allows you to create a default value for a type. Deriving
`Default` implements the `default` method. The derived implementation of the
`default` method calls the `default` method on each part of the type, meaning
all fields or values in the type must also implement `Default` to derive
`Default.`
`Default` implements the `default` function. The derived implementation of the
`default` function calls the `default` function on each part of the type,
meaning all fields or values in the type must also implement `Default` to
derive `Default.`
`Default::default` is commonly used in combination with the struct update
syntax discussed in the “Creating Instances From Other Instances With Struct
Update Syntax” section in Chapter 5. You can customize a few fields of a struct
and then set and use a default value for the rest of the fields by using
The `Default::default` function is commonly used in combination with the struct
update syntax discussed in the “Creating Instances From Other Instances With
Struct Update Syntax” section in Chapter 5. You can customize a few fields of a
struct and then set and use a default value for the rest of the fields by using
`..Default::default()`.
`Default` is required when, for example, you use the `unwrap_or_default` method
on `Option<T>` instances. If the `Option<T>` is `None`, the `unwrap_or_default`
method will return the result of `Default::default` for the type `T` stored in
the `Option<T>`.
The `Default` trait is required when you use the method `unwrap_or_default` on
`Option<T>` instances, for example. If the `Option<T>` is `None`, the method
`unwrap_or_default` will return the result of `Default::default` for the type
`T` stored in the `Option<T>`.

View File

@ -1,53 +1,55 @@
## Appendix D: Macros
Weve used macros like `println!` throughout this book, but havent fully
explored what a macro is and how it works. This appendix will explain:
Weve used macros like `println!` throughout this book but havent fully
explored what a macro is and how it works. This appendix explains macros as
follows:
- What macros are and how they differ from functions
- How to define a declarative macro to do metaprogramming
- How to define a procedural macro to create custom `derive` traits
* What macros are and how they differ from functions
* How to define a declarative macro to do metaprogramming
* How to define a procedural macro to create custom `derive` traits
Were covering the details of macros in an appendix because theyre still
evolving in Rust. Macros have changed and, in the near future, will change at a
quicker rate than the rest of the language and standard library since Rust 1.0,
so this section is more likely to date than the rest of the book. The code
shown here will still continue to work with future versions, due to Rusts
stability guarantees, but there may be additional capabilities or easier ways
so this section is more likely to become out-of-date than the rest of the book.
Due to Rusts stability guarantees, the code shown here will continue to work
with future versions, but there may be additional capabilities or easier ways
to write macros that werent available at the time of this publication. Bear
that in mind if you try to implement anything from this appendix.
that in mind when you try to implement anything from this appendix.
### The Difference Between Macros and Functions
Fundamentally, macros are a way of writing code that writes other code, known
as *metaprogramming*. In Appendix C, we discussed the `derive` attribute, which
generates an implementation of various traits for you. Weve also used the
`println!` and `vec!` macros throughout the book. All of these macros *expand*
to produce more code than the code youve written yourself.
Fundamentally, macros are a way of writing code that writes other code, which
is known as *metaprogramming*. In Appendix C, we discussed the `derive`
attribute, which generates an implementation of various traits for you. Weve
also used the `println!` and `vec!` macros throughout the book. All of these
macros *expand* to produce more code than the code youve written manually.
Metaprogramming is useful for reducing the amount of code you have to write and
maintain, which is also one of the roles of functions. However, macros have
some additional powers that functions dont have.
A function signature has to declare the number and type of parameters the
A function signature must declare the number and type of parameters the
function has. Macros, on the other hand, can take a variable number of
parameters: we can call `println!("hello")` with one argument, or
parameters: we can call `println!("hello")` with one argument or
`println!("hello {}", name)` with two arguments. Also, macros are expanded
before the compiler interprets the meaning of the code, so a macro can, for
example, implement a trait on a given type. A function cant, because it gets
called at runtime and a trait needs to be implemented at compile time.
The downside to implementing a macro over a function is that macro definitions
are more complex than function definitions because youre writing Rust code
that writes Rust code. Due to this indirection, macro definitions are generally
more difficult to read, understand, and maintain than function definitions.
The downside to implementing a macro instead of a function is that macro
definitions are more complex than function definitions because youre writing
Rust code that writes Rust code. Due to this indirection, macro definitions are
generally more difficult to read, understand, and maintain than function
definitions.
Another difference between macros and functions is that macro definitions
arent namespaced within modules like function definitions are. In order to
prevent unexpected name clashes when using external crates, you have to
explicitly bring the macros into the scope of your project at the same time as
bringing the external crate into scope, using the `#[macro_use]` annotation.
The following example would bring all the macros defined in the `serde` crate
into the scope of the current crate:
arent namespaced within modules like function definitions are. To prevent
unexpected name clashes when using external crates, you have to explicitly
bring the macros into the scope of your project at the same time as you bring
the external crate into scope, using the `#[macro_use]` annotation. The
following example would bring all the macros defined in the `serde` crate into
the scope of the current crate:
```rust,ignore
#[macro_use]
@ -56,12 +58,12 @@ extern crate serde;
If `extern crate` was able to bring macros into scope by default without this
explicit annotation, you would be prevented from using two crates that happened
to define macros with the same name. In practice this conflict doesnt come up
much, but the more crates you use, the more likely it is.
to define macros with the same name. In practice, this conflict doesnt occur
often, but the more crates you use, the more likely it is.
One last important difference between macros and functions: macros must be
defined or brought into scope *before* theyre called in a file, whereas
functions can be defined anywhere and called anywhere.
There is one last important difference between macros and functions: you must
define or bring macros into scope *before* you call them in a file, whereas you
can define functions anywhere and call them anywhere.
### Declarative Macros with `macro_rules!` for General Metaprogramming
@ -72,15 +74,15 @@ something similar to a Rust `match` expression. As discussed in Chapter 6,
`match` expressions are control structures that take an expression, compare the
resulting value of the expression to patterns, and then run the code associated
with the matching pattern. Macros also compare a value to patterns that have
code associated with them, but in this case the value is the literal Rust
code associated with them; in this situation, the value is the literal Rust
source code passed to the macro, the patterns are compared with the structure
of that source code, and the code associated with each pattern is the code that
replaces the code passed to the macro. This all happens during compilation.
To define a macro, you use the `macro_rules!` construct. Lets explore how to
use `macro_rules!` by taking a look at how the `vec!` macro is defined. Chapter
8 covered how we can use the `vec!` macro to create a new vector with
particular values. For example, this macro creates a new vector with three
use `macro_rules!` by looking at how the `vec!` macro is defined. Chapter 8
covered how we can use the `vec!` macro to create a new vector with particular
values. For example, the following macro creates a new vector with three
integers inside:
```rust
@ -88,11 +90,11 @@ let v: Vec<u32> = vec![1, 2, 3];
```
We could also use the `vec!` macro to make a vector of two integers or a vector
of five string slices---we wouldnt be able to use a function to do the same
of five string slices. We wouldnt be able to use a function to do the same
because we wouldnt know the number or type of values up front.
Lets take a look at a slightly simplified definition of the `vec!` macro in
Listing AD-1:
Lets look at a slightly simplified definition of the `vec!` macro in Listing
D-1.
```rust
#[macro_export]
@ -109,33 +111,33 @@ macro_rules! vec {
}
```
Listing AD-1: A simplified version of the `vec!` macro definition
<span class="caption">Listing D-1: A simplified version of the `vec!` macro
definition</span>
> Note: the actual definition of the `vec!` macro in the standard library
> includes code to pre-allocate the correct amount of memory up-front. That
> code is an optimization that weve chosen not to include here to make the
> example simpler.
> Note: The actual definition of the `vec!` macro in the standard library
> includes code to preallocate the correct amount of memory up front. That code
> is an optimization that we dont include here to make the example simpler.
The `#[macro_export]` annotation indicates that this macro should be made
available whenever the crate in which were defining the macro is imported.
Without this annotation, even if someone depending on this crate uses the
`#[macro_use]` annotation, the macro would not be brought into scope.
`#[macro_use]` annotation, the macro wouldnt be brought into scope.
We then start the macro definition with `macro_rules!` and the name of the
macro were defining *without* the exclamation mark. The name---in this case
`vec`---is followed by curly brackets denoting the body of the macro definition.
macro were defining *without* the exclamation mark. The name, in this case
`vec`, is followed by curly brackets denoting the body of the macro definition.
The structure in the `vec!` body is similar to the structure of a `match`
expression. Here we have one arm with the pattern `( $( $x:expr ),* )`,
followed by `=>` and the block of code associated with this pattern. If the
pattern matches, the associated block of code will be emitted. Given that this
is the only pattern in this macro, theres only one valid way to match; any
is the only pattern in this macro, there is only one valid way to match; any
other will be an error. More complex macros will have more than one arm.
Valid pattern syntax in macro definitions is different than the pattern syntax
covered in Chapter 18 because macro patterns are matched against Rust code
structure rather than values. Lets walk through what the pieces of the pattern
in Listing AD-1 mean; for the full macro pattern syntax, see [the reference].
in Listing D-1 mean; for the full macro pattern syntax, see [the reference].
[the reference]: ../../reference/macros.html
@ -154,16 +156,11 @@ When we call this macro with `vec![1, 2, 3];`, the `$x` pattern matches three
times with the three expressions `1`, `2`, and `3`.
Now lets look at the pattern in the body of the code associated with this arm:
The `temp_vec.push()` code within the `$()*` part is generated for each part
the `temp_vec.push()` code within the `$()*` part is generated for each part
that matches `$()` in the pattern, zero or more times depending on how many
times the pattern matches. The `$x` is replaced with each expression matched.
When we call this macro with `vec![1, 2, 3];`, the code generated that replaces
this macro call will be:
<!-- Above What about temp_vec.push, do you want to quickly mention that? Or do
you mean "The `$()*` part and the content of the parentheses is generated for
each part that matches `$()` in the pattern"-->
<!-- The latter, I've tried to clarify /Carol -->
this macro call will be the following:
```rust,ignore
let mut temp_vec = Vec::new();
@ -176,10 +173,10 @@ temp_vec
Weve defined a macro that can take any number of arguments of any type and can
generate code to create a vector containing the specified elements.
Given that most Rust programmers will *use* macros more than *write* macros,
thats all well discuss about `macro_rules!` in this book. To learn more about
how to write macros, consult the online documentation or other resources such
as [The Little Book of Rust Macros][tlborm].
Given that most Rust programmers will *use* macros more than *write* macros, we
wont discuss `macro_rules!` any further. To learn more about how to write
macros, consult the online documentation or other resources, such as [“The
Little Book of Rust Macros][tlborm].
[tlborm]: https://danielkeep.github.io/tlborm/book/index.html
@ -188,22 +185,20 @@ as [The Little Book of Rust Macros][tlborm].
The second form of macros is called *procedural macros* because theyre more
like functions (which are a type of procedure). Procedural macros accept some
Rust code as an input, operate on that code, and produce some Rust code as an
output, rather than matching against patterns and replacing the code with other
code as declarative macros do. At the time of writing, you can only really
define procedural macros to allow your traits to be implemented on a type by
output rather than matching against patterns and replacing the code with other
code as declarative macros do. At the time of this writing, you can only define
procedural macros to allow your traits to be implemented on a type by
specifying the trait name in a `derive` annotation.
Were going to create a crate named `hello_macro` that defines a trait named
Well create a crate named `hello_macro` that defines a trait named
`HelloMacro` with one associated function named `hello_macro`. Rather than
making users of our crate implement the `HelloMacro` trait for each of their
making our crate users implement the `HelloMacro` trait for each of their
types, well provide a procedural macro so users can annotate their type with
`#[derive(HelloMacro)]` to get a default implementation of the `hello_macro`
function. The default implementation will print `Hello, Macro! My name is
TypeName!` where `TypeName` is the name of the type on which this trait has
been defined.
In other words, were going to write a crate that enables another programmer to
write code like Listing AD-2 using our crate:
been defined. In other words, well write a crate that enables another
programmer to write code like Listing D-2 using our crate.
<span class="filename">Filename: src/main.rs</span>
@ -222,17 +217,17 @@ fn main() {
}
```
<span class="caption">Listing AD-2: The code a user of our crate will be able
to write with use of our procedural macro</span>
<span class="caption">Listing D-2: The code a user of our crate will be able to
write when using our procedural macro</span>
This code will print `Hello, Macro! My name is Pancakes!` when were done. Lets
get started! First we need to make a new library crate:
This code will print `Hello, Macro! My name is Pancakes!` when were done. The
first step is to make a new library crate, like this:
```text
$ cargo new hello_macro --lib
```
Now well define the `HelloMacro` trait and its associated function:
Next, well define the `HelloMacro` trait and its associated function:
<span class="filename">Filename: src/lib.rs</span>
@ -242,9 +237,8 @@ pub trait HelloMacro {
}
```
We have a trait and its function. At this point, a user of our crate would be
able to implement the trait themselves to achieve the desired functionality,
like so:
We have a trait and its function. At this point, our crate user could implement
the trait to achieve the desired functionality, like so:
```rust,ignore
extern crate hello_macro;
@ -264,24 +258,21 @@ fn main() {
}
```
However, they would need to write out the implementation block for each type
they wanted to use with `hello_macro`; wed like to save them this work.
However, they would need to write the implementation block for each type they
wanted to use with `hello_macro`; we want to spare them from having to do this
work.
Additionally, we cant yet provide a default implementation for the
`hello_macro` function that will print out the name of the type the trait is
implemented on: Rust doesnt have reflection capabilities, so cant look up the
types name at runtime. We need a macro to generate code at compile time.
`hello_macro` function that will print the name of the type the trait is
implemented on: Rust doesnt have reflection capabilities, so it cant look up
the types name at runtime. We need a macro to generate code at compile time.
<!--Defining Procedural Macros Requires a Separate Crate--> <!-- Since this is
a lone subheading, okay to merge with the general procedural macros section? -->
<!-- Sure /Carol -->
The next step is to define the procedural macro. At the time of writing,
The next step is to define the procedural macro. At the time of this writing,
procedural macros need to be in their own crate. Eventually, this restriction
may be lifted. The convention for structuring crates and macro crates is as
such: for a crate named `foo`, a custom derive procedural macro crate is called
`foo-derive`. Lets start a new crate called `hello_macro_derive` inside our
`hello_macro` project:
might be lifted. The convention for structuring crates and macro crates is as
follows: for a crate named `foo`, a custom derive procedural macro crate is
called `foo_derive`. Lets start a new crate called `hello_macro_derive` inside
our `hello_macro` project:
```text
$ cargo new hello_macro_derive --lib
@ -291,15 +282,15 @@ Our two crates are tightly related, so we create the procedural macro crate
within the directory of our `hello_macro` crate. If we change the trait
definition in `hello_macro`, well have to change the implementation of the
procedural macro in `hello_macro_derive` as well. The two crates will need to
be published separately, though, and programmers using these crates will need
to add both as dependencies and bring them both into scope. We could instead
have the `hello_macro` crate use `hello_macro_derive` as a dependency and
re-export the procedural macro code, but the way weve structured the project
makes it possible for programmers to use `hello_macro` even if they dont want
the `derive` functionality.
be published separately, and programmers using these crates will need to add
both as dependencies and bring them both into scope. We could instead have the
`hello_macro` crate use `hello_macro_derive` as a dependency and reexport the
procedural macro code. But the way weve structured the project makes it
possible for programmers to use `hello_macro` even if they dont want the
`derive` functionality.
We need to declare the `hello_macro_derive` crate as a procedural macro crate.
Well also need functionality from the `syn` and `quote` crates, as well see
Well also need functionality from the `syn` and `quote` crates, as youll see
in a moment, so we need to add them as dependencies. Add the following to the
*Cargo.toml* file for `hello_macro_derive`:
@ -314,16 +305,10 @@ syn = "0.11.11"
quote = "0.3.15"
```
To start defining the procedural macro, place the code from Listing AD-3 in
your *src/lib.rs* for the `hello_macro_derive` crate. Note that this wont
To start defining the procedural macro, place the code in Listing D-3 into your
*src/lib.rs* file for the `hello_macro_derive` crate. Note that this code wont
compile until we add a definition for the `impl_hello_macro` function.
Note the way weve split the functions in AD-3; this will be the same for
almost every procedural macro crate you see or create, as it makes writing a
procedural macro more convenient. What you choose to do in the place where the
`impl_hello_macro` function is called will be different depending on the
purpose of your procedural macro.
<span class="filename">Filename: hello_macro_derive/src/lib.rs</span>
```rust,ignore
@ -350,10 +335,16 @@ pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
}
```
<span class="caption">Listing AD-3: Code that most procedural macro crates will
<span class="caption">Listing D-3: Code that most procedural macro crates will
need to have for processing Rust code</span>
We have introduced three new crates: `proc_macro`, [`syn`], and [`quote`]. The
Notice the way weve split the functions in D-3; this will be the same for
almost every procedural macro crate you see or create, because it makes writing
a procedural macro more convenient. What you choose to do in the place where
the `impl_hello_macro` function is called will be different depending on your
procedural macros purpose.
Weve introduced three new crates: `proc_macro`, [`syn`], and [`quote`]. The
`proc_macro` crate comes with Rust, so we didnt need to add that to the
dependencies in *Cargo.toml*. The `proc_macro` crate allows us to convert Rust
code into a string containing that Rust code. The `syn` crate parses Rust code
@ -366,29 +357,24 @@ to handle: writing a full parser for Rust code is no simple task.
[`quote`]: https://crates.io/crates/quote
The `hello_macro_derive` function will get called when a user of our library
specifies `#[derive(HelloMacro)]` on a type, because weve annotated the
`hello_macro_derive` function here with `proc_macro_derive` and specified the
name, `HelloMacro`, which matches our trait name; thats the convention most
procedural macros follow.
specifies `#[derive(HelloMacro)]` on a type. The reason is that weve annotated
the `hello_macro_derive` function here with `proc_macro_derive` and specified
the name, `HelloMacro`, which matches our trait name; thats the convention
most procedural macros follow.
This function first converts the `input` from a `TokenStream` to a `String` by
calling `to_string`. This `String` is a string representation of the Rust code
for which we are deriving `HelloMacro`. In the example in Listing AD-2, `s`
will have the `String` value `struct Pancakes;` because thats the Rust code we
for which we are deriving `HelloMacro`. In the example in Listing D-2, `s` will
have the `String` value `struct Pancakes;` because that is the Rust code we
added the `#[derive(HelloMacro)]` annotation to.
<!-- I'm not sure why we convert to a string then to a structure we can use,
will that be clear to the reader here? -->
<!-- This is just how procedural macros work and what you have to do, which is
why we have the next note. /Carol -->
> Note: At the time of this writing, you can only convert a `TokenStream` to a
> string. A richer API will exist in the future.
> Note: At the time of writing, the only thing you can do with a `TokenStream`
> is convert it to a string. A richer API will exist in the future.
Now we need to be able to parse the Rust code `String` into a data structure
that we can then interpret and perform operations on. This is where `syn` comes
to play. The `parse_derive_input` function in `syn` takes a `String` and
returns a `DeriveInput` struct representing the parsed Rust code. The following
Now we need to parse the Rust code `String` into a data structure that we can
then interpret and perform operations on. This is where `syn` comes into play.
The `parse_derive_input` function in `syn` takes a `String` and returns a
`DeriveInput` struct representing the parsed Rust code. The following code
shows the relevant parts of the `DeriveInput` struct we get from parsing the
string `struct Pancakes;`:
@ -408,29 +394,29 @@ DeriveInput {
The fields of this struct show that the Rust code weve parsed is a unit struct
with the `ident` (identifier, meaning the name) of `Pancakes`. There are more
fields on this struct for describing all sorts of Rust code; check the [`syn`
API docs for `DeriveInput`][syn-docs] for more information.
documentation for `DeriveInput`][syn-docs] for more information.
[syn-docs]: https://docs.rs/syn/0.11.11/syn/struct.DeriveInput.html
At this point we havent defined the `impl_hello_macro` function, which is
where well build the new Rust code we want to include. Before we get to that,
the last part of this `hello_macro_derive` function is using the `parse`
At this point, we havent defined the `impl_hello_macro` function, which is
where well build the new Rust code we want to include. But before we do, note
that the last part of this `hello_macro_derive` function uses the `parse`
function from the `quote` crate to turn the output of the `impl_hello_macro`
function back into a `TokenStream`. The returned `TokenStream` is added to the
code that users of our crate write so that when they compile their crate, they
get extra functionality we provide.
code that our crate users write, so when they compile their crate, theyll get
extra functionality that we provide.
You may have noticed that were calling `unwrap` to panic if the calls to the
You might have noticed that were calling `unwrap` to panic if the calls to the
`parse_derive_input` or `parse` functions fail here. Panicking on errors is
necessary in procedural macro code because `proc_macro_derive` functions must
return `TokenStream` rather than `Result` in order to conform to the procedural
macro API. Weve chosen to keep this example simple by using `unwrap`; in
production code you should provide more specific error messages about what went
wrong by using `expect` or `panic!`.
return `TokenStream` rather than `Result` to conform to the procedural macro
API. Weve chosen to simplify this example by using `unwrap`; in production
code, you should provide more specific error messages about what went wrong by
using `panic!` or `expect`.
Now that we have the code to turn the annotated Rust code from a `TokenStream`
into a `String` and a `DeriveInput` instance, lets generate the code
implementing the `HelloMacro` trait on the annotated type:
into a `String` and a `DeriveInput` instance, lets generate the code that
implements the `HelloMacro` trait on the annotated type:
<span class="filename">Filename: hello_macro_derive/src/lib.rs</span>
@ -448,12 +434,12 @@ fn impl_hello_macro(ast: &syn::DeriveInput) -> quote::Tokens {
```
We get an `Ident` struct instance containing the name (identifier) of the
annotated type using `ast.ident`. With the code from Listing AD-2, `name` will
be `Ident("Pancakes")`.
annotated type using `ast.ident`. The code in Listing D-2 specifies that the
`name` will be `Ident("Pancakes")`.
The `quote!` macro lets us write up the Rust code that we want to return and
convert it into `quote::Tokens`. This macro also provides some really cool
templating mechanics; we can write `#name` and `quote!` will replace it with
The `quote!` macro lets us write the Rust code that we want to return and
convert it into `quote::Tokens`. This macro also provides some very cool
templating mechanics; we can write `#name`, and `quote!` will replace it with
the value in the variable named `name`. You can even do some repetition similar
to the way regular macros work. Check out [the `quote` crates
docs][quote-docs] for a thorough introduction.
@ -470,18 +456,18 @@ The `stringify!` macro used here is built into Rust. It takes a Rust
expression, such as `1 + 2`, and at compile time turns the expression into a
string literal, such as `"1 + 2"`. This is different than `format!` or
`println!`, which evaluate the expression and then turn the result into a
`String`. Theres a possibility that the `#name` input might be an expression
to print out literally so we use `stringify!`. Using `stringify!` also saves an
`String`. There is a possibility that the `#name` input might be an expression
to print literally, so we use `stringify!`. Using `stringify!` also saves an
allocation by converting `#name` to a string literal at compile time.
At this point, `cargo build` should complete successfully in both `hello_macro`
and `hello_macro_derive`. Lets hook these crates up to the code in Listing
AD-2 to see it in action! Create a new binary project in your `projects`
directory with `cargo new --bin pancakes`. We need to add both `hello_macro`
and `hello_macro_derive` as dependencies in the `pancakes` crates
*Cargo.toml*. If youve chosen to publish your versions of `hello_macro` and
`hello_macro_derive` to *https://crates.io* they would be regular dependencies;
if not, you can specify them as `path` dependencies as follows:
and `hello_macro_derive`. Lets hook up these crates to the code in Listing D-2
to see the procedural macro in action! Create a new binary project in your
*projects* directory using `cargo new pancakes`. We need to add
`hello_macro` and `hello_macro_derive` as dependencies in the `pancakes`
crates *Cargo.toml*. If youre publishing your versions of `hello_macro` and
`hello_macro_derive` to *https://crates.io/*, they would be regular
dependencies; if not, you can specify them as `path` dependencies as follows:
```toml
[dependencies]
@ -489,16 +475,16 @@ hello_macro = { path = "../hello_macro" }
hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }
```
Put the code from Listing AD-2 into *src/main.rs*, and when you run `cargo run`
it should print `Hello, Macro! My name is Pancakes!` The implementation of the
Put the code from Listing D-2 into *src/main.rs*, and run `cargo run`: it
should print `Hello, Macro! My name is Pancakes!` The implementation of the
`HelloMacro` trait from the procedural macro was included without the
`pancakes` crate needing to implement it; the `#[derive(HelloMacro)]` took care
of adding the trait implementation.
`pancakes` crate needing to implement it; the `#[derive(HelloMacro)]` added the
trait implementation.
### The Future of Macros
In the future, well be expanding both declarative and procedural macros. Rust
will use better declarative macro system with the `macro` keyword, and well
add more types of procedural macros, for more powerful tasks than just
`derive`. These systems are still under development at the time of publication;
In the future, Rust will expand declarative and procedural macros. Rust will
use a better declarative macro system with the `macro` keyword and will add
more types of procedural macros for more powerful tasks than just `derive`.
These systems are still under development at the time of this publication;
please consult the online Rust documentation for the latest information.

View File

@ -11,7 +11,7 @@ For resources in languages other than English. Most are still in progress; see
- [简体中文](http://www.broadview.com.cn/article/144), [alternate](https://github.com/KaiserY/trpl-zh-cn)
- [Українська](https://github.com/pavloslav/rust-book-uk-ua)
- [Español](https://github.com/thecodix/book)
- [Italiano](https://github.com/CodelessFuture/trpl2-it)
- [Italiano](https://github.com/AgeOfWar/rust-book-it)
- [Русский](https://github.com/iDeBugger/rust-book-ru)
- [한국어](https://github.com/rinthel/rust-lang-book-ko)
- [日本語](https://github.com/hazama-yuinyan/book)

View File

@ -1,128 +0,0 @@
# Appendix F - Newest Features
This appendix documents features that have been added to stable Rust since the
main part of the book was completed.
## Field init shorthand
We can initialize a data structure (struct, enum, union) with named
fields, by writing `fieldname` as a shorthand for `fieldname: fieldname`.
This allows a compact syntax for initialization, with less duplication:
```rust
#[derive(Debug)]
struct Person {
name: String,
age: u8,
}
fn main() {
let name = String::from("Peter");
let age = 27;
// Using full syntax:
let peter = Person { name: name, age: age };
let name = String::from("Portia");
let age = 27;
// Using field init shorthand:
let portia = Person { name, age };
println!("{:?}", portia);
}
```
## Returning from loops
One of the uses of a `loop` is to retry an operation you know can fail, such as
checking if a thread completed its job. However, you might need to pass the
result of that operation to the rest of your code. If you add it to the `break`
expression you use to stop the loop, it will be returned by the broken loop:
```rust
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
assert_eq!(result, 20);
}
```
## Nested groups in `use` declarations
If you have a complex module tree with many different submodules and you need
to import a few items from each one, it might be useful to group all the
imports in the same declaration to keep your code clean and avoid repeating the
base modules name.
The `use` declaration supports nesting to help you in those cases, both with
simple imports and glob ones. For example this snippets imports `bar`, `Foo`,
all the items in `baz` and `Bar`:
```rust
# #![allow(unused_imports, dead_code)]
#
# mod foo {
# pub mod bar {
# pub type Foo = ();
# }
# pub mod baz {
# pub mod quux {
# pub type Bar = ();
# }
# }
# }
#
use foo::{
bar::{self, Foo},
baz::{*, quux::Bar},
};
#
# fn main() {}
```
## Inclusive ranges
Previously, when a range (`..` or `...`) was used as an expression, it had to be
`..`, which is exclusive of the upper bound, while patterns had to use `...`,
which is inclusive of the upper bound. Now, `..=` is accepted as syntax for
inclusive ranges in both expression and range context:
```rust
fn main() {
for i in 0 ..= 10 {
match i {
0 ..= 5 => println!("{}: low", i),
6 ..= 10 => println!("{}: high", i),
_ => println!("{}: out of range", i),
}
}
}
```
The `...` syntax is still accepted in matches, but it is not accepted in
expressions. `..=` should be preferred.
## 128-bit integers
Rust 1.26.0 added 128-bit integer primitives:
- `u128`: A 128-bit unsigned integer with range [0, 2^128 - 1]
- `i128`: A 128-bit signed integer with range [-(2^127), 2^127 - 1]
These primitives are implemented efficiently via LLVM support. They are
available even on platforms that dont natively support 128-bit integers and
can be used like the other integer types.
These primitives can be very useful for algorithms that need to use very large
integers efficiently, such as certain cryptographic algorithms.

View File

@ -1,10 +1,7 @@
# Appendix G - How Rust is Made and “Nightly Rust”
# Appendix F - How Rust is Made and “Nightly Rust”
This appendix is about how Rust is made and how that affects you as a Rust
developer. We mentioned that the output in this book was generated by stable
Rust 1.21.0, but any examples that compile should continue to compile in any
stable version of Rust greater than that. This section is to explain how we
ensure this is true!
developer.
### Stability Without Stagnation
@ -150,7 +147,7 @@ $ rustup install nightly
You can see all of the *toolchains* (releases of Rust and associated
components) you have installed with `rustup` as well. Heres an example on one
of your authors computers:
of your authors Windows computer:
```powershell
> rustup toolchain list

View File

@ -1,7 +1,13 @@
# Introduction
Welcome to *The Rust Programming Language*, an introductory book about Rust.
> Note: This edition of the book is the same as [The Rust Programming
> Language][nsprust] available in print and ebook format from [No Starch
> Press][nsp].
[nsprust]: https://nostarch.com/rust
[nsp]: https://nostarch.com/
Welcome to *The Rust Programming Language*, an introductory book about Rust.
The Rust programming language helps you write faster, more reliable software.
High-level ergonomics and low-level control are often at odds in programming
language design; Rust challenges that conflict. Through balancing powerful
@ -18,11 +24,11 @@ the most important groups.
Rust is proving to be a productive tool for collaborating among large teams of
developers with varying levels of systems programming knowledge. Low-level code
is prone to a variety of subtle bugs, which in most other languages can only be
caught through extensive testing and careful code review by experienced
is prone to a variety of subtle bugs, which in most other languages can be
caught only through extensive testing and careful code review by experienced
developers. In Rust, the compiler plays a gatekeeper role by refusing to
compile code with these elusive bugs, including concurrency bugs. By working
alongside the compiler, the team can spend more time focusing on the programs
alongside the compiler, the team can spend their time focusing on the programs
logic rather than chasing down bugs.
Rust also brings contemporary developer tools to the systems programming world:
@ -51,7 +57,7 @@ programming.
Hundreds of companies, large and small, use Rust in production for a variety of
tasks. Those tasks include command line tools, web services, DevOps tooling,
embedded devices, audio and video analysis and transcoding, cryptocurrencies,
bioinformatics, search engines, internet of things applications, machine
bioinformatics, search engines, Internet of Things applications, machine
learning, and even major parts of the Firefox web browser.
### Open Source Developers
@ -65,18 +71,17 @@ language.
Rust is for people who crave speed and stability in a language. By speed, we
mean the speed of the programs that you can create with Rust and the speed at
which Rust lets you write them. The Rust compilers checks ensure stability
through feature additions and refactoring as opposed to brittle legacy code in
languages without these checks that developers are afraid to modify. By
striving for zero-cost abstractions, higher-level features that compile to
lower-level code as fast as code written manually, Rust endeavors to make safe
code be fast code as well.
through feature additions and refactoring. This is in contrast to the brittle
legacy code in languages without these checks, which developers are often
afraid to modify. By striving for zero-cost abstractions, higher-level features
that compile to lower-level code as fast as code written manually, Rust
endeavors to make safe code be fast code as well.
Although weve not provided a complete list of everyone the Rust language hopes
to support, those we have mentioned are some of the biggest stakeholders.
Overall, Rusts greatest ambition is to eliminate the dichotomy of the
trade-offs that programmers have accepted for decades: safety *and*
productivity, speed *and* ergonomics. Give Rust a try, and see if its choices
work for you.
The Rust language hopes to support many other users as well; those mentioned
here are merely some of the biggest stakeholders. Overall, Rusts greatest
ambition is to eliminate the trade-offs that programmers have accepted for
decades by providing safety *and* productivity, speed *and* ergonomics. Give
Rust a try and see if its choices work for you.
## Who This Book Is For
@ -99,16 +104,17 @@ chapters. In concept chapters, youll learn about an aspect of Rust. In projec
chapters, well build small programs together, applying what youve learned so
far. Chapters 2, 12, and 20 are project chapters; the rest are concept chapters.
Additionally, Chapter 2 is a hands-on introduction to the Rust language. Well
cover concepts at a high level, and later chapters will provide additional
detail. If you want to get your hands dirty right away, Chapter 2 is the one
for that. At first, you might even want to skip Chapter 3, which covers Rust
features similar to other programming language features, and head straight to
Chapter 4 to learn about Rusts ownership system. However, if youre a
particularly meticulous learner who prefers to learn every detail before moving
onto the next, you might want to skip Chapter 2 and go straight to Chapter 3,
returning to Chapter 2 when youd like to work on a project applying those
details.
Chapter 1 explains how to install Rust, how to write a Hello, world! program,
and how to use Cargo, Rusts package manager and build tool. Chapter 2 is a
hands-on introduction to the Rust language. Here we cover concepts at a high
level, and later chapters will provide additional detail. If you want to get
your hands dirty right away, Chapter 2 is the place for that. At first, you
might even want to skip Chapter 3, which covers Rust features similar to those
of other programming languages, and head straight to Chapter 4 to learn about
Rusts ownership system. However, if youre a particularly meticulous learner
who prefers to learn every detail before moving on to the next, you might want
to skip Chapter 2 and go straight to Chapter 3, returning to Chapter 2 when
youd like to work on a project applying the details youve learned.
Chapter 5 discusses structs and methods, and Chapter 6 covers enums, `match`
expressions, and the `if let` control flow construct. Youll use structs and
@ -118,15 +124,15 @@ In Chapter 7, youll learn about Rusts module system and about privacy rule
for organizing your code and its public Application Programming Interface
(API). Chapter 8 discusses some common collection data structures that the
standard library provides, such as vectors, strings, and hash maps. Chapter 9
explores Rusts error handling philosophy and techniques.
explores Rusts error-handling philosophy and techniques.
Chapter 10 digs into generics, traits, and lifetimes, which give you the power
to define code that applies to multiple types. Chapter 11 is all about testing,
which is still necessary even with Rusts safety guarantees to ensure your
programs logic is correct. In Chapter 12, well build our own implementation
of a subset of functionality from the `grep` command line tool that searches
for text within files. For this, well use many of the concepts we discussed in
the previous chapters.
which even with Rusts safety guarantees is necessary to ensure your programs
logic is correct. In Chapter 12, well build our own implementation of a subset
of functionality from the `grep` command line tool that searches for text
within files. For this, well use many of the concepts we discussed in the
previous chapters.
Chapter 13 explores closures and iterators: features of Rust that come from
functional programming languages. In Chapter 14, well examine Cargo in more
@ -136,7 +142,7 @@ traits that enable their functionality.
In Chapter 16, well walk through different models of concurrent programming
and talk about how Rust helps you to program in multiple threads fearlessly.
Chapter 17 looks at how Rust idioms compare to object oriented programming
Chapter 17 looks at how Rust idioms compare to object-oriented programming
principles you might be familiar with.
Chapter 18 is a reference on patterns and pattern matching, which are powerful
@ -148,9 +154,9 @@ In Chapter 20, well complete a project in which well implement a low-level
multithreaded web server!
Finally, some appendixes contain useful information about the language in a
more reference-like format. Appendix A covers Rusts keywords. Appendix B
covers Rusts operators and symbols. Appendix C covers derivable traits
provided by the standard library. Appendix D covers macros.
more reference-like format. Appendix A covers Rusts keywords, Appendix B
covers Rusts operators and symbols, Appendix C covers derivable traits
provided by the standard library, and Appendix D covers macros.
There is no wrong way to read this book: if you want to skip ahead, go for it!
You might have to jump back to earlier chapters if you experience any
@ -158,9 +164,9 @@ confusion. But do whatever works for you.
An important part of the process of learning Rust is learning how to read the
error messages the compiler displays: these will guide you toward working code.
As such, well provide many examples of code that dont compile along with the
error message the compiler will show you in each situation. Know that if you
enter and run a random example, it may not compile! Make sure you read the
As such, well provide many examples of code that doesnt compile along with
the error message the compiler will show you in each situation. Know that if
you enter and run a random example, it may not compile! Make sure you read the
surrounding text to see whether the example youre trying to run is meant to
error. In most situations, well lead you to the correct version of any code
that doesnt compile.
@ -170,4 +176,4 @@ that doesnt compile.
The source files from which this book is generated can be found on
[GitHub][book].
[book]: https://github.com/rust-lang/book/tree/master/2018-edition/src
[book]: https://github.com/rust-lang/book/tree/master/second-edition/src

View File

@ -1,12 +1,8 @@
# Getting Started
<!-- If you want to use this paragraph in the Introduction, can you replace it
with some other introductory text for the chapter here? Maybe just lay out
what's in this chapter so they know it's important not to skip it. -->
<!-- Yep, done! /Carol -->
Lets start your Rust journey! Theres a lot to learn, but every journey starts
somewhere. In this chapter, well discuss:
Lets get your Rust journey started! In this chapter, well discuss:
- Installing Rust on Linux, Mac, or Windows
- Writing a program that prints “Hello, world!”
- Using `cargo`, Rusts package manager and build system
* Installing Rust on Linux, macOS, and Windows
* Writing a program that prints `Hello, world!`
* Using `cargo`, Rusts package manager and build system

View File

@ -1,110 +1,96 @@
## Installation
The first step to using Rust is to install it. Well download Rust through
`rustup`, a command-line tool for managing Rust versions and associated tools.
For this youll need an internet connection.
The first step is to install Rust. Well download Rust through `rustup`, a
command line tool for managing Rust versions and associated tools. Youll need
an internet connection for the download.
The following steps will install the latest stable version of the Rust
compiler. The examples and output shown in this book all use stable Rust
1.21.0. Rusts stability guarantees ensure that all of the examples in the book
that compile will continue to compile with newer versions of Rust. The output
may differ slightly between versions, as error messages and warnings are often
improved. In other words, any newer, stable version of Rust you will install
with these steps should work as expected with the content of this book.
> Note: If you prefer not to use `rustup` for some reason, please see [the Rust
> installation page](https://www.rust-lang.org/install.html) for other options.
<!-- PROD: Start Box -->
The following steps install the latest stable version of the Rust compiler.
Rusts stability guarantees ensure that all the examples in the book that
compile will continue to compile with newer Rust versions. The output might
differ slightly between versions, because Rust often improves error messages
and warnings. In other words, any newer, stable version of Rust you install
using these steps should work as expected with the content of this book.
> #### Command Line Notation
> ### Command Line Notation
>
> In this chapter and throughout the book well be showing some commands used
> in the terminal. Lines that should be entered in a terminal all start with
> `$`. You dont need to type in the `$` character, it is simply there to
> indicate the start of each command. Many tutorials use this convention: `$`
> for commands run as a regular user, and `#` for commands you should be
> running as an administrator. Lines that dont start with `$` are typically
> showing the output of the previous command. Additionally, PowerShell specific
> examples will use `>` rather than `$`.
> In this chapter and throughout the book, well show some commands used in the
> terminal. Lines that you should enter in a terminal all start with `$`. You
> dont need to type in the `$` character; it indicates the start of each
> command. Lines that dont start with `$` typically show the output of the
> previous command. Additionally, PowerShell-specific examples will use `>`
> rather than `$`.
<!-- PROD: End box -->
### Installing `rustup` on Linux or macOS
### Installing Rustup on Linux or Mac
If youre on Linux or a Mac, open a terminal and enter the following command:
If youre using Linux or macOS, open a terminal and enter the following command:
```text
$ curl https://sh.rustup.rs -sSf | sh
```
This will download a script and start the installation of the `rustup` tool,
which installs the latest stable version of Rust. You may be prompted for your
password. If it all goes well, youll see this appear:
The command downloads a script and starts the installation of the `rustup`
tool, which installs the latest stable version of Rust. You might be prompted
for your password. If the install is successful, the following line will appear:
```text
Rust is installed now. Great!
```
Of course, if you distrust using `curl URL | sh` to install software, you can
download, inspect, and run the script however you like.
If you prefer, feel free to download the script and inspect it before running
it.
The installation script automatically adds Rust to your system PATH after your
next login. If you want to start using Rust right away instead of restarting
your terminal, run the following command in your shell to add Rust to your
system PATH manually:
<!-- what does this command do? Do you mean instead of logging out and logging
in, enter the following? -->
<!-- It runs a script that adds Rust to your system PATH manually. I've
clarified that yes, this is instead of logging out and back in to your
terminal. /Carol -->
```text
$ source $HOME/.cargo/env
```
Alternatively, you can add the following line to your `~/.bash_profile`:
Alternatively, you can add the following line to your *~/.bash_profile*:
```text
$ export PATH="$HOME/.cargo/bin:$PATH"
```
Finally, youll need a linker of some kind. Its likely you already have one
installed, but if you try to compile a Rust program and get errors telling you
that a linker could not be executed, youll need to install one. You can
install a C compiler, as that will usually come with the correct linker. Check
your platforms documentation for how to install a C compiler. Some common Rust
packages depend on C code and will need a C compiler too, so it may be worth
installing one now regardless.
Additionally, youll need a linker of some kind. Its likely one is already
installed, but when you try to compile a Rust program and get errors indicating
that a linker could not execute, that means a linker isnt installed on your
system and youll need to install one manually. C compilers usually come with
the correct linker. Check your platforms documentation for how to install a C
compiler. Also, some common Rust packages depend on C code and will need a C
compiler. Therefore, it might be worth installing one now.
### Installing Rustup on Windows
### Installing `rustup` on Windows
On Windows, go to [https://www.rust-lang.org/en-US/install.html][install] and
follow the instructions for installing Rust. At some point in the installation
youll receive a message telling you youll also need the C++ build tools for
On Windows, go to [https://www.rust-lang.org/install.html][install] and follow
the instructions for installing Rust. At some point in the installation, youll
receive a message explaining that youll also need the C++ build tools for
Visual Studio 2013 or later. The easiest way to acquire the build tools is to
install [Build Tools for Visual Studio 2017][visualstudio], found in the Other
Tools and Frameworks section.
install [Build Tools for Visual Studio 2017][visualstudio]. The tools are in
the Other Tools and Frameworks section.
[install]: https://www.rust-lang.org/en-US/install.html
[install]: https://www.rust-lang.org/install.html
[visualstudio]: https://www.visualstudio.com/downloads/
The rest of this book will use commands that work in both `cmd.exe` and
PowerShell. If there are specific differences, well explain which to use.
### Custom Installations Without Rustup
If you have reasons for preferring not to use `rustup`, please see [the Rust
installation page](https://www.rust-lang.org/install.html) for other options.
The rest of this book uses commands that work in both *cmd.exe* and PowerShell.
If there are specific differences, well explain which to use.
### Updating and Uninstalling
Once you have Rust installed via `rustup`, updating to the latest version is
easy. From your shell, run the update script:
After youve installed Rust via `rustup`, updating to the latest version is
easy. From your shell, run the following update script:
```text
$ rustup update
```
To uninstall Rust and `rustup`, from your shell, run the uninstall script:
To uninstall Rust and `rustup`, run the following uninstall script from your
shell:
```text
$ rustup self uninstall
@ -112,31 +98,28 @@ $ rustup self uninstall
### Troubleshooting
To check whether you have Rust installed correctly, open up a shell and enter:
To check whether you have Rust installed correctly, open a shell and enter this
line:
```text
$ rustc --version
```
You should see the version number, commit hash, and commit date for the latest
stable version at the time you install in the following format:
stable version that has been released in the following format:
```text
rustc x.y.z (abcabcabc yyyy-mm-dd)
```
If you see this, Rust has been installed successfully! Congrats!
If you dont and youre on Windows, check that Rust is in your `%PATH%` system
variable.
If thats all correct and Rust still isnt working, there are a number of
places you can get help. The easiest is [the #rust IRC channel on
If you see this information, you have installed Rust successfully! If you dont
see this information and youre on Windows, check that Rust is in your `%PATH%`
system variable. If thats all correct and Rust still isnt working, there are
a number of places you can get help. The easiest is [the #rust IRC channel on
irc.mozilla.org][irc]<!-- ignore -->, which you can access through
[Mibbit][mibbit]. Go to that address, and youll be chatting with other
Rustaceans (a silly nickname we call ourselves) who can help you out. Other
great resources include [the Users forum][users] and [Stack
Overflow][stackoverflow].
[Mibbit][mibbit]. At that address you can chat with other Rustaceans (a silly
nickname we call ourselves) who can help you out. Other great resources include
[the Users forum][users] and [Stack Overflow][stackoverflow].
[irc]: irc://irc.mozilla.org/#rust
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
@ -149,6 +132,6 @@ The installer also includes a copy of the documentation locally, so you can
read it offline. Run `rustup doc` to open the local documentation in your
browser.
Any time theres a type or function provided by the standard library and youre
not sure what it does or how to use it, use the API (Application Programming
Interface) documentation to find out!
Any time a type or function is provided by the standard library and youre not
sure what it does or how to use it, use the application programming interface
(API) documentation to find out!

View File

@ -1,28 +1,28 @@
## Hello, World!
Now that you have Rust installed, lets write your first Rust program. Its
traditional when learning a new language to write a little program to print the
text “Hello, world!” to the screen, so well do the same here!
Now that youve installed Rust, lets write your first Rust program. Its
traditional when learning a new language to write a little program that prints
the text `Hello, world!` to the screen, so well do the same here!
> Note: This book assumes basic familiarity with the command line. Rust itself
> makes no specific demands about your editing, tooling, or where your code
> lives, so if you prefer an IDE (Integrated Development Environment) to the
> command line, feel free to use your favorite IDE. Many IDEs now have some
> degree of Rust support; check the IDEs documentation for details. Enabling
> great IDE support has been a recent focus of the Rust team, and progress
> Note: This book assumes basic familiarity with the command line. Rust makes
> no specific demands about your editing or tooling or where your code lives, so
> if you prefer to use an integrated development environment (IDE) instead of
> the command line, feel free to use your favorite IDE. Many IDEs now have some
> degree of Rust support; check the IDEs documentation for details. Recently,
> the Rust team has been focusing on enabling great IDE support, and progress
> has been made rapidly on that front!
### Creating a Project Directory
First, make a directory to put your Rust code in. Rust doesnt care where your
code lives, but for the exercises and projects in this book, wed suggest
making a *projects* directory in your home directory and keeping all your
projects there.
Youll start by making a directory to store your Rust code. It doesnt matter
to Rust where your code lives, but for the exercises and projects in this book,
we suggest making a *projects* directory in your home directory and keeping all
your projects there.
Open a terminal and enter the following commands to make a *projects* directory
and, inside that, a directory for this “Hello, world!” project:
and a directory for the Hello, world! project within the *projects* directory.
Linux and Mac:
For Linux and macOS, enter this:
```text
$ mkdir ~/projects
@ -31,7 +31,7 @@ $ mkdir hello_world
$ cd hello_world
```
Windows CMD:
For Windows CMD, enter this:
```cmd
> mkdir "%USERPROFILE%\projects"
@ -40,7 +40,7 @@ Windows CMD:
> cd hello_world
```
Windows PowerShell:
For Windows PowerShell, enter this:
```powershell
> mkdir $env:USERPROFILE\projects
@ -51,13 +51,12 @@ Windows PowerShell:
### Writing and Running a Rust Program
Next, make a new source file and call it *main.rs*---Rust files always end with
Next, make a new source file and call it *main.rs*. Rust files always end with
the *.rs* extension. If youre using more than one word in your filename, use
an underscore to separate them. For example, youd use *hello_world.rs* rather
than *helloworld.rs*.
an underscore to separate them. For example, use *hello_world.rs* rather than
*helloworld.rs*.
Now open the *main.rs* file you just created, and enter the code shown in
Listing 1-1:
Now open the *main.rs* file you just created and enter the code in Listing 1-1.
<span class="filename">Filename: main.rs</span>
@ -67,9 +66,9 @@ fn main() {
}
```
<span class="caption">Listing 1-1: A program that prints “Hello, world!”</span>
<span class="caption">Listing 1-1: A program that prints `Hello, world!`</span>
Save the file, and go back to your terminal window. On Linux or macOS, enter
Save the file and go back to your terminal window. On Linux or macOS, enter
the following commands to compile and run the file:
```text
@ -78,7 +77,7 @@ $ ./main
Hello, world!
```
On Windows, use `.\main.exe` instead of `./main`.
On Windows, enter the command `.\main.exe` instead of `./main`:
```powershell
> rustc main.rs
@ -86,22 +85,17 @@ On Windows, use `.\main.exe` instead of `./main`.
Hello, world!
```
Regardless of your operating system, you should see the string `Hello, world!`
print to the terminal. If you dont see this output, see the “Troubleshooting”
section earlier for ways to get help.
Regardless of your operating system, the string `Hello, world!` should print to
the terminal. If you dont see this output, refer back to the “Troubleshooting”
part of the Intstallation section for ways to get help.
If you did see `Hello, world!` printed, then congratulations! Youve officially
written a Rust program. That makes you a Rust programmer! Welcome!
<!-- Any quick words of advice for if they didn't? (Disclosure: I tried
following this using Bash on windows and couldn't get it working) -->
<!-- Added a pointer to the previous troubleshooting section which also applies
here /Carol -->
If `Hello, world!` did print, congratulations! Youve officially written a Rust
program. That makes you a Rust programmer—welcome!
### Anatomy of a Rust Program
Now, lets go over what just happened in your “Hello, world!” program in
detail. Heres the first piece of the puzzle:
Lets review in detail what just happened in your Hello, world! program.
Heres the first piece of the puzzle:
```rust
fn main() {
@ -109,81 +103,86 @@ fn main() {
}
```
These lines define a *function* in Rust. The `main` function is special: it is
always the first code that is run for every executable Rust program. The first
These lines define a function in Rust. The `main` function is special: it is
always the first code that runs in every executable Rust program. The first
line declares a function named `main` that has no parameters and returns
nothing. If there were parameters, their names would go inside the parentheses,
`(` and `)`.
nothing. If there were parameters, they would go inside the parentheses, `()`.
Also note that the function body is wrapped in curly brackets, `{` and `}`.
Rust requires these around all function bodies. Its considered good style to
place the opening curly bracket on the same line as the function declaration,
with one space in between.
Also, note that the function body is wrapped in curly brackets, `{}`. Rust
requires these around all function bodies. Its good style to place the opening
curly bracket on the same line as the function declaration, adding one space in
between.
> At the time of writing, an automatic formatter, `rustfmt`, is under
> development. If youd like to stick to a standard style across Rust projects,
> `rustfmt` is a tool that will format your code in a particular style. The
> plan is to eventually include it with the standard Rust distribution, like
> `rustc`, so depending on when you read this book, you may have it already
> installed! Check the online documentation for more details.
At the time of this writing, an automatic formatter tool called `rustfmt` is
under development. If you want to stick to a standard style across Rust
projects, `rustfmt` will format your code in a particular style. The Rust team
plans to eventually include this tool with the standard Rust distribution, like
`rustc`. So depending on when you read this book, it might already be installed
on your computer! Check the online documentation for more details.
Inside the `main` function, we have this code:
Inside the `main` function is the following code:
```rust
println!("Hello, world!");
```
This line does all of the work in this little program: it prints text to the
screen. There are a number of details to notice here. The first is that Rust
style is to indent with four spaces, not a tab.
This line does all the work in this little program: it prints text to the
screen. There are four important details to notice here. First, Rust style is
to indent with four spaces, not a tab.
The second important detail is the `println!` call. This code is calling a Rust
*macro*. If it were calling a function instead, it would be entered as
`println` (without the `!`). Well discuss Rust macros in more detail in
Appendix D, but for now you just need to know that when you see a `!` that
Second, `println!` calls a Rust macro. If it called a function instead, it
would be entered as `println` (without the `!`). Well discuss Rust macros in
more detail in Appendix D. For now, you just need to know that using a `!`
means that youre calling a macro instead of a normal function.
<!-- I might suggest just cutting this next macro section -- for the sake of
the intro, we don't really need this info, and I feel like this first exercise
should be short and sweet and simple -->
<!-- I'm ok with cutting this; it's a fairly common question that some folks
have at this point, but I'm ok with those people having to do some research
online if they're curious /Carol -->
Third, you see the `"Hello, world!"` string. We pass this string as an argument
to `println!`, and the string is printed to the screen.
Next comes`"Hello, world!"` which is a *string*. We pass this string as an
argument to `println!` and the total effect is that the string is printed to
the screen. Easy enough!
We end the line with a semicolon `;`, which indicates that this expression is
over, and the next one is ready to begin. Most lines of Rust code end with a
`;`.
Fourth, we end the line with a semicolon (`;`), which indicates that this
expression is over and the next one is ready to begin. Most lines of Rust code
end with a semicolon.
### Compiling and Running Are Separate Steps
Youve just seen how to run a newly created program, so now lets break that
process down and examine each step.
Youve just run a newly created program, so lets examine each step in the
process.
Before running a Rust program, you have to compile it using the Rust compiler
by entering the `rustc` command and passing it the name of your source file,
like this:
Before running a Rust program, you must compile it using the Rust compiler by
entering the `rustc` command and passing it the name of your source file, like
this:
```text
$ rustc main.rs
```
If you come from a C or C++ background, youll notice that this is similar to
`gcc` or `clang`. After compiling successfully, Rust outputs a binary
executable.
If you have a C or C++ background, youll notice that this is similar to `gcc`
or `clang`. After compiling successfully, Rust outputs a binary executable.
On Linux, Mac, and PowerShell on Windows, you can see the executable by
entering the `ls` command in your shell as follows:
On Linux and macOS you can see the executable by entering the `ls` command in
your shell as follows:
```text
$ ls
main main.rs
```
With CMD on Windows, youd enter:
With PowerShell on Windows, you can use `ls` as well, but you'll see three files:
```text
> ls
Directory: Path:\to\the\project
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 6/1/2018 7:31 AM 137728 main.exe
-a---- 6/1/2018 7:31 AM 1454080 main.pdb
-a---- 6/1/2018 7:31 AM 14 main.rs
```
With CMD on Windows, you would enter the following:
```cmd
> dir /B %= the /B option says to only show the file names =%
@ -192,27 +191,28 @@ main.pdb
main.rs
```
This shows we have two files: the source code, with the *.rs* extension, and
the executable (*main.exe* on Windows, *main* everywhere else). All thats left
to do from here is run the *main* or *main.exe* file, like this:
This shows the source code file with the *.rs* extension, the executable file
(*main.exe* on Windows, but *main* on all other platforms), and, when using
CMD, a file containing debugging information with the *.pdb* extension. From
here, you run the *main* or *main.exe* file, like this:
```text
$ ./main # or .\main.exe on Windows
$ ./main # or .\main.exe on Windows
```
If *main.rs* were your “Hello, world!” program, this would print `Hello,
If *main.rs* was your Hello, world! program, this line would print `Hello,
world!` to your terminal.
If you come from a dynamic language like Ruby, Python, or JavaScript, you may
not be used to compiling and running a program being separate steps. Rust is an
*ahead-of-time compiled* language, which means that you can compile a program,
give the executable to someone else, and they can run it even without having
Rust installed. If you give someone a `.rb`, `.py`, or `.js` file, on the other
hand, they need to have a Ruby, Python, or JavaScript implementation installed
(respectively), but you only need one command to both compile and run your
program. Everything is a tradeoff in language design.
If youre more familiar with a dynamic language, such as Ruby, Python, or
JavaScript, you might not be used to compiling and running a program as
separate steps. Rust is an *ahead-of-time compiled* language, meaning you can
compile a program and give the executable to someone else, and they can run it
even without having Rust installed. If you give someone a *.rb*, *.py*, or
*.js* file, they need to have a Ruby, Python, or JavaScript implementation
installed (respectively). But in those languages, you only need one command to
compile and run your program. Everything is a trade-off in language design.
Just compiling with `rustc` is fine for simple programs, but as your project
grows, youll want to be able to manage all of the options and make it easy to
share your code. Next, well introduce you to a tool called Cargo, which will
help you write real-world Rust programs.
grows, youll want to manage all the options and make it easy to share your
code. Next, well introduce you to the Cargo tool, which will help you write
real-world Rust programs.

View File

@ -1,71 +1,57 @@
## Hello, Cargo!
Cargo is Rusts build system and package manager. Most Rustaceans will use this
tool to manage their Rust projects because Cargo takes care of a lot of tasks
for you, such as building your code, downloading the libraries your code
depends on, and building those libraries. (We call libraries your code needs
*dependencies*.)
Cargo is Rusts build system and package manager. Most Rustaceans use this tool
to manage their Rust projects because Cargo handles a lot of tasks for you,
such as building your code, downloading the libraries your code depends on, and
building those libraries. (We call libraries your code needs *dependencies*.)
The simplest Rust programs, like the one weve written so far, dont have any
dependencies, so if we had built the Hello World project with Cargo, it would
only be using the part of Cargo that takes care of building your code. As you
write more complex Rust programs, youll want to add dependencies, and if you
start the project off using Cargo, that will be a lot easier to do.
dependencies. So if we had built the Hello, world! project with Cargo, it would
only use the part of Cargo that handles building your code. As you write more
complex Rust programs, youll add dependencies, and if you start a project
using Cargo, adding dependencies will be much easier to do.
As the vast majority of Rust projects use Cargo, the rest of this book will
assume that youre using Cargo too. Cargo comes installed with Rust itself, if
you used the official installers as covered in the “Installation” section. If
you installed Rust through some other means, you can check if you have Cargo
installed by entering the following into your terminal:
Because the vast majority of Rust projects use Cargo, the rest of this book
assumes that youre using Cargo too. Cargo comes installed with Rust if you
used the official installers discussed in the “Installation” section. If you
installed Rust through some other means, check whether Cargo is installed by
entering the following into your terminal:
```text
$ cargo --version
```
If you see a version number, great! If you see an error like `command not
found`, then you should look at the documentation for your method of
installation to determine how to install Cargo separately.
If you see a version number, you have it! If you see an error, such as `command
not found`, look at the documentation for your method of installation to
determine how to install Cargo separately.
### Creating a Project with Cargo
Lets create a new project using Cargo and look at how it differs from our
original Hello World project. Navigate back to your *projects* directory (or
whichever location you decided to place your code) and then on any operating
system run:
original Hello, world! project. Navigate back to your *projects* directory (or
wherever you decided to store your code). Then, on any operating system, run
the following:
```text
$ cargo new hello_cargo --bin
$ cargo new hello_cargo
$ cd hello_cargo
```
<!-- Below -- so we always have to start a cargo project with the --bin option
if we want it to be something we can execute and not just a library, is that
right? It might be worth laying that out -->
<!-- As of Rust 1.21.0 (the version we're using for the book), yes, you must
always specify `--bin`. In a version of Rust in the near future (1.25 or 1.26),
binary crates will become the default kind of crate that `cargo new` makes, so
you won't have to specify `--bin` (but you can if you want and the behavior
will be the same). We'd rather not go into any more detail than we have here
because of this change; I think "The `--bin` argument to passed to `cargo new`
makes an executable application (often just called a *binary*), as opposed to a
library." lays this out enough. /Carol -->
The first command creates a new directory called *hello_cargo*. Weve named
our project *hello_cargo*, and Cargo creates its files in a directory of the
same name.
This creates a new binary executable called `hello_cargo`. The `--bin` argument
to passed to `cargo new` makes an executable application (often just called a
*binary*), as opposed to a library. Weve given `hello_cargo` as the name for
our project, and Cargo creates its files in a directory of the same name.
Go into the *hello_cargo* directory and list the files, and you should see that
Cargo has generated two files and one directory for us: a *Cargo.toml* and a
*src* directory with a *main.rs* file inside. It has also initialized a new git
repository, along with a *.gitignore* file.
Go into the *hello_cargo* directory and list the files. Youll see that Cargo
has generated two files and one directory for us: a *Cargo.toml* file and a
*src* directory with a *main.rs* file inside. It has also initialized a new Git
repository along with a *.gitignore* file.
> Note: Git is a common version control system. You can change `cargo new` to
> use a different version control system, or no version control system, by
> using the `--vcs` flag. Run `cargo new --help` to see the available options.
> use a different version control system or no version control system by using
> the `--vcs` flag. Run `cargo new --help` to see the available options.
Open up *Cargo.toml* in your text editor of choice. It should look similar to
the code in Listing 1-2:
Open *Cargo.toml* in your text editor of choice. It should look similar to the
code in Listing 1-2.
<span class="filename">Filename: Cargo.toml</span>
@ -81,8 +67,8 @@ authors = ["Your Name <you@example.com>"]
<span class="caption">Listing 1-2: Contents of *Cargo.toml* generated by `cargo
new`</span>
This file is in the [*TOML*][toml]<!-- ignore --> (Toms Obvious, Minimal
Language) format, which is what Cargo uses as its configuration format.
This file is in the [*TOML*][toml]<!-- ignore --> (*Toms Obvious, Minimal
Language*) format, which is Cargos configuration format.
[toml]: https://github.com/toml-lang/toml
@ -90,17 +76,17 @@ The first line, `[package]`, is a section heading that indicates that the
following statements are configuring a package. As we add more information to
this file, well add other sections.
The next three lines set the configuration information Cargo needs in order to
know that it should compile your program: the name, the version, and who wrote
it. Cargo gets your name and email information from your environment, so if
thats not correct, go ahead and fix that and save the file.
The next three lines set the configuration information Cargo needs to compile
your program: the name, the version, and who wrote it. Cargo gets your name and
email information from your environment, so if that information is not correct,
fix the information now and then save the file.
The last line, `[dependencies]`, is the start of a section for you to list any
of your projects dependencies. In Rust, packages of code are referred to as
*crates*. We wont need any other crates for this project, but we will in the
first project in Chapter 2, so well use this dependencies section then.
Now open up *src/main.rs* and take a look:
Now open *src/main.rs* and take a look:
<span class="filename">Filename: src/main.rs</span>
@ -110,27 +96,27 @@ fn main() {
}
```
Cargo has generated a “Hello World!” for you, just like the one we wrote in
Listing 1-1! So far, the differences between our previous project and the
project generated by Cargo are that with Cargo our code goes in the *src*
directory, and we have a *Cargo.toml* configuration file in the top directory.
Cargo has generated a Hello, world! program for you, just like the one we wrote
in Listing 1-1! So far, the differences between our previous project and the
project Cargo generates are that Cargo placed the code in the *src* directory,
and we have a *Cargo.toml* configuration file in the top directory.
Cargo expects your source files to live inside the *src* directory; the
top-level project directory is just for READMEs, license information,
configuration files, and anything else not related to your code. In this way,
using Cargo helps you keep your projects nice and tidy. Theres a place for
everything, and everything is in its place.
Cargo expects your source files to live inside the *src* directory. The
top-level project directory is just for README files, license information,
configuration files, and anything else not related to your code. Using Cargo
helps you organize your projects. Theres a place for everything, and
everything is in its place.
If you started a project that doesnt use Cargo, as we did with our project in
the *hello_world* directory, you can convert it to a project that does use
Cargo by moving the project code into the *src* directory and creating an
appropriate *Cargo.toml*.
If you started a project that doesnt use Cargo, as we did with the Hello,
world! project, you can convert it to a project that does use Cargo. Move the
project code into the *src* directory and create an appropriate *Cargo.toml*
file.
### Building and Running a Cargo Project
Now lets look at whats different about building and running your Hello World
program through Cargo! From your project directory, build your project by
entering the following commands:
Now lets look at whats different when we build and run the Hello, world!
program with Cargo! From your *hello_cargo* directory, build your project by
entering the following command:
```text
$ cargo build
@ -138,25 +124,25 @@ $ cargo build
Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs
```
This creates an executable file in *target/debug/hello_cargo* (or
*target\\debug\\hello_cargo.exe* on Windows), which you can run with this
command:
This command creates an executable file in *target/debug/hello_cargo* (or
*target\debug\hello_cargo.exe* on Windows) rather than in your current
directory. You can run the executable with this command:
```text
$ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows
Hello, world!
```
Bam! If all goes well, `Hello, world!` should print to the terminal once more.
Running `cargo build` for the first time also causes Cargo to create a new file
at the top level called *Cargo.lock*, which is used to keep track of the exact
versions of dependencies in your project. This project doesnt have
dependencies, so the file is a bit sparse. You wont ever need to touch this
file yourself; Cargo will manage its contents for you.
If all goes well, `Hello, world!` should print to the terminal. Running `cargo
build` for the first time also causes Cargo to create a new file at the top
level: *Cargo.lock*. This file keeps track of the exact versions of
dependencies in your project. This project doesnt have dependencies, so the
file is a bit sparse. You wont ever need to change this file manually; Cargo
manages its contents for you.
We just built a project with `cargo build` and ran it with
`./target/debug/hello_cargo`, but we can also use `cargo run` to compile and
then run all in one go:
`./target/debug/hello_cargo`, but we can also use `cargo run` to compile the
code and then run the resulting executable all in one command:
```text
$ cargo run
@ -165,10 +151,10 @@ $ cargo run
Hello, world!
```
Notice that this time, we didnt see the output telling us that Cargo was
compiling `hello_cargo`. Cargo figured out that the files havent changed, so
it just ran the binary. If you had modified your source code, Cargo would have
rebuilt the project before running it, and you would have seen output like this:
Notice that this time we didnt see output indicating that Cargo was compiling
`hello_cargo`. Cargo figured out that the files hadnt changed, so it just ran
the binary. If you had modified your source code, Cargo would have rebuilt the
project before running it, and you would have seen this output:
```text
$ cargo run
@ -178,8 +164,8 @@ $ cargo run
Hello, world!
```
Finally, theres `cargo check`. This command will quickly check your code to
make sure that it compiles, but not bother producing an executable:
Cargo also provides a command called `cargo check`. This command quickly checks
your code to make sure it compiles but doesnt produce an executable:
```text
$ cargo check
@ -187,48 +173,48 @@ $ cargo check
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
```
Why would you not want an executable? `cargo check` is often much faster than
`cargo build`, because it skips the entire step of producing the executable. If
youre checking your work throughout the process of writing the code, using
`cargo check` will speed things up! As such, many Rustaceans run `cargo check`
periodically as they write their program to make sure that it compiles, and
then run `cargo build` once theyre ready to give it a spin themselves.
Why would you not want an executable? Often, `cargo check` is much faster than
`cargo build`, because it skips the step of producing an executable. If youre
continually checking your work while writing the code, using `cargo check` will
speed up the process! As such, many Rustaceans run `cargo check` periodically
as they write their program to make sure it compiles. Then they run `cargo
build` when theyre ready to use the executable.
So to recap, using Cargo:
Lets recap what weve learned so far about Cargo:
- We can build a project using `cargo build` or `cargo check`
- We can build and run the project in one step with `cargo run`
- Instead of the result of the build being put in the same directory as our
code, Cargo will put it in the *target/debug* directory.
* We can build a project using `cargo build` or `cargo check`.
* We can build and run a project in one step using `cargo run`.
* Instead of saving the result of the build in the same directory as our code,
Cargo stores it in the *target/debug* directory.
A final advantage of using Cargo is that the commands are the same no matter
what operating system youre on, so at this point we will no longer be
providing specific instructions for Linux and Mac versus Windows.
An additional advantage of using Cargo is that the commands are the same no
matter which operating system youre working on. So, at this point, well no
longer provide specific instructions for Linux and macOS versus Windows.
### Building for Release
When your project is finally ready for release, you can use `cargo build
--release` to compile your project with optimizations. This will create an
executable in *target/release* instead of *target/debug*. These optimizations
make your Rust code run faster, but turning them on increases the compilation
time of your program. This is why there are two different profiles: one for
development when you want to be able to rebuild quickly and often, and one for
--release` to compile it with optimizations. This command will create an
executable in *target/release* instead of *target/debug*. The optimizations
make your Rust code run faster, but turning them on lengthens the time it takes
for your program to compile. This is why there are two different profiles: one
for development, when you want to rebuild quickly and often, and another for
building the final program youll give to a user that wont be rebuilt
repeatedly and that will run as fast as possible. If youre benchmarking the
running time of your code, be sure to run `cargo build --release` and benchmark
with the executable in *target/release*.
repeatedly and that will run as fast as possible. If youre benchmarking your
codes running time, be sure to run `cargo build --release` and benchmark with
the executable in *target/release*.
### Cargo as Convention
With simple projects, Cargo doesnt provide a whole lot of value over just
using `rustc`, but it will prove its worth as you continue. With complex
projects composed of multiple crates, its much easier to let Cargo coordinate
the build.
With simple projects, Cargo doesnt provide a lot of value over just using
`rustc`, but it will prove its worth as your programs become more intricate.
With complex projects composed of multiple crates, its much easier to let
Cargo coordinate the build.
Even though the `hello_cargo` project is simple, it now uses much of the real
tooling youll use for the rest of your Rust career. In fact, to work on any
existing projects you can use the following commands to check out the code
using Git, change into the project directory, and build:
tooling youll use in the rest of your Rust career. In fact, to work on any
existing projects, you can use the following commands to check out the code
using Git, change to that projects directory, and build:
```text
$ git clone someurl.com/someproject
@ -236,31 +222,22 @@ $ cd someproject
$ cargo build
```
If you want to look at Cargo in more detail, check out [its documentation].
For more information about Cargo, check out [its documentation].
[its documentation]: https://doc.rust-lang.org/cargo/
<!--Below -- I`m not sure this is the place for this conversation, it seems too
deep into the weeds for the "getting started" chapter. I know we discussed
Nightly Rust as an appendix previously, but honestly I think this is more
suited somewhere online, perhaps in the extended docs. I like the idea of
finishing the chapter here, on this practical note, and I think at this point
readers will want to get stuck in anyway and may skip this and never come back
because it's buried at the end of a chapter that's not really related to it. If
it's online somewhere separate they can come to it when they're ready. What do
you think?-->
<!-- Ok, I can see that. /Carol -->
## Summary
Youre already off to a great start on your Rust journey! In this chapter,
youve:
youve learned how to:
* Installed the latest stable version of Rust
* Written a “Hello, world!” program using both `rustc` directly and using
the conventions of `cargo`
* Install the latest stable version of Rust using `rustup`
* Update to a newer Rust version
* Open locally installed documentation
* Write and run a Hello, world! program using `rustc` directly
* Create and run a new project using the conventions of Cargo
This is a great time to build a more substantial program, to get used to
reading and writing Rust code. In the next chapter, well build a guessing game
program. If youd rather start by learning about how common programming
concepts work in Rust, see Chapter 3.
This is a great time to build a more substantial program to get used to reading
and writing Rust code. So, in Chapter 2, well build a guessing game program.
If you would rather start by learning how common programming concepts work in
Rust, see Chapter 3 and then return to Chapter 2.

View File

@ -18,13 +18,12 @@ To set up a new project, go to the *projects* directory that you created in
Chapter 1 and make a new project using Cargo, like so:
```text
$ cargo new guessing_game --bin
$ cargo new guessing_game
$ cd guessing_game
```
The first command, `cargo new`, takes the name of the project (`guessing_game`)
as the first argument. The `--bin` flag tells Cargo to make a binary project,
like the one in Chapter 1. The second command changes to the new projects
as the first argument. The second command changes to the new projects
directory.
Look at the generated *Cargo.toml* file:
@ -155,11 +154,11 @@ line. Notice that this is a `let` statement, which is used to create a
let foo = bar;
```
This line creates a new variable named `foo` and bind it to the value `bar`. In
Rust, variables are immutable by default. Well be discussing this concept in
detail in the “Variables and Mutability” section in Chapter 3. The following
example shows how to use `mut` before the variable name to make a variable
mutable:
This line creates a new variable named `foo` and binds it to the value of the
`bar` variable. In Rust, variables are immutable by default. Well be
discussing this concept in detail in the “Variables and Mutability” section in
Chapter 3. The following example shows how to use `mut` before the variable
name to make a variable mutable:
```rust,ignore
let foo = 5; // immutable
@ -685,8 +684,8 @@ Could not compile `guessing_game`.
The core of the error states that there are *mismatched types*. Rust has a
strong, static type system. However, it also has type inference. When we wrote
`let guess = String::new()`, Rust was able to infer that `guess` should be a
`String` and didnt make us write the type. The `secret_number`, on the other
`let mut guess = String::new();`, Rust was able to infer that `guess` should be
a `String` and didnt make us write the type. The `secret_number`, on the other
hand, is a number type. A few number types can have a value between 1 and 100:
`i32`, a 32-bit number; `u32`, an unsigned 32-bit number; `i64`, a 64-bit
number; as well as others. Rust defaults to an `i32`, which is the type of

View File

@ -9,7 +9,7 @@ out.
When a variable is immutable, once a value is bound to a name, you cant change
that value. To illustrate this, lets generate a new project called *variables*
in your *projects* directory by using `cargo new --bin variables`.
in your *projects* directory by using `cargo new variables`.
Then, in your new *variables* directory, open *src/main.rs* and replace its
code with the following code that wont compile just yet:

View File

@ -50,13 +50,14 @@ value.
<span class="caption">Table 3-1: Integer Types in Rust</span>
| Length | Signed | Unsigned |
|--------|---------|----------|
| 8-bit | `i8` | `u8` |
| 16-bit | `i16` | `u16` |
| 32-bit | `i32` | `u32` |
| 64-bit | `i64` | `u64` |
| arch | `isize` | `usize` |
| Length | Signed | Unsigned |
|---------|---------|----------|
| 8-bit | `i8` | `u8` |
| 16-bit | `i16` | `u16` |
| 32-bit | `i32` | `u32` |
| 64-bit | `i64` | `u64` |
| 128-bit | `i128` | `u128` |
| arch | `isize` | `usize` |
Each variant can be either signed or unsigned and has an explicit size.
*Signed* and *unsigned* refer to whether its possible for the number to be
@ -98,6 +99,21 @@ defaults are generally good choices, and integer types default to `i32`: this
type is generally the fastest, even on 64-bit systems. The primary situation in
which youd use `isize` or `usize` is when indexing some sort of collection.
##### Integer Overflow
Let's say that you have a `u8`, which can hold values between zero and `255`.
What happens if you try to change it to `256`? This is called "integer
overflow", and Rust has some interesting rules around this behavior. When
compiling in debug mode, Rust checks for this kind of issue and will cause
your program to *panic*, which is the term Rust uses when a program exits
with an error. We'll discuss panics more in Chapter 9.
In release builds, Rust does not check for overflow, and instead will
do something called "two's compliment wrapping." In short, `256` becomes
`0`, `257` becomes `1`, etc. Relying on overflow is considered an error,
even if this behavior happens. If you want this behavior explicitly, the
standard library has a type, `Wrapping`, that provides it explicitly.
#### Floating-Point Types
Rust also has two primitive types for *floating-point numbers*, which are
@ -172,12 +188,14 @@ The main way to consume Boolean values is through conditionals, such as an `if`
expression. Well cover how `if` expressions work in Rust in the “Control Flow”
section.
Booleans are one byte in size.
#### The Character Type
So far weve worked only with numbers, but Rust supports letters too. Rusts
`char` type is the languages most primitive alphabetic type, and the following
code shows one way to use it. (Note that the `char` type is specified with
single quotes, as opposed to strings, which use double quotes.)
code shows one way to use it. (Note that the `char` literal is specified with
single quotes, as opposed to string literals, which use double quotes.)
<span class="filename">Filename: src/main.rs</span>
@ -204,8 +222,9 @@ primitive compound types: tuples and arrays.
#### The Tuple Type
A tuple is a general way of grouping together some number of other values with
a variety of types into one compound type.
A tuple is a general way of grouping together some number of other values
with a variety of types into one compound type. Tuples have a fixed length:
once declared, they cannot grow or shrink in size.
We create a tuple by writing a comma-separated list of values inside
parentheses. Each position in the tuple has a type, and the types of the
@ -269,7 +288,7 @@ index in a tuple is 0.
Another way to have a collection of multiple values is with an *array*. Unlike
a tuple, every element of an array must have the same type. Arrays in Rust are
different from arrays in some other languages because arrays in Rust have a
fixed length: once declared, they cannot grow or shrink in size.
fixed length, like tuples.
In Rust, the values going into an array are written as a comma-separated list
inside square brackets:
@ -300,6 +319,21 @@ let months = ["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"];
```
Arrays have an interesting type; it looks like this: `[type; number]`. For
example:
```rust
let a: [i32; 5] = [1, 2, 3, 4, 5];
```
First, there's square brackets; they look like the syntax for creating an
array. Inside, there's two pieces of information, separated by a semicolon.
The first is the type of each element of the array. Since all elements have
the same type, we only need to list it once. After the semicolon, there's
a number that indicates the length of the array. Since an array has a fixed size,
this number is always the same, even if the array's elements are modified, it
cannot grow or shrink.
##### Accessing Array Elements
An array is a single chunk of memory allocated on the stack. You can access
@ -355,7 +389,7 @@ The compilation didnt produce any errors, but the program resulted in a
*runtime* error and didnt exit successfully. When you attempt to access an
element using indexing, Rust will check that the index youve specified is less
than the array length. If the index is greater than the length, Rust will
*panic*, which is the term Rust uses when a program exits with an error.
panic.
This is the first example of Rusts safety principles in action. In many
low-level languages, this kind of check is not done, and when you provide an

View File

@ -320,7 +320,7 @@ fn plus_one(x: i32) -> i32 {
}
```
Running this code produces an error, as follows:
Compiling this code produces an error, as follows:
```text
error[E0308]: mismatched types

View File

@ -226,7 +226,7 @@ fn main() {
}
```
When we try to run this code, well get an error. The `if` and `else` arms have
When we try to compile this code, well get an error. The `if` and `else` arms have
value types that are incompatible, and Rust indicates exactly where to find the
problem in the program:
@ -309,6 +309,30 @@ stop executing the loop. Recall that we did this in the guessing game in the
“Quitting After a Correct Guess” section of Chapter 2 to exit the
program when the user won the game by guessing the correct number.
#### Returning from loops
One of the uses of a `loop` is to retry an operation you know can fail, such as
checking if a thread completed its job. However, you might need to pass the
result of that operation to the rest of your code. If you add it to the `break`
expression you use to stop the loop, it will be returned by the broken loop:
```rust
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
assert_eq!(result, 20);
}
```
#### Conditional Loops with `while`
Its often useful for a program to evaluate a condition within a loop. While

View File

@ -150,7 +150,18 @@ let world = &s[6..11];
This is similar to taking a reference to the whole `String` but with the extra
`[0..5]` bit. Rather than a reference to the entire `String`, its a reference
to a portion of the `String`. The `start..end` syntax is a range that begins at
`start` and continues up to, but not including, `end`.
`start` and continues up to, but not including, `end`. If we wanted to include
`end`, we can use `..=` instead of `..`:
```rust
let s = String::from("hello world");
let hello = &s[0..=4];
let world = &s[6..=10];
```
The `=` means that we're including the last number, if that helps you remember
the difference between `..` and `..=`.
We can create slices using a range within brackets by specifying
`[starting_index..ending_index]`, where `starting_index` is the first position
@ -158,7 +169,7 @@ in the slice and `ending_index` is one more than the last position in the
slice. Internally, the slice data structure stores the starting position and
the length of the slice, which corresponds to `ending_index` minus
`starting_index`. So in the case of `let world = &s[6..11];`, `world` would be
a slice that contains a pointer to the 6th byte of `s` and a length value of 5.
a slice that contains a pointer to the 7th byte of `s` and a length value of 5.
Figure 4-6 shows this in a diagram.

View File

@ -10,7 +10,7 @@ Well create a skeleton of a library that provides some general networking
functionality; well concentrate on the organization of the modules and
functions, but we wont worry about what code goes in the function bodies.
Well call our library `communicator`. To create a library, pass the `--lib`
option instead of `--bin`:
option:
```text
$ cargo new communicator --lib
@ -32,8 +32,7 @@ mod tests {
}
```
Cargo creates an example test to help us get our library started, rather than
the “Hello, world!” binary that we get when we use the `--bin` option. Well
Cargo creates an example test to help us get our library started. Well
look at the `#[]` and `mod tests` syntax in the “Using `super` to Access a
Parent Module” section later in this chapter, but for now, leave this code at
the bottom of *src/lib.rs*.

View File

@ -104,6 +104,39 @@ fn main() {
Were still specifying the `TrafficLight` namespace for the `Green` variant
because we didnt include `Green` in the `use` statement.
#### Nested groups in `use` declarations
If you have a complex module tree with many different submodules and you need
to import a few items from each one, it might be useful to group all the
imports in the same declaration to keep your code clean and avoid repeating the
base modules name.
The `use` declaration supports nesting to help you in those cases, both with
simple imports and glob ones. For example this snippets imports `bar`, `Foo`,
all the items in `baz` and `Bar`:
```rust
# #![allow(unused_imports, dead_code)]
#
# mod foo {
# pub mod bar {
# pub type Foo = ();
# }
# pub mod baz {
# pub mod quux {
# pub type Bar = ();
# }
# }
# }
#
use foo::{
bar::{self, Foo},
baz::{*, quux::Bar},
};
#
# fn main() {}
```
### Bringing All Names into Scope with a Glob
To bring all the items in a namespace into scope at once, we can use the `*`

View File

@ -96,17 +96,32 @@ read their contents is a good next step. There are two ways to reference a
value stored in a vector. In the examples, weve annotated the types of the
values that are returned from these functions for extra clarity.
Listing 8-5 shows both methods of accessing a value in a vector, either with
indexing syntax or the `get` method:
Listing 8-5 shows the method of accessing a value in a vector with
indexing syntax:
```rust
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
let third: Option<&i32> = v.get(2);
```
<span class="caption">Listing 8-5: Using indexing syntax or the `get` method to
<span class="caption">Listing 8-5: Using indexing syntax to
access an item in a vector</span>
Listing 8-6 shows the method of accessing a value in a vector, with
the `get` method:
```rust
let v = vec![1, 2, 3, 4, 5];
let v_index = 2;
match v.get(v_index) {
Some(_) => { println!("Reachable element at index: {}", v_index); },
None => { println!("Unreachable element at index: {}", v_index); }
}
```
<span class="caption">Listing 8-6: Using the `get` method to
access an item in a vector</span>
Note two details here. First, we use the index value of `2` to get the third
@ -119,7 +134,7 @@ Rust has two ways to reference an element so you can choose how the program
behaves when you try to use an index value that the vector doesnt have an
element for. As an example, lets see what a program will do if it has a vector
that holds five elements and then tries to access an element at index 100, as
shown in Listing 8-6:
shown in Listing 8-7:
```rust,should_panic
let v = vec![1, 2, 3, 4, 5];
@ -128,7 +143,7 @@ let does_not_exist = &v[100];
let does_not_exist = v.get(100);
```
<span class="caption">Listing 8-6: Attempting to access the element at index
<span class="caption">Listing 8-7: Attempting to access the element at index
100 in a vector containing five elements</span>
When we run this code, the first `[]` method will cause the program to panic
@ -150,7 +165,7 @@ When the program has a valid reference, the borrow checker enforces the
ownership and borrowing rules (covered in Chapter 4) to ensure this reference
and any other references to the contents of the vector remain valid. Recall the
rule that states you cant have mutable and immutable references in the same
scope. That rule applies in Listing 8-7, where we hold an immutable reference to
scope. That rule applies in Listing 8-8, where we hold an immutable reference to
the first element in a vector and try to add an element to the end, which wont
work:
@ -162,7 +177,7 @@ let first = &v[0];
v.push(6);
```
<span class="caption">Listing 8-7: Attempting to add an element to a vector
<span class="caption">Listing 8-8: Attempting to add an element to a vector
while holding a reference to an item</span>
Compiling this code will result in this error:
@ -181,7 +196,7 @@ error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immuta
| - immutable borrow ends here
```
The code in Listing 8-7 might look like it should work: why should a reference
The code in Listing 8-8 might look like it should work: why should a reference
to the first element care about what changes at the end of the vector? This
error is due to the way vectors work: adding a new element onto the end of the
vector might require allocating new memory and copying the old elements to the
@ -197,7 +212,7 @@ programs from ending up in that situation.
If we want to access each element in a vector in turn, we can iterate through
all of the elements rather than use indexes to access one at a time. Listing
8-8 shows how to use a `for` loop to get immutable references to each element
8-9 shows how to use a `for` loop to get immutable references to each element
in a vector of `i32` values and print them:
```rust
@ -207,11 +222,11 @@ for i in &v {
}
```
<span class="caption">Listing 8-8: Printing each element in a vector by
<span class="caption">Listing 8-9: Printing each element in a vector by
iterating over the elements using a `for` loop</span>
We can also iterate over mutable references to each element in a mutable vector
in order to make changes to all the elements. The `for` loop in Listing 8-9
in order to make changes to all the elements. The `for` loop in Listing 8-10
will add `50` to each element:
```rust
@ -221,12 +236,12 @@ for i in &mut v {
}
```
<span class="caption">Listing 8-9: Iterating over mutable references to
<span class="caption">Listing 8-10: Iterating over mutable references to
elements in a vector</span>
To change the value that the mutable reference refers to, we have to use the
dereference operator (`*`) to get to the value in `i` before we can use the
`+=` operator .
`+=` operator . We'll talk more about `*` in Chapter 15.
### Using an Enum to Store Multiple Types
@ -241,7 +256,7 @@ some of the columns in the row contain integers, some floating-point numbers,
and some strings. We can define an enum whose variants will hold the different
value types, and then all the enum variants will be considered the same type:
that of the enum. Then we can create a vector that holds that enum and so,
ultimately, holds different types. Weve demonstrated this in Listing 8-10:
ultimately, holds different types. Weve demonstrated this in Listing 8-11:
```rust
enum SpreadsheetCell {
@ -257,7 +272,7 @@ let row = vec![
];
```
<span class="caption">Listing 8-10: Defining an `enum` to store values of
<span class="caption">Listing 8-11: Defining an `enum` to store values of
different types in one vector</span>
Rust needs to know what types will be in the vector at compile time so it knows

View File

@ -307,19 +307,22 @@ fn read_username_from_file() -> Result<String, io::Error> {
<span class="caption">Listing 9-6: A function that returns errors to the
calling code using `match`</span>
Lets look at the return type of the function first: `Result<String,
io::Error>`. This means the function is returning a value of the type
`Result<T, E>` where the generic parameter `T` has been filled in with the
concrete type `String`, and the generic type `E` has been filled in with the
concrete type `io::Error`. If this function succeeds without any problems, the
code that calls this function will receive an `Ok` value that holds a
`String`—the username that this function read from the file. If this function
encounters any problems, the code that calls this function will receive an
`Err` value that holds an instance of `io::Error` that contains more
information about what the problems were. We chose `io::Error` as the return
type of this function because that happens to be the type of the error value
returned from both of the operations were calling in this functions body that
might fail: the `File::open` function and the `read_to_string` method.
This function can be written in a much shorter way, but we're going to start by
doing a lot of it manually in order to explore error handling; at the end,
we'll show the easy way. Lets look at the return type of the function first:
`Result<String, io::Error>`. This means the function is returning a value of
the type `Result<T, E>` where the generic parameter `T` has been filled in
with the concrete type `String`, and the generic type `E` has been filled in
with the concrete type `io::Error`. If this function succeeds without any
problems, the code that calls this function will receive an `Ok` value that
holds a `String`—the username that this function read from the file. If this
function encounters any problems, the code that calls this function will
receive an `Err` value that holds an instance of `io::Error` that contains
more information about what the problems were. We chose `io::Error` as the
return type of this function because that happens to be the type of the error
value returned from both of the operations were calling in this functions
body that might fail: the `File::open` function and the `read_to_string`
method.
The body of the function starts by calling the `File::open` function. Then we
handle the `Result` value returned with a `match` similar to the `match` in
@ -379,12 +382,12 @@ The `?` placed after a `Result` value is defined to work in almost the same way
as the `match` expressions we defined to handle the `Result` values in Listing
9-6. If the value of the `Result` is an `Ok`, the value inside the `Ok` will
get returned from this expression, and the program will continue. If the value
is an `Err`, the value inside the `Err` will be returned from the whole
function as if we had used the `return` keyword so the error value gets
propagated to the calling code.
is an `Err`, the `Err` will be returned from the whole function as if we had
used the `return` keyword so the error value gets propagated to the calling
code.
There is a difference between what the `match` expression from Listing 9-6 and
`?` do: error values used with `?` go through the `from` function, defined in
`?` do: error values taken by `?` go through the `from` function, defined in
the `From` trait in the standard library, which is used to convert errors from
one type into another. When `?` calls the `from` function, the error type
received is converted into the error type defined in the return type of the
@ -431,6 +434,30 @@ username in `s` when both `File::open` and `read_to_string` succeed rather than
returning errors. The functionality is again the same as in Listing 9-6 and
Listing 9-7; this is just a different, more ergonomic way to write it.
Speaking of different ways to write this function, there's a way to make this even
shorter:
<span class="filename">Filename: src/main.rs</span>
```rust
use std::io;
use std::io::Read;
use std::fs;
fn read_username_from_file() -> Result<String, io::Error> {
fs::read_to_string("hello.txt")
}
```
<span class="caption">Listing 9-9: Using `fs::read_to_string`</span>
Reading a file into a string is a fairly common operation, and so Rust
provides a convenience function called `fs::read_to_string` that will
open the file, create a new `String`, read the contents of the file,
and put the contents into that `String`, and then return it. Of course,
this doesn't give us the opportunity to show off all of this error handling,
so we did it the hard way at first.
#### The `?` Operator Can Only Be Used in Functions That Return `Result`
The `?` operator can only be used in functions that have a return type of

View File

@ -192,7 +192,7 @@ impl Guess {
}
```
<span class="caption">Listing 9-9: A `Guess` type that will only continue with
<span class="caption">Listing 9-10: A `Guess` type that will only continue with
values between 1 and 100</span>
First, we define a struct named `Guess` that has a field named `value` that

View File

@ -15,11 +15,11 @@ explore how to define your own types, functions, and methods with generics!
First, well review how to extract a function to reduce code duplication. Next,
well use the same technique to make a generic function from two functions that
only differ in the types of their parameters. Well also explain how to use
differ only in the types of their parameters. Well also explain how to use
generic types in struct and enum definitions.
Then youll learn how to use *traits* to define behavior in a generic way. You
can then combine traits with generic types to constrain a generic type to only
can combine traits with generic types to constrain a generic type to only
those types that have a particular behavior, as opposed to just any type.
Finally, well discuss *lifetimes*, a variety of generics that give the
@ -36,7 +36,7 @@ you recognize duplicated code to extract into a function, youll start to
recognize duplicated code that can use generics.
Consider a short program that finds the largest number in a list, as shown in
Listing 10-1:
Listing 10-1.
<span class="filename">Filename: src/main.rs</span>
@ -65,13 +65,13 @@ the first number in the list in a variable named `largest`. Then it iterates
through all the numbers in the list, and if the current number is greater than
the number stored in `largest`, it replaces the number in that variable.
However, if the current number is less than the largest number seen so far, the
variable doesnt change and the code moves on to the next number in the list.
variable doesnt change, and the code moves on to the next number in the list.
After considering all the numbers in the list, `largest` should hold the
largest number, which in this case is 100.
To find the largest number in two different lists of numbers, we can duplicate
the code in Listing 10-1 and use the same logic at two different places in the
program, as shown in Listing 10-2:
program, as shown in Listing 10-2.
<span class="filename">Filename: src/main.rs</span>
@ -107,7 +107,7 @@ fn main() {
lists of numbers</span>
Although this code works, duplicating code is tedious and error prone. We also
have to update the code in multiple places to change it.
have to update the code in multiple places when we want to change it.
To eliminate this duplication, we can create an abstraction by defining a
function that operates on any list of integers given to it in a parameter. This
@ -117,7 +117,7 @@ largest number in a list abstractly.
In Listing 10-3, we extracted the code that finds the largest number into a
function named `largest`. Unlike the code in Listing 10-1, which can find the
largest number in only one particular list, this program can find the largest
number in two different lists:
number in two different lists.
<span class="filename">Filename: src/main.rs</span>
@ -161,7 +161,7 @@ In sum, here are the steps we took to change the code from Listing 10-2 to
Listing 10-3:
1. Identify duplicate code.
2. Extract the duplicate code into the body of the function, and specify the
2. Extract the duplicate code into the body of the function and specify the
inputs and return values of that code in the function signature.
3. Update the two instances of duplicated code to call the function instead.

View File

@ -13,7 +13,7 @@ parameters and return value. Doing so makes our code more flexible and provides
more functionality to callers of our function while preventing code duplication.
Continuing with our `largest` function, Listing 10-4 shows two functions that
both find the largest value in a slice:
both find the largest value in a slice.
<span class="filename">Filename: src/main.rs</span>
@ -66,17 +66,17 @@ the largest `i32` in a slice. The `largest_char` function finds the largest
the duplication by introducing a generic type parameter in a single function.
To parameterize the types in the new function well define, we need to name the
type parameter, just like we do for the value parameters to a function. You can
type parameter, just as we do for the value parameters to a function. You can
use any identifier as a type parameter name. But well use `T` because, by
convention, parameter names in Rust are short, often just a letter, and Rusts
type naming convention is CamelCase. Short for “type,” `T` is the default
type-naming convention is CamelCase. Short for “type,” `T` is the default
choice of most Rust programmers.
When we use a parameter in the body of the function, we have to declare the
parameter name in the signature so that the compiler knows what that name
means. Similarly, when we use a type parameter name in a function signature, we
have to declare the type parameter name before we use it. To define the generic
`largest` function, place type name declarations inside angle brackets (`<>`)
parameter name in the signature so the compiler knows what that name means.
Similarly, when we use a type parameter name in a function signature, we have
to declare the type parameter name before we use it. To define the generic
`largest` function, place type name declarations inside angle brackets, `<>`,
between the name of the function and the parameter list, like this:
```rust,ignore
@ -140,16 +140,16 @@ traits in the next section. For now, this error states that the body of
`largest` wont work for all possible types that `T` could be. Because we want
to compare values of type `T` in the body, we can only use types whose values
can be ordered. To enable comparisons, the standard library has the
`std::cmp::PartialOrd` trait that you can implement on types (see Appendix C,
“Derivable Traits,” for more on this trait). Youll learn how to specify that a
generic type has a particular trait in the “Trait Bounds” section, but lets
first explore other ways of using generic type parameters.
`std::cmp::PartialOrd` trait that you can implement on types (see Appendix C
for more on this trait). Youll learn how to specify that a generic type has a
particular trait in the “Trait Bounds” section, but lets first explore other
ways of using generic type parameters.
### In Struct Definitions
We can also define structs to use a generic type parameter in one or more
fields using the `<>` syntax. Listing 10-6 shows how to define a `Point<T>`
struct to hold `x` and `y` coordinate values of any type:
struct to hold `x` and `y` coordinate values of any type.
<span class="filename">Filename: src/main.rs</span>
@ -174,11 +174,11 @@ angle brackets just after the name of the struct. Then we can use the generic
type in the struct definition where we would otherwise specify concrete data
types.
Note that because weve only used one generic type to define `Point<T>`, this
Note that because weve used only one generic type to define `Point<T>`, this
definition says that the `Point<T>` struct is generic over some type `T`, and
the fields `x` and `y` are *both* that same type, whatever that type may be. If
we create an instance of a `Point<T>` that has values of different types, as in
Listing 10-7, our code wont compile:
Listing 10-7, our code wont compile.
<span class="filename">Filename: src/main.rs</span>
@ -194,11 +194,11 @@ fn main() {
```
<span class="caption">Listing 10-7: The fields `x` and `y` must be the same
type because both have the same generic data type `T`</span>
type because both have the same generic data type `T`.</span>
In this example, when we assign the integer value `5` to `x`, we let the
In this example, when we assign the integer value 5 to `x`, we let the
compiler know that the generic type `T` will be an integer for this instance of
`Point<T>`. Then when we specify `4.0` for `y`, which weve defined to have the
`Point<T>`. Then when we specify 4.0 for `y`, which weve defined to have the
same type as `x`, well get a type mismatch error like this:
```text
@ -216,7 +216,7 @@ floating-point variable
To define a `Point` struct where `x` and `y` are both generics but could have
different types, we can use multiple generic type parameters. For example, in
Listing 10-8, we can change the definition of `Point` to be generic over types
`T` and `U` where `x` is of type `T` and `y` is of type `U`:
`T` and `U` where `x` is of type `T` and `y` is of type `U`.
<span class="filename">Filename: src/main.rs</span>
@ -245,7 +245,7 @@ could indicate that your code needs restructuring into smaller pieces.
As we did with structs, we can define enums to hold generic data types in their
variants. Lets take another look at the `Option<T>` enum that the standard
library provides that we used in Chapter 6:
library provides, which we used in Chapter 6:
```rust
enum Option<T> {
@ -276,7 +276,7 @@ The `Result` enum is generic over two types, `T` and `E`, and has two variants:
`E`. This definition makes it convenient to use the `Result` enum anywhere we
have an operation that might succeed (return a value of some type `T`) or fail
(return an error of some type `E`). In fact, this is what we used to open a
file in Listing 9-3 where `T` was filled in with the type `std::fs::File` when
file in Listing 9-3, where `T` was filled in with the type `std::fs::File` when
the file was opened successfully and `E` was filled in with the type
`std::io::Error` when there were problems opening the file.
@ -286,9 +286,9 @@ avoid duplication by using generic types instead.
### In Method Definitions
As we did in Chapter 5, we can implement methods on structs and enums that have
generic types in their definitions. Listing 10-9 shows the `Point<T>` struct we
defined in Listing 10-6 with a method named `x` implemented on it:
We can implement methods on structs and enums (as we did in Chapter 5) and use
generic types in their definitions, too. Listing 10-9 shows the `Point<T>`
struct we defined in Listing 10-6 with a method named `x` implemented on it.
<span class="filename">Filename: src/main.rs</span>
@ -325,7 +325,7 @@ brackets in `Point` is a generic type rather than a concrete type.
We could, for example, implement methods only on `Point<f32>` instances rather
than on `Point<T>` instances with any generic type. In Listing 10-10 we use the
concrete type `f32`, meaning we dont declare any types after `impl`:
concrete type `f32`, meaning we dont declare any types after `impl`.
```rust
# struct Point<T> {
@ -344,10 +344,10 @@ impl Point<f32> {
struct with a particular concrete type for the generic type parameter `T`</span>
This code means the type `Point<f32>` will have a method named
`distance_from_origin`, and other instances of `Point<T>` where `T` is not of
`distance_from_origin` and other instances of `Point<T>` where `T` is not of
type `f32` will not have this method defined. The method measures how far our
point is from the point at coordinates (0.0, 0.0) and uses mathematical
operations that are only available for floating point types.
operations that are available only for floating point types.
Generic type parameters in a struct definition arent always the same as those
you use in that structs method signatures. For example, Listing 10-11 defines
@ -355,7 +355,7 @@ the method `mixup` on the `Point<T, U>` struct from Listing 10-8. The method
takes another `Point` as a parameter, which might have different types than the
`self` `Point` were calling `mixup` on. The method creates a new `Point`
instance with the `x` value from the `self` `Point` (of type `T`) and the `y`
value from the passed-in `Point` (of type `W`):
value from the passed-in `Point` (of type `W`).
<span class="filename">Filename: src/main.rs</span>
@ -427,8 +427,8 @@ let float = Some(5.0);
```
When Rust compiles this code, it performs monomorphization. During that
process, the compiler reads the values that have been used in the instances of
`Option<T>` and identifies two kinds of `Option<T>`: one is `i32` and the other
process, the compiler reads the values that have been used in `Option<T>`
instances and identifies two kinds of `Option<T>`: one is `i32` and the other
is `f64`. As such, it expands the generic definition of `Option<T>` into
`Option_i32` and `Option_f64`, thereby replacing the generic definition with
the specific ones.
@ -457,6 +457,6 @@ fn main() {
Because Rust compiles generic code into code that specifies the type in each
instance, we pay no runtime cost for using generics. When the code runs, it
performs just like it would if we had duplicated each definition by hand. The
performs just as it would if we had duplicated each definition by hand. The
process of monomorphization makes Rusts generics extremely efficient at
runtime.

View File

@ -25,7 +25,7 @@ We want to make a media aggregator library that can display summaries of data
that might be stored in a `NewsArticle` or `Tweet` instance. To do this, we
need a summary from each type, and we need to request that summary by calling a
`summarize` method on an instance. Listing 10-12 shows the definition of a
`Summary` trait that expresses this behavior:
`Summary` trait that expresses this behavior.
<span class="filename">Filename: src/lib.rs</span>
@ -39,7 +39,7 @@ pub trait Summary {
behavior provided by a `summarize` method</span>
Here, we declare a trait using the `trait` keyword and then the traits name,
which is `Summary` in this case. Inside the curly brackets we declare the
which is `Summary` in this case. Inside the curly brackets, we declare the
method signatures that describe the behaviors of the types that implement this
trait, which in this case is `fn summarize(&self) -> String`.
@ -127,14 +127,14 @@ know, people`.
Note that because we defined the `Summary` trait and the `NewsArticle` and
`Tweet` types in the same *lib.rs* in Listing 10-13, theyre all in the same
scope. Lets say this *lib.rs* is for a crate weve called `aggregator`, and
scope. Lets say this *lib.rs* is for a crate weve called `aggregator` and
someone else wants to use our crates functionality to implement the `Summary`
trait on a struct defined within their librarys scope. They would need to
import the trait into their scope first. They would do so by specifying `use
aggregator::Summary;`, which then enables them to implement `Summary` for their
type. The `Summary` trait would also need to be a public trait for another
crate to implement it, which it is because we put the `pub` keyword before
`trait` in Listing 10-12.
aggregator::Summary;`, which then would enable them to implement `Summary` for
their type. The `Summary` trait would also need to be a public trait for
another crate to implement it, which it is because we put the `pub` keyword
before `trait` in Listing 10-12.
One restriction to note with trait implementations is that we can implement a
trait on a type only if either the trait or the type is local to our crate.
@ -162,8 +162,8 @@ Then, as we implement the trait on a particular type, we can keep or override
each methods default behavior.
Listing 10-14 shows how to specify a default string for the `summarize` method
of the `Summary` trait instead of only defining the method signature, like we
did in Listing 10-12:
of the `Summary` trait instead of only defining the method signature, as we did
in Listing 10-12.
<span class="filename">Filename: src/lib.rs</span>
@ -258,20 +258,29 @@ This code prints `1 new tweet: (Read more from @horse_ebooks...)`.
Note that it isnt possible to call the default implementation from an
overriding implementation of that same method.
### Trait Bounds
### Traits as arguments
Now that you know how to define traits and implement those traits on types, we
can explore how to use traits with generic type parameters. We can use *trait
bounds* to constrain generic types to ensure the type will be limited to those
that implement a particular trait and behavior.
can explore how to use traits to accept arguments of many different types.
For example, in Listing 10-13, we implemented the `Summary` trait on the types
`NewsArticle` and `Tweet`. We can define a function `notify` that calls the
`summarize` method on its parameter `item`, which is of the generic type `T`.
To be able to call `summarize` on `item` without getting an error telling us
that the generic type `T` doesnt implement the method `summarize`, we can use
trait bounds on `T` to specify that `item` must be of a type that implements
the `Summary` trait:
`summarize` method on its parameter `item`, which is of some type that implements
the `Summary` trait. To do this, we can use the '`impl Trait`' syntax, like this:
```rust,ignore
pub fn notify(item: impl Summary) {
println!("Breaking news! {}", item.summarize());
}
```
In the body of `notify`, we can call any methods on `item` that come from
the `Summary` trait, like `summarize`.
#### Trait Bounds
The `impl Trait` syntax works for short examples, but is syntax sugar for a
longer form. This is called a 'trait bound', and it looks like this:
```rust,ignore
pub fn notify<T: Summary>(item: T) {
@ -279,28 +288,45 @@ pub fn notify<T: Summary>(item: T) {
}
```
We place trait bounds with the declaration of the generic type parameter, after
a colon and inside angle brackets. Because of the trait bound on `T`, we can
This is equivalent to the example above, but is a bit more verbose. We place
trait bounds with the declaration of the generic type parameter, after a
colon and inside angle brackets. Because of the trait bound on `T`, we can
call `notify` and pass in any instance of `NewsArticle` or `Tweet`. Code that
calls the function with any other type, like a `String` or an `i32`, wont
compile, because those types dont implement `Summary`.
When should you use this form over `impl Trait`? While `impl Trait` is nice for
shorter examples, trait bounds are nice for more complex ones. For example,
say we wanted to take two things that implement `Summary`:
```rust,ignore
pub fn notify(item1: impl Summary, item2: impl Summary) {
pub fn notify<T: Summary>(item1: T, item2: T) {
```
The version with the bound is a bit easier. In general, you should use whatever
form makes your code the most understandable.
##### Multiple trait bounds with `+`
We can specify multiple trait bounds on a generic type using the `+` syntax.
For example, to use display formatting on the type `T` in a function as well as
the `summarize` method, we can use `T: Summary + Display` to say `T` can be any
type that implements `Summary` and `Display`.
However, there are downsides to using too many trait bounds. Each generic has
its own trait bounds; so functions with multiple generic type parameters can
have lots of trait bound information between a functions name and its
parameter list, making the function signature hard to read. For this reason,
Rust has alternate syntax for specifying trait bounds inside a `where` clause
after the function signature. So instead of writing this:
type that implements `Summary` and `Display`. This can grow quite complex!
```rust,ignore
fn some_function<T: Display + Clone, U: Clone + Debug>(t: T, u: U) -> i32 {
```
#### `where` clauses for clearer code
However, there are downsides to using too many trait bounds. Each generic has
its own trait bounds, so functions with multiple generic type parameters can
have lots of trait bound information between a functions name and its
parameter list, making the function signature hard to read. For this reason,
Rust has alternate syntax for specifying trait bounds inside a `where` clause
after the function signature. So instead of writing this:
we can use a `where` clause, like this:
```rust,ignore
@ -314,6 +340,60 @@ This functions signature is less cluttered in that the function name,
parameter list, and return type are close together, similar to a function
without lots of trait bounds.
### Returning Traits
We can use the `impl Trait` syntax in return position as well, to return
something that implements a trait:
```rust,ignore
fn returns_summarizable() -> impl Summary {
Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
}
}
```
This signature says, "I'm going to return something that implements the
`Summary` trait, but I'm not going to tell you the exact type. In our case,
we're returning a `Tweet`, but the caller doesn't know that.
Why is this useful? In chapter 13, we're going to learn about two features
that rely heavily on traits: closures, and iterators. These features create
types that only the compiler knows, or types that are very, very long.
`impl Trait` lets you simply say "this returns an `Iterator`" without
needing to write out a really long type.
This only works if you have a single type that you're returning, however.
For example, this would *not* work:
```rust,ignore
fn returns_summarizable(switch: bool) -> impl Summary {
if switch {
NewsArticle {
headline: String::from("Penguins win the Stanley Cup Championship!"),
location: String::from("Pittsburgh, PA, USA"),
author: String::from("Iceburgh"),
content: String::from("The Pittsburgh Penguins once again are the best
hockey team in the NHL."),
}
} else {
Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
}
}
}
```
Here, we try to return either a `NewsArticle` or a `Tweet`. This cannot work,
due to restrictions around how `impl Trait` works. To write this code, you'll
have to wait until Chapter 17, "trait objects".
### Fixing the `largest` Function with Trait Bounds
Now that you know how to specify the behavior you want to use using the generic
@ -332,7 +412,7 @@ error[E0369]: binary operation `>` cannot be applied to type `T`
```
In the body of `largest` we wanted to compare two values of type `T` using the
greater-than (`>`) operator. Because that operator is defined as a default
greater than (`>`) operator. Because that operator is defined as a default
method on the standard library trait `std::cmp::PartialOrd`, we need to specify
`PartialOrd` in the trait bounds for `T` so the `largest` function can work on
slices of any type that we can compare. We dont need to bring `PartialOrd`
@ -379,7 +459,7 @@ To call this code with only those types that implement the `Copy` trait, we can
add `Copy` to the trait bounds of `T`! Listing 10-15 shows the complete code of
a generic `largest` function that will compile as long as the types of the
values in the slice that we pass into the function implement the `PartialOrd`
*and* `Copy` traits, like `i32` and `char` do:
*and* `Copy` traits, like `i32` and `char` do.
<span class="filename">Filename: src/main.rs</span>
@ -434,7 +514,7 @@ we can implement methods conditionally for types that implement the specified
traits. For example, the type `Pair<T>` in Listing 10-16 always implements the
`new` function. But `Pair<T>` only implements the `cmp_display` method if its
inner type `T` implements the `PartialOrd` trait that enables comparison *and*
the `Display` trait that enables printing:
the `Display` trait that enables printing.
```rust
use std::fmt::Display;

View File

@ -2,8 +2,8 @@
One detail we didnt discuss in the “References and Borrowing” section in
Chapter 4 is that every reference in Rust has a *lifetime*, which is the scope
for which that reference is valid. Most of the time lifetimes are implicit and
inferred, just like most of the time types are inferred. We must annotate types
for which that reference is valid. Most of the time, lifetimes are implicit and
inferred, just like most of the time, types are inferred. We must annotate types
when multiple types are possible. In a similar way, we must annotate lifetimes
when the lifetimes of references could be related in a few different ways. Rust
requires us to annotate the relationships using generic lifetime parameters to
@ -16,12 +16,12 @@ common ways you might encounter lifetime syntax so you can become familiar with
the concepts. See the “Advanced Lifetimes” section in Chapter 19 for more
detailed information.
### Lifetimes Prevent Dangling References
### Preventing Dangling References with Lifetimes
The main aim of lifetimes is to prevent dangling references, which cause a
program to reference data other than the data its intended to reference.
Consider the program in Listing 10-17, which has an outer scope and an inner
scope:
scope.
```rust,ignore
{
@ -39,15 +39,15 @@ scope:
<span class="caption">Listing 10-17: An attempt to use a reference whose value
has gone out of scope</span>
> Note: The example in Listing 10-17 and the next few examples declare
> variables without giving them an initial value, so the variable name exists
> in the outer scope. At first glance, this might appear to be in conflict with
> Rust having no null values. However, if we try to use a variable before
> giving it a value, well get a compile time error, which shows that Rust
> indeed does not allow null values.
> Note: The examples in Listings 10-17, 10-18, and 10-24 declare variables
> without giving them an initial value, so the variable name exists in the
> outer scope. At first glance, this might appear to be in conflict with Rusts
> having no null values. However, if we try to use a variable before giving it
> a value, well get a compile-time error, which shows that Rust indeed does
> not allow null values.
The outer scope declares a variable named `r` with no initial value, and the
inner scope declares a variable named `x` with the initial value of `5`. Inside
inner scope declares a variable named `x` with the initial value of 5. Inside
the inner scope, we attempt to set the value of `r` as a reference to `x`. Then
the inner scope ends, and we attempt to print the value in `r`. This code wont
compile because the value `r` is referring to has gone out of scope before we
@ -76,9 +76,9 @@ It uses a borrow checker.
### The Borrow Checker
The Rust compiler has a *borrow checker* that compares scopes to determine that
all borrows are valid. Listing 10-18 shows the same code as Listing 10-17 but
with annotations showing the lifetimes of the variables:
The Rust compiler has a *borrow checker* that compares scopes to determine
whether all borrows are valid. Listing 10-18 shows the same code as Listing
10-17 but with annotations showing the lifetimes of the variables.
```rust,ignore
{
@ -104,7 +104,7 @@ with a lifetime of `'b`. The program is rejected because `'b` is shorter than
`'a`: the subject of the reference doesnt live as long as the reference.
Listing 10-19 fixes the code so it doesnt have a dangling reference and
compiles without any errors:
compiles without any errors.
```rust
{
@ -133,7 +133,7 @@ lifetimes of parameters and return values in the context of functions.
Lets write a function that returns the longer of two string slices. This
function will take two string slices and return a string slice. After weve
implemented the `longest` function, the code in Listing 10-20 should print `The
longest string is abcd`:
longest string is abcd`.
<span class="filename">Filename: src/main.rs</span>
@ -148,7 +148,7 @@ fn main() {
```
<span class="caption">Listing 10-20: A `main` function that calls the `longest`
function to find the longest of two string slices</span>
function to find the longer of two string slices</span>
Note that we want the function to take string slices, which are references,
because we dont want the `longest` function to take ownership of its
@ -161,7 +161,7 @@ discussion about why the parameters we use in Listing 10-20 are the ones we
want.
If we try to implement the `longest` function as shown in Listing 10-21, it
wont compile:
wont compile.
<span class="filename">Filename: src/main.rs</span>
@ -201,8 +201,8 @@ reference to `y`!
When were defining this function, we dont know the concrete values that will
be passed into this function, so we dont know whether the `if` case or the
`else` case will execute. We also dont know the concrete lifetimes of the
references that will be passed in, so we cant look at the scopes like we did
in Listings 10-18 and 10-19 to determine that the reference we return will
references that will be passed in, so we cant look at the scopes as we did in
Listings 10-18 and 10-19 to determine whether the reference we return will
always be valid. The borrow checker cant determine this either, because it
doesnt know how the lifetimes of `x` and `y` relate to the lifetime of the
return value. To fix this error, well add generic lifetime parameters that
@ -212,14 +212,14 @@ perform its analysis.
### Lifetime Annotation Syntax
Lifetime annotations dont change how long any of the references live. Just
like functions can accept any type when the signature specifies a generic type
as functions can accept any type when the signature specifies a generic type
parameter, functions can accept references with any lifetime by specifying a
generic lifetime parameter. Lifetime annotations describe the relationships of
the lifetimes of multiple references to each other without affecting the
lifetimes.
Lifetime annotations have a slightly unusual syntax: the names of lifetime
parameters must start with an apostrophe `'` and are usually all lowercase and
parameters must start with an apostrophe (`'`) and are usually all lowercase and
very short, like generic types. Most people use the name `'a`. We place
lifetime parameter annotations after the `&` of a reference, using a space to
separate the annotation from the references type.
@ -234,7 +234,7 @@ reference to an `i32` that also has the lifetime `'a`.
&'a mut i32 // a mutable reference with an explicit lifetime
```
One lifetime annotation by itself doesnt have much meaning because the
One lifetime annotation by itself doesnt have much meaning, because the
annotations are meant to tell Rust how generic lifetime parameters of multiple
references relate to each other. For example, lets say we have a function with
the parameter `first` that is a reference to an `i32` with lifetime `'a`. The
@ -250,8 +250,8 @@ function. As with generic type parameters, we need to declare generic lifetime
parameters inside angle brackets between the function name and the parameter
list. The constraint we want to express in this signature is that all the
references in the parameters and the return value must have the same lifetime.
Well name the lifetime `'a`, and then add it to each reference, as shown in
Listing 10-22:
Well name the lifetime `'a` and then add it to each reference, as shown in
Listing 10-22.
<span class="filename">Filename: src/main.rs</span>
@ -302,7 +302,7 @@ lifetimes of `x` and `y`.
Lets look at how the lifetime annotations restrict the `longest` function by
passing in references that have different concrete lifetimes. Listing 10-23 is
a straightforward example:
a straightforward example.
<span class="filename">Filename: src/main.rs</span>
@ -341,7 +341,7 @@ declaration of the `result` variable outside the inner scope but leave the
assignment of the value to the `result` variable inside the scope with
`string2`. Then well move the `println!` that uses `result` outside the inner
scope, after the inner scope has ended. The code in Listing 10-24 will not
compile:
compile.
<span class="filename">Filename: src/main.rs</span>
@ -358,7 +358,7 @@ fn main() {
```
<span class="caption">Listing 10-24: Attempting to use `result` after `string2`
has gone out of scope; the code wont compile</span>
has gone out of scope</span>
When we try to compile this code, well get this error:
@ -381,7 +381,7 @@ this because we annotated the lifetimes of the function parameters and return
values using the same lifetime parameter `'a`.
As humans, we can look at this code and see that `string1` is longer than
`string2`, and therefore `result` will contain a reference to `string1`.
`string2` and therefore `result` will contain a reference to `string1`.
Because `string1` has not gone out of scope yet, a reference to `string1` will
still be valid for the `println!` statement. However, the compiler cant see
that the reference is valid in this case. Weve told Rust that the lifetime of
@ -473,7 +473,7 @@ would create dangling pointers or otherwise violate memory safety.
So far, weve only defined structs to hold owned types. Its possible for
structs to hold references, but in that case we would need to add a lifetime
annotation on every reference in the structs definition. Listing 10-25 has a
struct named `ImportantExcerpt` that holds a string slice:
struct named `ImportantExcerpt` that holds a string slice.
<span class="filename">Filename: src/main.rs</span>
@ -512,8 +512,8 @@ the `ImportantExcerpt` goes out of scope, so the reference in the
Youve learned that every reference has a lifetime and that you need to specify
lifetime parameters for functions or structs that use references. However, in
Chapter 4 we had a function in the “String Slices” section, which is shown again
in Listing 10-26, that compiled without lifetime annotations:
Chapter 4 we had a function in Listing 4-9, which is shown again in Listing
10-26, that compiled without lifetime annotations.
<span class="filename">Filename: src/lib.rs</span>
@ -531,7 +531,7 @@ fn first_word(s: &str) -> &str {
}
```
<span class="caption">Listing 10-26: A function we defined in Chapter 4 that
<span class="caption">Listing 10-26: A function we defined in Listing 4-9 that
compiled without lifetime annotations, even though the parameter and return
type are references</span>
@ -548,8 +548,8 @@ After writing a lot of Rust code, the Rust team found that Rust programmers
were entering the same lifetime annotations over and over in particular
situations. These situations were predictable and followed a few deterministic
patterns. The developers programmed these patterns into the compilers code so
the borrow checker could infer the lifetimes in these situations and not need
explicit annotations.
the borrow checker could infer the lifetimes in these situations and wouldnt
need explicit annotations.
This piece of Rust history is relevant because its possible that more
deterministic patterns will emerge and be added to the compiler. In the future,
@ -601,7 +601,8 @@ fn first_word(s: &str) -> &str {
```
Then the compiler applies the first rule, which specifies that each parameter
gets its own lifetime. Well call it `'a` as usual, so now the signature is:
gets its own lifetime. Well call it `'a` as usual, so now the signature is
this:
```rust,ignore
fn first_word<'a>(s: &'a str) -> &str {
@ -705,8 +706,11 @@ and all lifetimes have been accounted for.
One special lifetime we need to discuss is `'static`, which denotes the entire
duration of the program. All string literals have the `'static` lifetime, which
we can annotate as follows: `let s: &'static str = "I have a static
lifetime.";`.
we can annotate as follows:
```rust
let s: &'static str = "I have a static lifetime.";
```
The text of this string is stored directly in the binary of your program, which
is always available. Therefore, the lifetime of all string literals is
@ -763,6 +767,5 @@ analysis happens at compile time, which doesnt affect runtime performance!
Believe it or not, there is much more to learn on the topics we discussed in
this chapter: Chapter 17 discusses trait objects, which are another way to use
traits. Chapter 19 covers more complex scenarios involving lifetime annotations
as well as some advanced type system features. But in the next chapter, youll
learn how to write tests in Rust so you can make sure your code is working the
way it should.
as well as some advanced type system features. But next, youll learn how to
write tests in Rust so you can make sure your code is working the way it should.

View File

@ -5,7 +5,7 @@ Lets create a new project with, as always, `cargo new`. Well call our proj
on your system.
```text
$ cargo new --bin minigrep
$ cargo new minigrep
Created binary (application) `minigrep` project
$ cd minigrep
```

View File

@ -32,7 +32,7 @@ shown in Listing 12-4:
```rust,should_panic
use std::env;
use std::fs::File;
use std::fs;
use std::io::prelude::*;
fn main() {
@ -45,11 +45,8 @@ fn main() {
// --snip--
println!("In file {}", filename);
let mut f = File::open(filename).expect("file not found");
let mut contents = String::new();
f.read_to_string(&mut contents)
.expect("something went wrong reading the file");
let contents = fs::read_to_string(filename)
.expect("Something went wrong reading the file");
println!("With text:\n{}", contents);
}
@ -59,22 +56,18 @@ fn main() {
by the second argument</span>
First, we add some more `use` statements to bring in relevant parts of the
standard library: we need `std::fs::File` to handle files, and
standard library: we need `std::fs` to handle files, and
`std::io::prelude::*` contains various useful traits for doing I/O, including
file I/O. In the same way that Rust has a general prelude that brings certain
types and functions into scope automatically, the `std::io` module has its own
prelude of common types and functions youll need when working with I/O. Unlike
with the default prelude, we must explicitly add a `use` statement for the
prelude from `std::io`.
types and functions into scope automatically, the `std::io` module has its
own prelude of common types and functions youll need when working with I/O.
Unlike with the default prelude, we must explicitly add a `use` statement for
the prelude from `std::io`.
In `main`, weve added three statements: first, we get a mutable handle to the
file by calling the `File::open` function and passing it the value of the
`filename` variable. Second, we create a variable called `contents` and set it
to a mutable, empty `String`. This will hold the content of the file after we
read it in. Third, we call `read_to_string` on our file handle and pass a
mutable reference to `contents` as an argument.
In `main`, weve added a new statement: `fs::read_to_string` will take the
`filename`, open that file, and then produce a new `String` with its contents.
After those lines, weve again added a temporary `println!` statement that
After that lines, weve again added a temporary `println!` statement that
prints the value of `contents` after the file is read, so we can check that the
program is working so far.

View File

@ -136,7 +136,7 @@ the struct fields rather than having separate variables:
```rust,should_panic
# use std::env;
# use std::fs::File;
# use std::fs;
#
fn main() {
let args: Vec<String> = env::args().collect();
@ -146,7 +146,8 @@ fn main() {
println!("Searching for {}", config.query);
println!("In file {}", config.filename);
let mut f = File::open(config.filename).expect("file not found");
let contents = fs::read_to_string(config.filename)
.expect("Something went wrong reading the file");
// --snip--
}
@ -466,10 +467,7 @@ fn main() {
}
fn run(config: Config) {
let mut f = File::open(config.filename).expect("file not found");
let mut contents = String::new();
f.read_to_string(&mut contents)
let contents = fs::read_to_string(config.filename)
.expect("something went wrong reading the file");
println!("With text:\n{}", contents);
@ -502,11 +500,8 @@ use std::error::Error;
// --snip--
fn run(config: Config) -> Result<(), Box<Error>> {
let mut f = File::open(config.filename)?;
let mut contents = String::new();
f.read_to_string(&mut contents)?;
fn run(config: Config) -> Result<(), Box<dyn Error>> {
let contents = fs::read_to_string(config.filename)?;
println!("With text:\n{}", contents);
@ -518,19 +513,20 @@ fn run(config: Config) -> Result<(), Box<Error>> {
`Result`</span>
Weve made three significant changes here. First, we changed the return type of
the `run` function to `Result<(), Box<Error>>`. This function previously
the `run` function to `Result<(), Box<dyn Error>>`. This function previously
returned the unit type, `()`, and we keep that as the value returned in the
`Ok` case.
For the error type, we used the *trait object* `Box<Error>` (and weve brought
`std::error::Error` into scope with a `use` statement at the top). Well cover
trait objects in Chapter 17. For now, just know that `Box<Error>` means the
function will return a type that implements the `Error` trait, but we dont
have to specify what particular type the return value will be. This gives us
flexibility to return error values that may be of different types in different
error cases.
For the error type, we used the *trait object* `Box<dyn Error>` (and weve
brought `std::error::Error` into scope with a `use` statement at the top).
Well cover trait objects in Chapter 17. For now, just know that `Box<dyn
Error>` means the function will return a type that implements the `Error`
trait, but we dont have to specify what particular type the return value
will be. This gives us flexibility to return error values that may be of
different types in different error cases. This is what the `dyn` means, it's
short for "dynamic."
Second, weve removed the calls to `expect` in favor of `?`, as we talked about
Second, weve removed the call to `expect` in favor of `?`, as we talked about
in Chapter 9. Rather than `panic!` on an error, `?` will return the error value
from the current function for the caller to handle.
@ -625,7 +621,7 @@ impl Config {
}
}
pub fn run(config: Config) -> Result<(), Box<Error>> {
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
// --snip--
}
```

View File

@ -276,11 +276,10 @@ will print each line returned from `search`:
<span class="filename">Filename: src/lib.rs</span>
```rust,ignore
pub fn run(config: Config) -> Result<(), Box<Error>> {
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
let mut f = File::open(config.filename)?;
let mut contents = String::new();
f.read_to_string(&mut contents)?;
let contents = fs::read_to_string(config.filename)?;
for line in search(&config.query, &contents) {
println!("{}", line);

View File

@ -155,7 +155,7 @@ wont compile yet:
```rust
# use std::error::Error;
# use std::fs::File;
# use std::fs::{self, File};
# use std::io::prelude::*;
#
# fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
@ -166,17 +166,14 @@ wont compile yet:
# vec![]
# }
#
# struct Config {
# pub struct Config {
# query: String,
# filename: String,
# case_sensitive: bool,
# }
#
pub fn run(config: Config) -> Result<(), Box<Error>> {
let mut f = File::open(config.filename)?;
let mut contents = String::new();
f.read_to_string(&mut contents)?;
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
let contents = fs::read_to_string(config.filename)?;
let results = if config.case_sensitive {
search(&config.query, &contents)

View File

@ -469,10 +469,10 @@ closure we want to store in the `calculation` field must have one `u32`
parameter (specified within the parentheses after `Fn`) and must return a
`u32` (specified after the `->`).
> Note: Functions implement all three of the `Fn` traits too. If what we want
> to do doesnt require capturing a value from the environment, we can use a
> function rather than a closure where we need something that implements an `Fn`
> trait.
> Note: Functions can implement all three of the `Fn` traits too. If what we
> want to do doesnt require capturing a value from the environment, we can use
> a function rather than a closure where we need something that implements an
> `Fn` trait.
The `value` field is of type `Option<u32>`. Before we execute the closure,
`value` will be `None`. When code using a `Cacher` asks for the *result* of the

View File

@ -44,7 +44,7 @@ Next, well create the `adder` binary crate by running `cargo new` within the
*add* directory:
```text
$ cargo new --bin adder
$ cargo new adder
Created binary (application) `adder` project
```
@ -92,7 +92,7 @@ members = [
Then generate a new library crate named `add-one`:
```text
$ cargo new add-one
$ cargo new add-one --lib
Created library `add-one` project
```

View File

@ -14,6 +14,11 @@ smart pointers to work in a similar way as references. Then well look at
Rusts *deref coercion* feature and how it lets us work with either references
or smart pointers.
> There's one big difference between the `MyBox<T>` type we're about to build
> and the real `Box<T>`: our version will not store its data on the heap. We
> are focusing this example on `Deref`, and so where the data is actually stored
> is less important than the pointer-like behavior.
### Following the Pointer to the Value with the Dereference Operator
A regular reference is a type of pointer, and one way to think of a pointer is

View File

@ -43,12 +43,13 @@ To implement the behavior we want `gui` to have, well define a trait named
takes a *trait object*. A trait object points to an instance of a type that
implements the trait we specify. We create a trait object by specifying some
sort of pointer, such as a `&` reference or a `Box<T>` smart pointer, and then
specifying the relevant trait. (Well talk about the reason trait objects must
use a pointer in Chapter 19 in the section “Dynamically Sized Types & Sized”.)
We can use trait objects in place of a generic or concrete type. Wherever we
use a trait object, Rusts type system will ensure at compile time that any
value used in that context will implement the trait objects trait.
Consequently, we dont need to know all the possible types at compile time.
specifying the relevant trait, and add a `dyn` keyword. (Well talk about the
reason trait objects must use a pointer in Chapter 19 in the section
“Dynamically Sized Types & Sized”.) We can use trait objects in place of a
generic or concrete type. Wherever we use a trait object, Rusts type system
will ensure at compile time that any value used in that context will
implement the trait objects trait. Consequently, we dont need to know all
the possible types at compile time.
Weve mentioned that in Rust, we refrain from calling structs and enums
“objects” to distinguish them from other languages objects. In a struct or
@ -77,8 +78,8 @@ pub trait Draw {
This syntax should look familiar from our discussions on how to define traits
in Chapter 10. Next comes some new syntax: Listing 17-4 defines a struct named
`Screen` that holds a vector named `components`. This vector is of type
`Box<Draw>`, which is a trait object; its a stand-in for any type inside a
`Box` that implements the `Draw` trait.
`Box<dyn Draw>`, which is a trait object; its a stand-in for any type inside
a `Box` that implements the `Draw` trait.
<span class="filename">Filename: src/lib.rs</span>
@ -88,7 +89,7 @@ in Chapter 10. Next comes some new syntax: Listing 17-4 defines a struct named
# }
#
pub struct Screen {
pub components: Vec<Box<Draw>>,
pub components: Vec<Box<dyn Draw>>,
}
```
@ -107,7 +108,7 @@ On the `Screen` struct, well define a method named `run` that will call the
# }
#
# pub struct Screen {
# pub components: Vec<Box<Draw>>,
# pub components: Vec<Box<dyn Draw>>,
# }
#
impl Screen {
@ -280,8 +281,8 @@ then it must be a duck! In the implementation of `run` on `Screen` in Listing
17-5, `run` doesnt need to know what the concrete type of each component is.
It doesnt check whether a component is an instance of a `Button` or a
`SelectBox`, it just calls the `draw` method on the component. By specifying
`Box<Draw>` as the type of the values in the `components` vector, weve defined
`Screen` to need values that we can call the `draw` method on.
`Box<dyn Draw>` as the type of the values in the `components` vector, weve
defined `Screen` to need values that we can call the `draw` method on.
The advantage of using trait objects and Rusts type system to write code
similar to code using duck typing is that we never have to check whether a
@ -397,7 +398,7 @@ implement the `Clone` trait instead of the `Draw` trait, like this:
```rust,ignore
pub struct Screen {
pub components: Vec<Box<Clone>>,
pub components: Vec<Box<dyn Clone>>,
}
```
@ -407,7 +408,7 @@ We would get this error:
error[E0038]: the trait `std::clone::Clone` cannot be made into an object
--> src/lib.rs:2:5
|
2 | pub components: Vec<Box<Clone>>,
2 | pub components: Vec<Box<dyn Clone>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` cannot be
made into an object
|

View File

@ -83,15 +83,15 @@ Lets get started on the implementation of the library! We know we need a
public `Post` struct that holds some content, so well start with the
definition of the struct and an associated public `new` function to create an
instance of `Post`, as shown in Listing 17-12. Well also make a private
`State` trait. Then `Post` will hold a trait object of `Box<State>` inside an
`Option` in a private field named `state`. Youll see why the `Option` is
necessary in a bit.
`State` trait. Then `Post` will hold a trait object of `Box<dyn State>`
inside an `Option<T>` in a private field named `state`. Youll see why the
`Option<T>` is necessary in a bit.
<span class="filename">Filename: src/lib.rs</span>
```rust
pub struct Post {
state: Option<Box<State>>,
state: Option<Box<dyn State>>,
content: String,
}
@ -204,7 +204,7 @@ change its state from `Draft` to `PendingReview`. Listing 17-15 shows this code:
```rust
# pub struct Post {
# state: Option<Box<State>>,
# state: Option<Box<dyn State>>,
# content: String,
# }
#
@ -218,13 +218,13 @@ impl Post {
}
trait State {
fn request_review(self: Box<Self>) -> Box<State>;
fn request_review(self: Box<Self>) -> Box<dyn State>;
}
struct Draft {}
impl State for Draft {
fn request_review(self: Box<Self>) -> Box<State> {
fn request_review(self: Box<Self>) -> Box<dyn State> {
Box::new(PendingReview {})
}
}
@ -232,7 +232,7 @@ impl State for Draft {
struct PendingReview {}
impl State for PendingReview {
fn request_review(self: Box<Self>) -> Box<State> {
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
}
@ -293,7 +293,7 @@ state is approved, as shown in Listing 17-16:
```rust
# pub struct Post {
# state: Option<Box<State>>,
# state: Option<Box<dyn State>>,
# content: String,
# }
#
@ -307,19 +307,19 @@ impl Post {
}
trait State {
fn request_review(self: Box<Self>) -> Box<State>;
fn approve(self: Box<Self>) -> Box<State>;
fn request_review(self: Box<Self>) -> Box<dyn State>;
fn approve(self: Box<Self>) -> Box<dyn State>;
}
struct Draft {}
impl State for Draft {
# fn request_review(self: Box<Self>) -> Box<State> {
# fn request_review(self: Box<Self>) -> Box<dyn State> {
# Box::new(PendingReview {})
# }
#
// --snip--
fn approve(self: Box<Self>) -> Box<State> {
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
}
@ -327,12 +327,12 @@ impl State for Draft {
struct PendingReview {}
impl State for PendingReview {
# fn request_review(self: Box<Self>) -> Box<State> {
# fn request_review(self: Box<Self>) -> Box<dyn State> {
# self
# }
#
// --snip--
fn approve(self: Box<Self>) -> Box<State> {
fn approve(self: Box<Self>) -> Box<dyn State> {
Box::new(Published {})
}
}
@ -340,11 +340,11 @@ impl State for PendingReview {
struct Published {}
impl State for Published {
fn request_review(self: Box<Self>) -> Box<State> {
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
fn approve(self: Box<Self>) -> Box<State> {
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
}
@ -374,7 +374,7 @@ otherwise, we want to return an empty string slice, as shown in Listing 17-17:
# fn content<'a>(&self, post: &'a Post) -> &'a str;
# }
# pub struct Post {
# state: Option<Box<State>>,
# state: Option<Box<dyn State>>,
# content: String,
# }
#
@ -397,7 +397,7 @@ returned from using the `content` method on the `state` value.
We call the `as_ref` method on the `Option` because we want a reference to the
value inside the `Option` rather than ownership of the value. Because `state`
is an `Option<Box<State>>`, when we call `as_ref`, an `Option<&Box<State>>` is
is an `Option<Box<dyn State>>`, when we call `as_ref`, an `Option<&Box<dyn State>>` is
returned. If we didnt call `as_ref`, we would get an error because we cant
move `state` out of the borrowed `&self` of the function parameter.
@ -408,7 +408,7 @@ the “Cases When You Have More Information Than the Compiler” section of Chap
9 when we know that a `None` value is never possible, even though the compiler
isnt able to understand that.
At this point, when we call `content` on the `&Box<State>`, deref coercion will
At this point, when we call `content` on the `&Box<dyn State>`, deref coercion will
take effect on the `&` and the `Box` so the `content` method will ultimately be
called on the type that implements the `State` trait. That means we need to add
`content` to the `State` trait definition, and that is where well put the

View File

@ -17,12 +17,12 @@ to continue running a particular piece of code.
To use a pattern, we compare it to some value. If the pattern matches the
value, we use the value parts in our code. Recall the `match` expressions in
Chapter 6 that used patterns, such as the coin sorting machine example. If the
Chapter 6 that used patterns, such as the coin-sorting machine example. If the
value fits the shape of the pattern, we can use the named pieces. If it
doesnt, the code associated with the pattern wont run.
This chapter is a reference on all things related to patterns. Well cover the
valid places to use patterns, the difference between *refutable* and
*irrefutable* patterns, and the different kinds of pattern syntax that you
might see. By the end of the chapter, youll know how to use patterns to
express many concepts in a clear way.
valid places to use patterns, the difference between refutable and irrefutable
patterns, and the different kinds of pattern syntax that you might see. By the
end of the chapter, youll know how to use patterns to express many concepts in
a clear way.

View File

@ -1,8 +1,8 @@
## All the Places Patterns Can Be Used
Patterns pop up in a number of places in Rust, and youve been using them a lot
without realizing it! This section provides you with a reference to all the
places where patterns are valid.
without realizing it! This section discusses all the places where patterns are
valid.
### `match` Arms
@ -40,20 +40,14 @@ the pattern in the `if let` doesnt match.
Listing 18-1 shows that its also possible to mix and match `if let`, `else
if`, and `else if let` expressions. Doing so gives us more flexibility than a
`match` expression in which we can only express one value to compare with the
`match` expression in which we can express only one value to compare with the
patterns. Also, the conditions in a series of `if let`, `else if`, `else if
let` arms arent required to relate to each other.
The code in Listing 18-1 shows a series of checks for several different
conditions that decide what the background color should be. For this example,
weve created variables with hardcoded values that a real program might receive
from user input.
If the user specifies a favorite color, that color is the background color. If
today is Tuesday, the background color will be green. If the user specifies
their age as a string and we can parse it as a number successfully, the color
is either purple or orange depending on the value of the number. If none of
these conditions apply, the background color will be blue:
The code in Listing 18-1 shows a series of checks for several conditions that
decide what the background color should be. For this example, weve created
variables with hardcoded values that a real program might receive from user
input.
<span class="filename">Filename: src/main.rs</span>
@ -82,6 +76,12 @@ fn main() {
<span class="caption">Listing 18-1: Mixing `if let`, `else if`, `else if let`,
and `else`</span>
If the user specifies a favorite color, that color is the background color. If
today is Tuesday, the background color is green. If the user specifies
their age as a string and we can parse it as a number successfully, the color
is either purple or orange depending on the value of the number. If none of
these conditions apply, the background color is blue.
This conditional structure lets us support complex requirements. With the
hardcoded values we have here, this example will print `Using purple as the
background color`.
@ -104,7 +104,7 @@ not alert us to the possible logic bug.
Similar in construction to `if let`, the `while let` conditional loop allows a
`while` loop to run for as long as a pattern continues to match. The example in
Listing 18-2 shows a `while let` loop that uses a vector as a stack and prints
out the values in the vector in the opposite order in which they were pushed:
the values in the vector in the opposite order in which they were pushed.
```rust
let mut stack = Vec::new();
@ -118,8 +118,8 @@ while let Some(top) = stack.pop() {
}
```
<span class="caption">Listing 18-2: Using a `while let` loop to print out
values for as long as `stack.pop()` returns `Some`</span>
<span class="caption">Listing 18-2: Using a `while let` loop to print values
for as long as `stack.pop()` returns `Some`</span>
This example prints 3, 2, and then 1. The `pop` method takes the last element
out of the vector and returns `Some(value)`. If the vector is empty, `pop`
@ -129,13 +129,13 @@ use `while let` to pop every element off our stack.
### `for` Loops
In Chapter 3 we mentioned that the `for` loop is the most common loop
In Chapter 3, we mentioned that the `for` loop is the most common loop
construction in Rust code, but we havent yet discussed the pattern that `for`
takes. In a `for` loop, the pattern is the value that directly follows the
keyword `for`, so in `for x in y` the `x` is the pattern.
Listing 18-3 demonstrates how to use a pattern in a `for` loop to destructure,
or break apart, a tuple as part of the `for` loop:
or break apart, a tuple as part of the `for` loop.
```rust
let v = vec!['a', 'b', 'c'];
@ -189,7 +189,7 @@ the variable `x`.” Because the name `x` is the whole pattern, this pattern
effectively means “bind everything to the variable `x`, whatever the value is.”
To see the pattern matching aspect of `let` more clearly, consider Listing
18-4, which uses a pattern with `let` to destructure a tuple:
18-4, which uses a pattern with `let` to destructure a tuple.
```rust
let (x, y, z) = (1, 2, 3);
@ -206,7 +206,7 @@ pattern as nesting three individual variable patterns inside it.
If the number of elements in the pattern doesnt match the number of elements
in the tuple, the overall type wont match and well get a compiler error. For
example, Listing 18-5 shows an attempt to destructure a tuple with three
elements into two variables, which wont work:
elements into two variables, which wont work.
```rust,ignore
let (x, y) = (1, 2, 3);
@ -229,7 +229,7 @@ error[E0308]: mismatched types
```
If we wanted to ignore one or more of the values in the tuple, we could use `_`
or `..` as youll see in the “Ignoring Values in a Pattern” section. If the
or `..`, as youll see in the “Ignoring Values in a Pattern” section. If the
problem is that we have too many variables in the pattern, the solution is to
make the types match by removing variables so the number of variables equals
the number of elements in the tuple.
@ -238,7 +238,7 @@ the number of elements in the tuple.
Function parameters can also be patterns. The code in Listing 18-6, which
declares a function named `foo` that takes one parameter named `x` of type
`i32`, should by now look familiar:
`i32`, should by now look familiar.
```rust
fn foo(x: i32) {
@ -251,7 +251,7 @@ parameters</span>
The `x` part is a pattern! As we did with `let`, we could match a tuple in a
functions arguments to the pattern. Listing 18-7 splits the values in a tuple
as we pass it to a function:
as we pass it to a function.
<span class="filename">Filename: src/main.rs</span>
@ -278,5 +278,5 @@ discussed in Chapter 13.
At this point, youve seen several ways of using patterns, but patterns dont
work the same in every place we can use them. In some places, the patterns must
be *irrefutable*, meaning they must match any value provided. In other
circumstances, they can be refutable. Lets discuss these two concepts next.
be irrefutable; in other circumstances, they can be refutable. Well discuss
these two concepts next.

View File

@ -5,8 +5,8 @@ for any possible value passed are *irrefutable*. An example would be `x` in the
statement `let x = 5;` because `x` matches anything and therefore cannot fail
to match. Patterns that can fail to match for some possible value are
*refutable*. An example would be `Some(x)` in the expression `if let Some(x) =
a_value`; if the value in `a_value` variable is `None` rather than `Some`, the
`Some(x)` pattern would not match.
a_value` because if the value in the `a_value` variable is `None` rather than
`Some`, the `Some(x)` pattern will not match.
Function parameters, `let` statements, and `for` loops can only accept
irrefutable patterns, because the program cannot do anything meaningful when
@ -24,7 +24,7 @@ using the pattern with, depending on the intended behavior of the code.
Lets look at an example of what happens when we try to use a refutable pattern
where Rust requires an irrefutable pattern and vice versa. Listing 18-8 shows a
`let` statement, but for the pattern weve specified `Some(x)`, a refutable
pattern. As you might expect, this code will error:
pattern. As you might expect, this code will not compile.
```rust,ignore
let Some(x) = some_option_value;
@ -54,7 +54,7 @@ To fix the problem where we have a refutable pattern where an irrefutable
pattern is needed, we can change the code that uses the pattern: instead of
using `let`, we can use `if let`. Then if the pattern doesnt match, the code
will just skip the code in the curly brackets, giving it a way to continue
validly. Listing 18-9 shows how to fix the code in Listing 18-8:
validly. Listing 18-9 shows how to fix the code in Listing 18-8.
```rust
# let some_option_value: Option<i32> = None;
@ -69,7 +69,7 @@ patterns instead of `let`</span>
Weve given the code an out! This code is perfectly valid, although it means we
cannot use an irrefutable pattern without receiving an error. If we give `if
let` a pattern that will always match, such as `x`, as shown in Listing 18-10,
it will error:
it will not compile.
```rust,ignore
if let x = 5 {

View File

@ -1,8 +1,8 @@
## All the Pattern Syntax
## Pattern Syntax
Throughout the book, youve seen examples of many different kinds of patterns.
In this section, we gather all the syntax valid in patterns and discuss why you
might want to use each of them.
Throughout the book, youve seen examples of many kinds of patterns. In this
section, we gather all the syntax valid in patterns and discuss why you might
want to use each one.
### Matching Literals
@ -35,7 +35,7 @@ with all variables. In Listing 18-11, we declare a variable named `x` with the
value `Some(5)` and a variable `y` with the value `10`. We then create a
`match` expression on the value `x`. Look at the patterns in the match arms and
`println!` at the end, and try to figure out what the code will print before
running this code or reading further:
running this code or reading further.
<span class="filename">Filename: src/main.rs</span>
@ -152,7 +152,7 @@ to use different parts of these values. Lets walk through each value.
#### Destructuring Structs
Listing 18-12 shows a `Point` struct with two fields, `x` and `y`, that we can
break apart using a pattern with a `let` statement:
break apart using a pattern with a `let` statement.
<span class="filename">Filename: src/main.rs</span>
@ -186,7 +186,7 @@ shorthand for patterns that match struct fields: you only need to list the name
of the struct field, and the variables created from the pattern will have the
same names. Listing 18-13 shows code that behaves in the same way as the code
in Listing 18-12, but the variables created in the `let` pattern are `x` and
`y` instead of `a` and `b`:
`y` instead of `a` and `b`.
<span class="filename">Filename: src/main.rs</span>
@ -219,7 +219,7 @@ destructure the other fields.
Listing 18-14 shows a `match` expression that separates `Point` values into
three cases: points that lie directly on the `x` axis (which is true when `y =
0`), on the `y` axis (`x = 0`), or neither:
0`), on the `y` axis (`x = 0`), or neither.
<span class="filename">Filename: src/main.rs</span>
@ -262,7 +262,7 @@ destructured `Option<i32>` in Listing 6-5 in Chapter 6. One detail we havent
mentioned explicitly is that the pattern to destructure an enum should
correspond to the way the data stored within the enum is defined. As an
example, in Listing 18-15 we use the `Message` enum from Listing 6-2 and write
a `match` with patterns that will destructure each inner value:
a `match` with patterns that will destructure each inner value.
<span class="filename">Filename: src/main.rs</span>
@ -323,6 +323,51 @@ pattern is similar to the pattern we specify to match tuples. The number of
variables in the pattern must match the number of elements in the variant were
matching.
#### Destructuring Nested Structs & Enums
Up until now, all of our examples have been matching structures that were one
level deep. Matching can work on nested structures too!
We can refactor the example above to support both RGB and HSV colors:
```rust
enum Color {
Rgb(i32, i32, i32),
Hsv(i32, i32, i32)
}
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(Color),
}
fn main() {
let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));
match msg {
Message::ChangeColor(Color::Rgb(r, g, b)) => {
println!(
"Change the color to red {}, green {}, and blue {}",
r,
g,
b
)
},
Message::ChangeColor(Color::Hsv(h, s, v)) => {
println!(
"Change the color to hue {}, saturation {}, and value {}",
h,
s,
v
)
}
_ => ()
}
}
```
#### Destructuring References
When the value were matching to our pattern contains a reference, we need to
@ -334,8 +379,8 @@ iterate over references, but we want to use the values in the closure rather
than the references.
The example in Listing 18-16 iterates over references to `Point` instances in a
vector, and destructures the reference and the struct so we can perform
calculations on the `x` and `y` values easily:
vector, destructuring the reference and the struct so we can perform
calculations on the `x` and `y` values easily.
```rust
# struct Point {
@ -363,7 +408,7 @@ is the result of squaring the `x` value and the `y` value, adding those
together, and then adding the result for each `Point` in the `points` vector to
get one number.
If we had not included the `&` in `&Point { x, y }` wed get a type mismatch
If we had not included the `&` in `&Point { x, y }`, wed get a type mismatch
error, because `iter` would then iterate over references to the items in the
vector rather than the actual values. The error would look like this:
@ -385,7 +430,7 @@ we tried to match directly to a `Point` value, not a reference to a `Point`.
We can mix, match, and nest destructuring patterns in even more complex ways.
The following example shows a complicated destructure where we nest structs and
tuples inside a tuple, and destructure all the primitive values out:
tuples inside a tuple and destructure all the primitive values out:
```rust
# struct Point {
@ -414,10 +459,10 @@ parts of a value. Lets explore how and why to use each of these patterns.
#### Ignoring an Entire Value with `_`
Weve used the underscore `_` as a wildcard pattern that will match any value
Weve used the underscore (`_`) as a wildcard pattern that will match any value
but not bind to the value. Although the underscore `_` pattern is especially
useful as the last arm in a `match` expression, we can use it in any pattern,
including function parameters, as shown in Listing 18-17:
including function parameters, as shown in Listing 18-17.
<span class="filename">Filename: src/main.rs</span>
@ -438,7 +483,7 @@ and will print `This code only uses the y parameter: 4`.
In most cases when you no longer need a particular function parameter, you
would change the signature so it doesnt include the unused parameter. Ignoring
a function parameter can be especially useful in some cases: for example, when
a function parameter can be especially useful in some cases, for example, when
implementing a trait when you need a certain type signature but the function
body in your implementation doesnt need one of the parameters. The compiler
will then not warn about unused function parameters, as it would if you used a
@ -446,8 +491,8 @@ name instead.
#### Ignoring Parts of a Value with a Nested `_`
We can also use `_` inside another pattern to ignore just part of a value: for
example, when we only want to test for part of a value but have no use for the
We can also use `_` inside another pattern to ignore just part of a value, for
example, when we want to test for only part of a value but have no use for the
other parts in the corresponding code we want to run. Listing 18-18 shows code
responsible for managing a settings value. The business requirements are that
the user should not be allowed to overwrite an existing customization of a
@ -487,7 +532,7 @@ In all other cases (if either `setting_value` or `new_setting_value` are
We can also use underscores in multiple places within one pattern to ignore
particular values. Listing 18-19 shows an example of ignoring the second and
fourth values in a tuple of five items:
fourth values in a tuple of five items.
```rust
let numbers = (2, 4, 8, 16, 32);
@ -504,7 +549,7 @@ match numbers {
This code will print `Some numbers: 2, 8, 32`, and the values 4 and 16 will be
ignored.
#### Ignoring an Unused Variable by Starting Its Name with an Underscore
#### Ignoring an Unused Variable by Starting Its Name with `_`
If you create a variable but dont use it anywhere, Rust will usually issue a
warning because that could be a bug. But sometimes its useful to create a
@ -532,7 +577,7 @@ warning about not using the variable preceded by the underscore.
Note that there is a subtle difference between using only `_` and using a name
that starts with an underscore. The syntax `_x` still binds the value to the
variable, whereas `_` doesnt bind at all. To show a case where this
distinction matters, Listing 18-21 will provide us with an error:
distinction matters, Listing 18-21 will provide us with an error.
```rust,ignore
let s = Some(String::from("Hello!"));
@ -550,7 +595,7 @@ underscore still binds the value, which might take ownership of the value</span>
Well receive an error because the `s` value will still be moved into `_s`,
which prevents us from using `s` again. However, using the underscore by itself
doesnt ever bind to the value. Listing 18-22 will compile without any errors
because `s` doesnt get moved into `_`:
because `s` doesnt get moved into `_`.
```rust
let s = Some(String::from("Hello!"));
@ -570,12 +615,12 @@ This code works just fine because we never bind `s` to anything; it isnt move
#### Ignoring Remaining Parts of a Value with `..`
With values that have many parts, we can use the `..` syntax to use only a few
parts and ignore the rest, and avoid having to list underscores for each
parts and ignore the rest, avoiding the need to list underscores for each
ignored value. The `..` pattern ignores any parts of a value that we havent
explicitly matched in the rest of the pattern. In Listing 18-23, we have a
`Point` struct that holds a coordinate in three-dimensional space. In the
`match` expression, we want to operate only on the `x` coordinate and ignore
the values in the `y` and `z` fields:
the values in the `y` and `z` fields.
```rust
struct Point {
@ -594,13 +639,13 @@ match origin {
<span class="caption">Listing 18-23: Ignoring all fields of a `Point` except
for `x` by using `..`</span>
We list the `x` value, and then just include the `..` pattern. This is quicker
We list the `x` value and then just include the `..` pattern. This is quicker
than having to list `y: _` and `z: _`, particularly when were working with
structs that have lots of fields in situations where only one or two fields are
relevant.
The syntax `..` will expand to as many values as it needs to be. Listing 18-24
shows how to use `..` with a tuple:
shows how to use `..` with a tuple.
<span class="filename">Filename: src/main.rs</span>
@ -623,8 +668,9 @@ In this code, the first and last value are matched with `first` and `last`. The
`..` will match and ignore everything in the middle.
However, using `..` must be unambiguous. If it is unclear which values are
intended for matching and which should be ignored, Rust will error. Listing
18-25 shows an example of using `..` ambiguously, so it will not compile:
intended for matching and which should be ignored, Rust will give us an error.
Listing 18-25 shows an example of using `..` ambiguously, so it will not
compile.
<span class="filename">Filename: src/main.rs</span>
@ -654,14 +700,14 @@ error: `..` can only be used once per tuple or tuple struct pattern
```
Its impossible for Rust to determine how many values in the tuple to ignore
before matching a value with `second`, and then how many further values to
before matching a value with `second` and then how many further values to
ignore thereafter. This code could mean that we want to ignore `2`, bind
`second` to `4`, and then ignore `8`, `16`, and `32`; or that we want to ignore
`2` and `4`, bind `second` to `8`, and then ignore `16` and `32`; and so forth.
The variable name `second` doesnt mean anything special to Rust, so we get a
compiler error because using `..` in two places like this is ambiguous.
### `ref` and `ref mut` to Create References in Patterns
### Creating References in Patterns with `ref` and `ref mut`
Lets look at using `ref` to make references so ownership of the values isnt
moved to variables in the pattern. Usually, when you match against a pattern,
@ -671,7 +717,7 @@ the pattern. Listing 18-26 shows an example of a `match` that has a pattern
with a variable and then usage of the entire value in the `println!` statement
later, after the `match`. This code will fail to compile because ownership of
part of the `robot_name` value is transferred to the `name` variable in the
pattern of the first `match` arm:
pattern of the first `match` arm.
```rust,ignore
let robot_name = Some(String::from("Bors"));
@ -702,7 +748,7 @@ reference in the value. Because `&` already has that meaning in patterns, we
cant use `&` to create a reference in a pattern.
Instead, to create a reference in a pattern, we use the `ref` keyword before
the new variable, as shown in Listing 18-27:
the new variable, as shown in Listing 18-27.
```rust
let robot_name = Some(String::from("Bors"));
@ -726,7 +772,7 @@ To create a mutable reference so were able to mutate a value matched in a
pattern, we use `ref mut` instead of `&mut`. The reason is, again, that in
patterns, the latter is for matching existing mutable references, not creating
new ones. Listing 18-28 shows an example of a pattern creating a mutable
reference:
reference.
```rust
let mut robot_name = Some(String::from("Bors"));
@ -755,7 +801,7 @@ than a pattern alone allows.
The condition can use variables created in the pattern. Listing 18-29 shows a
`match` where the first arm has the pattern `Some(x)` and also has a match
guard of `if x < 5`:
guard of `if x < 5`.
```rust
let num = Some(4);
@ -783,11 +829,11 @@ There is no way to express the `if x < 5` condition within a pattern, so the
match guard gives us the ability to express this logic.
In Listing 18-11, we mentioned that we could use match guards to solve our
pattern shadowing problem. Recall that a new variable was created inside the
pattern-shadowing problem. Recall that a new variable was created inside the
pattern in the `match` expression instead of using the variable outside the
`match`. That new variable meant we couldnt test against the value of the
outer variable. Listing 18-30 shows how we can use a match guard to fix this
problem:
problem.
<span class="filename">Filename: src/main.rs</span>
@ -826,7 +872,7 @@ patterns; the match guard condition will apply to all the patterns. Listing
18-31 shows the precedence of combining a match guard with a pattern that uses
`|`. The important part of this example is that the `if y` match guard applies
to `4`, `5`, *and* `6`, even though it might look like `if y` only applies to
`6`:
`6`.
```rust
let x = 4;
@ -861,19 +907,19 @@ rather than this:
```
After running the code, the precedence behavior is evident: if the match guard
was only applied to the final value in the list of values specified using the
were applied only to the final value in the list of values specified using the
`|` operator, the arm would have matched and the program would have printed
`yes`.
### `@` Bindings
The *at* operator `@` lets us create a variable that holds a value at the same
time were testing that value to see whether it matches a pattern. Listing
The *at* operator (`@`) lets us create a variable that holds a value at the
same time were testing that value to see whether it matches a pattern. Listing
18-32 shows an example where we want to test that a `Message::Hello` `id` field
is within the range `3...7`. But we also want to bind the value to the variable
`id_variable` so we can use it in the code associated with the arm. We could
name this variable `id`, the same as the field, but for this example well use
a different name:
a different name.
```rust
enum Message {
@ -902,18 +948,18 @@ This example will print `Found an id in range: 5`. By specifying `id_variable
@` before the range `3...7`, were capturing whatever value matched the range
while also testing that the value matched the range pattern.
In the second arm where we only have a range specified in the pattern, the code
In the second arm, where we only have a range specified in the pattern, the code
associated with the arm doesnt have a variable that contains the actual value
of the `id` field. The `id` fields value could have been 10, 11, or 12, but
the code that goes with that pattern doesnt know which it is. The pattern code
isnt able to use the value from the `id` field, because we havent saved the
`id` value in a variable.
In the last arm where weve specified a variable without a range, we do have
In the last arm, where weve specified a variable without a range, we do have
the value available to use in the arms code in a variable named `id`. The
reason is that weve used the struct field shorthand syntax. But we havent
applied any test to the value in the `id` field in this arm, like we did with
the first two arms: any value would match this pattern.
applied any test to the value in the `id` field in this arm, as we did with the
first two arms: any value would match this pattern.
Using `@` lets us test a value and save it in a variable within one pattern.

View File

@ -10,13 +10,13 @@ make sure you have a grasp of all the features Rust has to offer.
In this chapter, well cover:
* Unsafe Rust: How to opt out of some of Rusts guarantees and take
* Unsafe Rust: how to opt out of some of Rusts guarantees and take
responsibility for manually upholding those guarantees
* Advanced lifetimes: Syntax for complex lifetime situations
* Advanced traits: Associated types, default type parameters, fully qualified
* Advanced lifetimes: syntax for complex lifetime situations
* Advanced traits: associated types, default type parameters, fully qualified
syntax, supertraits, and the newtype pattern in relation to traits
* Advanced types: More about the newtype pattern, type aliases, the *never*
type, and dynamically sized types
* Advanced functions and closures: Function pointers and returning closures
* Advanced types: more about the newtype pattern, type aliases, the never type,
and dynamically sized types
* Advanced functions and closures: function pointers and returning closures
Its a panoply of Rust features with something for everyone! Lets dive in!

View File

@ -7,27 +7,27 @@ and works just like regular Rust, but gives us extra superpowers.
Unsafe Rust exists because, by nature, static analysis is conservative. When
the compiler tries to determine whether or not code upholds the guarantees,
its better for it to reject some valid programs rather than accepting some
its better for it to reject some valid programs rather than accept some
invalid programs. Although the code might be okay, as far as Rust is able to
tell, its not! In these cases, we can use unsafe code to tell the compiler,
trust me, I know what Im doing.” The downside is that we use it at our own
risk: if we use unsafe code incorrectly, problems due to memory unsafety, such
tell, its not! In these cases, you can use unsafe code to tell the compiler,
Trust me, I know what Im doing.” The downside is that you use it at your own
risk: if you use unsafe code incorrectly, problems due to memory unsafety, such
as null pointer dereferencing, can occur.
Another reason Rust has an unsafe alter ego is that the underlying computer
hardware is inherently unsafe. If Rust didnt let us do unsafe operations, we
couldnt do certain tasks. Rust needs to allow us to do low-level systems
hardware is inherently unsafe. If Rust didnt let you do unsafe operations, you
couldnt do certain tasks. Rust needs to allow you to do low-level systems
programming, such as directly interacting with the operating system or even
writing our own operating system. Working with low-level systems programming is
one of the goals of the language. Lets explore what we can do with unsafe Rust
and how to do it.
writing your own operating system. Working with low-level systems programming
is one of the goals of the language. Lets explore what we can do with unsafe
Rust and how to do it.
### Unsafe Superpowers
To switch to unsafe Rust, we use the `unsafe` keyword, and then start a new
block that holds the unsafe code. We can take four actions in unsafe Rust,
which we call *unsafe superpowers*, that we cant in safe Rust. Those
superpowers include the ability to:
To switch to unsafe Rust, use the `unsafe` keyword and then start a new block
that holds the unsafe code. You can take four actions in unsafe Rust, called
*unsafe superpowers*, that you cant in safe Rust. Those superpowers include
the ability to:
* Dereference a raw pointer
* Call an unsafe function or method
@ -36,17 +36,17 @@ superpowers include the ability to:
Its important to understand that `unsafe` doesnt turn off the borrow checker
or disable any other of Rusts safety checks: if you use a reference in unsafe
code, it will still be checked. The `unsafe` keyword only gives us access to
code, it will still be checked. The `unsafe` keyword only gives you access to
these four features that are then not checked by the compiler for memory
safety. We still get some degree of safety inside of an unsafe block.
safety. Youll still get some degree of safety inside of an unsafe block.
In addition, `unsafe` does not mean the code inside the block is necessarily
dangerous or that it will definitely have memory safety problems: the intent is
that as the programmer, well ensure the code inside an `unsafe` block will
that as the programmer, youll ensure the code inside an `unsafe` block will
access memory in a valid way.
People are fallible, and mistakes will happen, but by requiring these four
unsafe operations to be inside blocks annotated with `unsafe` well know that
unsafe operations to be inside blocks annotated with `unsafe` youll know that
any errors related to memory safety must be within an `unsafe` block. Keep
`unsafe` blocks small; youll be thankful later when you investigate memory
bugs.
@ -60,7 +60,7 @@ from leaking out into all the places that you or your users might want to use
the functionality implemented with `unsafe` code, because using a safe
abstraction is safe.
Lets look at each of the four unsafe superpowers in turn: well also look at
Lets look at each of the four unsafe superpowers in turn. Well also look at
some abstractions that provide a safe interface to unsafe code.
### Dereferencing a Raw Pointer
@ -70,10 +70,10 @@ compiler ensures references are always valid. Unsafe Rust has two new types
called *raw pointers* that are similar to references. As with references, raw
pointers can be immutable or mutable and are written as `*const T` and `*mut
T`, respectively. The asterisk isnt the dereference operator; its part of the
type name. In the context of raw pointers, “immutable” means that the pointer
type name. In the context of raw pointers, *immutable* means that the pointer
cant be directly assigned to after being dereferenced.
Different from references and smart pointers, keep in mind that raw pointers:
Different from references and smart pointers, raw pointers:
* Are allowed to ignore the borrowing rules by having both immutable and
mutable pointers or multiple mutable pointers to the same location
@ -81,12 +81,12 @@ Different from references and smart pointers, keep in mind that raw pointers:
* Are allowed to be null
* Dont implement any automatic cleanup
By opting out of having Rust enforce these guarantees, we can make the
trade-off of giving up guaranteed safety to gain performance or the ability to
By opting out of having Rust enforce these guarantees, you can give up
guaranteed safety in exchange for greater performance or the ability to
interface with another language or hardware where Rusts guarantees dont apply.
Listing 19-1 shows how to create an immutable and a mutable raw pointer from
references:
references.
```rust
let mut num = 5;
@ -112,7 +112,7 @@ Listing 19-2 shows how to create a raw pointer to an arbitrary location in
memory. Trying to use arbitrary memory is undefined: there might be data at
that address or there might not, the compiler might optimize the code so there
is no memory access, or the program might error with a segmentation fault.
Usually, there is no good reason to write code like this, but it is possible:
Usually, there is no good reason to write code like this, but it is possible.
```rust
let address = 0x012345usize;
@ -124,7 +124,7 @@ memory address</span>
Recall that we can create raw pointers in safe code, but we cant *dereference*
raw pointers and read the data being pointed to. In Listing 19-3, we use the
dereference operator `*` on a raw pointer that requires an `unsafe` block:
dereference operator `*` on a raw pointer that requires an `unsafe` block.
```rust
let mut num = 5;
@ -144,16 +144,16 @@ unsafe {
Creating a pointer does no harm; its only when we try to access the value that
it points at that we might end up dealing with an invalid value.
Note also that in Listing 19-1 and 19-3 we created `*const i32` and `*mut i32`
Note also that in Listing 19-1 and 19-3, we created `*const i32` and `*mut i32`
raw pointers that both pointed to the same memory location, where `num` is
stored. If we instead tried to create an immutable and a mutable reference to
`num`, the code would not have compiled because Rusts ownership rules dont
allow a mutable reference at the same time as any immutable references. With
raw pointers, we can create a mutable pointer and an immutable pointer to the
same location, and change data through the mutable pointer, potentially
creating a data race. Be careful!
same location and change data through the mutable pointer, potentially creating
a data race. Be careful!
With all of these dangers, why would we ever use raw pointers? One major use
With all of these dangers, why would you ever use raw pointers? One major use
case is when interfacing with C code, as youll see in the next section,
“Calling an Unsafe Function or Method.” Another case is when building up safe
abstractions that the borrow checker doesnt understand. Well introduce unsafe
@ -210,7 +210,7 @@ a common abstraction. As an example, lets study a function from the standard
library, `split_at_mut`, that requires some unsafe code and explore how we
might implement it. This safe method is defined on mutable slices: it takes one
slice and makes it two by splitting the slice at the index given as an
argument. Listing 19-4 shows how to use `split_at_mut`:
argument. Listing 19-4 shows how to use `split_at_mut`.
```rust
let mut v = vec![1, 2, 3, 4, 5, 6];
@ -245,17 +245,17 @@ fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
<span class="caption">Listing 19-5: An attempted implementation of
`split_at_mut` using only safe Rust</span>
This function first gets the total length of the slice, then it asserts that
the index given as a parameter is within the slice by checking that its less
than or equal to the length. The assertion means that if we pass an index that
is greater than the index to split the slice at, the function will panic before
it attempts to use that index.
This function first gets the total length of the slice. Then it asserts that
the index given as a parameter is within the slice by checking whether its
less than or equal to the length. The assertion means that if we pass an index
that is greater than the index to split the slice at, the function will panic
before it attempts to use that index.
Then we return two mutable slices in a tuple: one from the start of the
original slice to the `mid` index and another from `mid` to the end of the
slice.
When we try to compile the code in Listing 19-5, well get an error:
When we try to compile the code in Listing 19-5, well get an error.
```text
error[E0499]: cannot borrow `*slice` as mutable more than once at a time
@ -276,7 +276,7 @@ slices arent overlapping, but Rust isnt smart enough to know this. When we
know code is okay, but Rust doesnt, its time to reach for unsafe code.
Listing 19-6 shows how to use an `unsafe` block, a raw pointer, and some calls
to unsafe functions to make the implementation of `split_at_mut` work:
to unsafe functions to make the implementation of `split_at_mut` work.
```rust
use std::slice;
@ -297,20 +297,20 @@ fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
<span class="caption">Listing 19-6: Using unsafe code in the implementation of
the `split_at_mut` function</span>
Recall from the “Slices” section in Chapter 4 that slices are a pointer to some
data and the length of the slice. We use the `len` method to get the length of
a slice and the `as_mut_ptr` method to access the raw pointer of a slice. In
this case, because we have a mutable slice to `i32` values, `as_mut_ptr`
returns a raw pointer with the type `*mut i32`, which weve stored in the
variable `ptr`.
Recall from “The Slice Type” section in Chapter 4 that slices are a pointer to
some data and the length of the slice. We use the `len` method to get the
length of a slice and the `as_mut_ptr` method to access the raw pointer of a
slice. In this case, because we have a mutable slice to `i32` values,
`as_mut_ptr` returns a raw pointer with the type `*mut i32`, which weve stored
in the variable `ptr`.
We keep the assertion that the `mid` index is within the slice. Then we get to
the unsafe code: the `slice::from_raw_parts_mut` function takes a raw pointer
and a length, and creates a slice. We use this function to create a slice that
starts from `ptr` and is `mid` items long. Then we call the `offset` method on
`ptr` with `mid` as an argument to get a raw pointer that starts at `mid`, and
we create a slice using that pointer and the remaining number of items after
`mid` as the length.
and a length, and it creates a slice. We use this function to create a slice
that starts from `ptr` and is `mid` items long. Then we call the `offset`
method on `ptr` with `mid` as an argument to get a raw pointer that starts at
`mid`, and we create a slice using that pointer and the remaining number of
items after `mid` as the length.
The function `slice::from_raw_parts_mut` is unsafe because it takes a raw
pointer and must trust that this pointer is valid. The `offset` method on raw
@ -330,7 +330,7 @@ data this function has access to.
In contrast, the use of `slice::from_raw_parts_mut` in Listing 19-7 would
likely crash when the slice is used. This code takes an arbitrary memory
location and creates a slice ten thousand items long:
location and creates a slice 10,000 items long.
```rust
use std::slice;
@ -360,7 +360,7 @@ programming language to call those functions.
Listing 19-8 demonstrates how to set up an integration with the `abs` function
from the C standard library. Functions declared within `extern` blocks are
always unsafe to call from Rust code. The reason is that other languages don`t
always unsafe to call from Rust code. The reason is that other languages dont
enforce Rusts rules and guarantees, and Rust cant check them, so
responsibility falls on the programmer to ensure safety.
@ -387,30 +387,30 @@ functions from another language we want to call. The `"C"` part defines which
defines how to call the function at the assembly level. The `"C"` ABI is the
most common and follows the C programming languages ABI.
#### Calling Rust Functions from Other Languages
We can also use `extern` to create an interface that allows other languages to
call Rust functions. Instead of an `extern` block, we add the `extern` keyword
and specify the ABI to use just before the `fn` keyword. We also need to add a
`#[no_mangle]` annotation to tell the Rust compiler not to mangle the name of
this function. *Mangling* is when a compiler changes the name weve given a
function to a different name that contains more information for other parts of
the compilation process to consume but is less human readable. Every
programming language compiler mangles names slightly differently, so for a Rust
function to be nameable by other languages, we must disable the Rust compilers
name mangling.
In the following example, we make the `call_from_c` function accessible from C
code, after its compiled to a shared library and linked from C:
```rust
#[no_mangle]
pub extern "C" fn call_from_c() {
println!("Just called a Rust function from C!");
}
```
This usage of `extern` does not require `unsafe`.
> #### Calling Rust Functions from Other Languages
>
> We can also use `extern` to create an interface that allows other languages
> to call Rust functions. Instead of an `extern` block, we add the `extern`
> keyword and specify the ABI to use just before the `fn` keyword. We also need
> to add a `#[no_mangle]` annotation to tell the Rust compiler not to mangle
> the name of this function. *Mangling* is when a compiler changes the name
> weve given a function to a different name that contains more information for
> other parts of the compilation process to consume but is less human readable.
> Every programming language compiler mangles names slightly differently, so
> for a Rust function to be nameable by other languages, we must disable the
> Rust compilers name mangling.
>
> In the following example, we make the `call_from_c` function accessible from
> C code, after its compiled to a shared library and linked from C:
>
> ```rust
> #[no_mangle]
> pub extern "C" fn call_from_c() {
> println!("Just called a Rust function from C!");
> }
> ```
>
> This usage of `extern` does not require `unsafe`.
### Accessing or Modifying a Mutable Static Variable
@ -420,7 +420,7 @@ accessing the same mutable global variable, it can cause a data race.
In Rust, global variables are called *static* variables. Listing 19-9 shows an
example declaration and use of a static variable with a string slice as a
value:
value.
<span class="filename">Filename: src/main.rs</span>
@ -451,7 +451,7 @@ are allowed to duplicate their data whenever theyre used.
Another difference between constants and static variables is that static
variables can be mutable. Accessing and modifying mutable static variables is
*unsafe*. Listing 19-10 shows how to declare, access, and modify a mutable
static variable named `COUNTER`:
static variable named `COUNTER`.
<span class="filename">Filename: src/main.rs</span>
@ -485,16 +485,16 @@ races.
With mutable data that is globally accessible, its difficult to ensure there
are no data races, which is why Rust considers mutable static variables to be
unsafe. Where possible, its preferable to use the concurrency techniques and
thread-safe smart pointers we discussed in Chapter 16, so the compiler checks
thread-safe smart pointers we discussed in Chapter 16 so the compiler checks
that data accessed from different threads is done safely.
### Implementing an Unsafe Trait
The final action that only works with `unsafe` is implementing an unsafe trait.
The final action that works only with `unsafe` is implementing an unsafe trait.
A trait is unsafe when at least one of its methods has some invariant that the
compiler cant verify. We can declare that a trait is `unsafe` by adding the
`unsafe` keyword before `trait`; then implementation of the trait must be
marked as `unsafe` too, as shown in Listing 19-11:
`unsafe` keyword before `trait` and marking the implementation of the trait as
`unsafe` too, as shown in Listing 19-11.
```rust
unsafe trait Foo {

View File

@ -6,12 +6,12 @@ lifetimes of different references relate. You saw how every reference has a
lifetime, but most of the time, Rust will let you elide lifetimes. Now well
look at three advanced features of lifetimes that we havent covered yet:
* Lifetime subtyping: Ensures that one lifetime outlives another lifetime
* Lifetime bounds: Specifies a lifetime for a reference to a generic type
* Inference of trait object lifetimes: How the compiler infers trait object
lifetimes and when they need to be specified
* Lifetime subtyping: ensures that one lifetime outlives another lifetime
* Lifetime bounds: specifies a lifetime for a reference to a generic type
* Inference of trait object lifetimes: allows the compiler to infer trait
object lifetimes and when they need to be specified
### Lifetime Subtyping Ensures One Lifetime Outlives Another
### Ensuring One Lifetime Outlives Another with Lifetime Subtyping
*Lifetime subtyping* specifies that one lifetime should outlive another
lifetime. To explore lifetime subtyping, imagine we want to write a parser.
@ -19,7 +19,7 @@ Well use a structure called `Context` that holds a reference to the string
were parsing. Well write a parser that will parse this string and return
success or failure. The parser will need to borrow the `Context` to do the
parsing. Listing 19-12 implements this parser code, except the code doesnt
have the required lifetime annotations, so it wont compile:
have the required lifetime annotations, so it wont compile.
<span class="filename">Filename: src/lib.rs</span>
@ -37,13 +37,14 @@ impl Parser {
}
```
Listing 19-12: Defining a parser without lifetime annotations
<span class="caption">Listing 19-12: Defining a parser without lifetime
annotations</span>
Compiling the code results in errors because Rust expects lifetime parameters
on the string slice in `Context` and the reference to a `Context` in `Parser`.
For simplicitys sake, the `parse` function returns `Result<(), &str>`. That
is, the function will do nothing on success, and on failure will return the
is, the function will do nothing on success and, on failure, will return the
part of the string slice that didnt parse correctly. A real implementation
would provide more error information and would return a structured data type
when parsing succeeds. We wont be discussing those details because they arent
@ -60,8 +61,12 @@ lifetimes involved.
To get this code to compile, we need to fill in the lifetime parameters for the
string slice in `Context` and the reference to the `Context` in `Parser`. The
most straightforward way to do this is to use the same lifetime everywhere, as
shown in Listing 19-13:
most straightforward way to do this is to use the same lifetime name
everywhere, as shown in Listing 19-13. Recall from the “Lifetime Annotations in
Struct Definitions” section in Chapter 10 that each of `struct Context<'a>`,
`struct Parser<'a>`, and `impl<'a>` is declaring a new lifetime parameter.
While their names happen to all be the same, the three lifetime parameters
declared in this example arent related.
<span class="filename">Filename: src/lib.rs</span>
@ -80,17 +85,17 @@ impl<'a> Parser<'a> {
```
<span class="caption">Listing 19-13: Annotating all references in `Context` and
`Parser` with the same lifetime parameter</span>
`Parser` with lifetime parameters</span>
This code compiles just fine. It tells Rust that a `Parser` holds a reference
to a `Context` with lifetime `'a`, and that `Context` holds a string slice that
to a `Context` with lifetime `'a` and that `Context` holds a string slice that
also lives as long as the reference to the `Context` in `Parser`. Rusts
compiler error message stated that lifetime parameters were required for these
references, and weve now added lifetime parameters.
Next, in Listing 19-14, well add a function that takes an instance of
`Context`, uses a `Parser` to parse that context, and returns what `parse`
returns. This code doesnt quite work:
returns. This code doesnt quite work.
<span class="filename">Filename: src/lib.rs</span>
@ -186,18 +191,18 @@ string slice that `Context` holds is the same as that of the lifetime of the
reference to `Context` that `Parser` holds.
The `parse_context` function cant see that within the `parse` function, the
string slice returned will outlive `Context` and `Parser`, and that the
string slice returned will outlive `Context` and `Parser` and that the
reference `parse_context` returns refers to the string slice, not to `Context`
or `Parser`.
By knowing what the implementation of `parse` does, we know that the only
reason the return value of `parse` is tied to the `Parser` is because its
referencing the `Parser`s `Context`, which is referencing the string slice.
So, its really the lifetime of the string slice that `parse_context` needs to
care about. We need a way to tell Rust that the string slice in `Context` and
the reference to the `Context` in `Parser` have different lifetimes and that
the return value of `parse_context` is tied to the lifetime of the string slice
in `Context`.
reason the return value of `parse` is tied to the `Parser` instance is that
its referencing the `Parser` instances `Context`, which is referencing the
string slice. So, its really the lifetime of the string slice that
`parse_context` needs to care about. We need a way to tell Rust that the string
slice in `Context` and the reference to the `Context` in `Parser` have
different lifetimes and that the return value of `parse_context` is tied to the
lifetime of the string slice in `Context`.
First, well try giving `Parser` and `Context` different lifetime parameters,
as shown in Listing 19-15. Well use `'s` and `'c` as lifetime parameter names
@ -266,8 +271,8 @@ referenced data in `Context` with lifetime `'s` needs to be constrained to
guarantee that it lives longer than the reference with lifetime `'c`. If `'s`
is not longer than `'c`, the reference to `Context` might not be valid.
Now we get to the point of this section: the Rust feature *lifetime*
*subtyping* specifies that one lifetime parameter lives at least as long as
Now we get to the point of this section: the Rust feature *lifetime
subtyping* specifies that one lifetime parameter lives at least as long as
another one. In the angle brackets where we declare lifetime parameters, we can
declare a lifetime `'a` as usual and declare a lifetime `'b` that lives at
least as long as `'a` by declaring `'b` using the syntax `'b: 'a`.
@ -293,7 +298,7 @@ lifetime of the string slice is longer than the reference to the `Context`.
That was a very long-winded example, but as we mentioned at the start of this
chapter, Rusts advanced features are very specific. You wont often need the
syntax we described in this example, but in such situations, youll know how to
refer to something you have a reference to.
refer to something and give it the necessary lifetime.
### Lifetime Bounds on References to Generic Types
@ -307,7 +312,7 @@ As an example, consider a type that is a wrapper over references. Recall the
section in Chapter 15: its `borrow` and `borrow_mut` methods return the types
`Ref` and `RefMut`, respectively. These types are wrappers over references that
keep track of the borrowing rules at runtime. The definition of the `Ref`
struct is shown in Listing 19-16, without lifetime bounds for now:
struct is shown in Listing 19-16, without lifetime bounds for now.
<span class="filename">Filename: src/lib.rs</span>
@ -316,7 +321,7 @@ struct Ref<'a, T>(&'a T);
```
<span class="caption">Listing 19-16: Defining a struct to wrap a reference to a
generic type, without lifetime bounds to start</span>
generic type, without lifetime bounds</span>
Without explicitly constraining the lifetime `'a` in relation to the generic
parameter `T`, Rust will error because it doesnt know how long the generic
@ -350,7 +355,7 @@ consider adding an explicit lifetime bound `T: 'a` so that the reference type
```
Listing 19-17 shows how to apply this advice by specifying the lifetime bound
when we declare the generic type `T`:
when we declare the generic type `T`.
```rust
struct Ref<'a, T: 'a>(&'a T);
@ -366,7 +371,7 @@ long as `'a`.
We could solve this problem in a different way, as shown in the definition of a
`StaticRef` struct in Listing 19-18, by adding the `'static` lifetime bound on
`T`. This means if `T` contains any references, they must have the `'static`
lifetime:
lifetime.
```rust
struct StaticRef<T: 'static>(&'static T);
@ -393,7 +398,7 @@ happens if the type implementing the trait in the trait object has a lifetime
of its own. Consider Listing 19-19 where we have a trait `Red` and a struct
`Ball`. The `Ball` struct holds a reference (and thus has a lifetime parameter)
and also implements trait `Red`. We want to use an instance of `Ball` as the
trait object `Box<Red>`:
trait object `Box<dyn Red>`.
<span class="filename">Filename: src/main.rs</span>
@ -409,7 +414,7 @@ impl<'a> Red for Ball<'a> { }
fn main() {
let num = 5;
let obj = Box::new(Ball { diameter: &num }) as Box<Red>;
let obj = Box::new(Ball { diameter: &num }) as Box<dyn Red>;
}
```
@ -425,14 +430,14 @@ rules for working with lifetimes and trait objects:
is `'a`.
* With a single `T: 'a` clause, the default lifetime of the trait object is
`'a`.
* With multiple `T: 'a`-like clauses, there is no default lifetime; we must be
* With multiple clauses like `T: 'a`, there is no default lifetime; we must be
explicit.
When we must be explicit, we can add a lifetime bound on a trait object like
`Box<Red>` using the syntax `Box<Red + 'static>` or `Box<Red + 'a>`, depending
on whether the reference lives for the entire program or not. As with the other
bounds, the syntax adding a lifetime bound means that any implementor of the
`Red` trait that has references inside the type must have the same lifetime
specified in the trait object bounds as those references.
`Box<dyn Red>` using the syntax `Box<dyn Red + 'static>` or `Box<dyn Red +
'a>`, depending on whether the reference lives for the entire program or not.
As with the other bounds, the syntax adding a lifetime bound means that any
implementor of the `Red` trait that has references inside the type must have
the same lifetime specified in the trait object bounds as those references.
Next, lets look at some other advanced features that manage traits.

View File

@ -4,7 +4,7 @@ We first covered traits in the “Traits: Defining Shared Behavior” section of
Chapter 10, but as with lifetimes, we didnt discuss the more advanced details.
Now that you know more about Rust, we can get into the nitty-gritty.
### Associated Types Specify Placeholder Types in Trait Definitions
### Specifying Placeholder Types in Trait Definitions with Associated Types
*Associated types* connect a type placeholder with a trait such that the trait
method definitions can use these placeholder types in their signatures. The
@ -15,7 +15,7 @@ trait is implemented.
Weve described most of the advanced features in this chapter as being rarely
needed. Associated types are somewhere in the middle: theyre used more rarely
than features explained in the rest of the book, but more commonly than many of
than features explained in the rest of the book but more commonly than many of
the other features discussed in this chapter.
One example of a trait with an associated type is the `Iterator` trait that the
@ -23,11 +23,12 @@ standard library provides. The associated type is named `Item` and stands in
for the type of the values the type implementing the `Iterator` trait is
iterating over. In “The `Iterator` Trait and the `next` Method” section of
Chapter 13, we mentioned that the definition of the `Iterator` trait is as
shown in Listing 19-20:
shown in Listing 19-20.
```rust
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
```
@ -40,11 +41,9 @@ that it will return values of type `Option<Self::Item>`. Implementors of the
`Iterator` trait will specify the concrete type for `Item`, and the `next`
method will return an `Option` containing a value of that concrete type.
#### Associated Types vs. Generics
Associated types might seem like a similar concept to generics, in that they
allow us to define a function without specifying what types it can handle. So
why use associated types?
Associated types might seem like a similar concept to generics, in that the
latter allow us to define a function without specifying what types it can
handle. So why use associated types?
Lets examine the difference between the two concepts with an example from
Chapter 13 that implements the `Iterator` trait on the `Counter` struct. In
@ -60,8 +59,8 @@ impl Iterator for Counter {
// --snip--
```
This syntax seems comparable to generics. So why not just define the `Iterator`
trait with generics, as shown in Listing 19-21?
This syntax seems comparable to that of generics. So why not just define the
`Iterator` trait with generics, as shown in Listing 19-21?
```rust
pub trait Iterator<T> {
@ -73,13 +72,13 @@ pub trait Iterator<T> {
`Iterator` trait using generics</span>
The difference is that when using generics, as in Listing 19-21, we must
annotate the types in each implementation. The reason is that we can also
implement `Iterator<String> for Counter` or any other type, which would give us
multiple implementations of `Iterator` for `Counter`. In other words, when a
trait has a generic parameter, it can be implemented for a type multiple times,
changing the concrete types of the generic type parameters each time. When we
use the `next` method on `Counter`, we would have to provide type annotations
to indicate which implementation of `Iterator` we want to use.
annotate the types in each implementation; because we can also implement
`Iterator<String> for Counter` or any other type, we could have multiple
implementations of `Iterator` for `Counter`. In other words, when a trait has a
generic parameter, it can be implemented for a type multiple times, changing
the concrete types of the generic type parameters each time. When we use the
`next` method on `Counter`, we would have to provide type annotations to
indicate which implementation of `Iterator` we want to use.
With associated types, we dont need to annotate types because we cant
implement a trait on a type multiple times. In Listing 19-20 with the
@ -112,7 +111,7 @@ struct:
```rust
use std::ops::Add;
#[derive(Debug,PartialEq)]
#[derive(Debug, PartialEq)]
struct Point {
x: i32,
y: i32,
@ -155,22 +154,22 @@ trait Add<RHS=Self> {
```
This code should look generally familiar: a trait with one method and an
associated type. The new part is `RHS=Self` in the angle brackets: this syntax
is called *default type parameters*. The `RHS` generic type parameter (short
for “right hand side”) defines the type of the `rhs` parameter in the `add`
method. If we dont specify a concrete type for `RHS` when we implement the
`Add` trait, the type of `RHS` will default to `Self`, which will be the type
were implementing `Add` on.
associated type. The new part is `RHS=Self`: this syntax is called *default
type parameters*. The `RHS` generic type parameter (short for “right hand
side”) defines the type of the `rhs` parameter in the `add` method. If we dont
specify a concrete type for `RHS` when we implement the `Add` trait, the type
of `RHS` will default to `Self`, which will be the type were implementing
`Add` on.
When we implemented `Add` for `Point`, we used the default for `RHS` because we
wanted to add two `Point` instances. Lets look at an example of implementing
the `Add` trait where we want to customize the `RHS` type rather than using the
default.
We have two structs holding values in different units, `Millimeters` and
`Meters`. We want to add values in millimeters to values in meters and have the
We have two structs, `Millimeters` and `Meters`, holding values in different
units. We want to add values in millimeters to values in meters and have the
implementation of `Add` do the conversion correctly. We can implement `Add` for
`Millimeters` with `Meters` as the `RHS`, as shown in Listing 19-23:
`Millimeters` with `Meters` as the `RHS`, as shown in Listing 19-23.
<span class="filename">Filename: src/lib.rs</span>
@ -195,35 +194,35 @@ impl Add<Meters> for Millimeters {
To add `Millimeters` and `Meters`, we specify `impl Add<Meters>` to set the
value of the `RHS` type parameter instead of using the default of `Self`.
We use default type parameters in two main ways:
Youll use default type parameters in two main ways:
* To extend a type without breaking existing code
* To allow customization in specific cases most users wont need
The standard librarys `Add` trait is an example of the second purpose:
usually, youll add two like types, but the `Add` trait provides the ability
for customizing beyond that. Using a default type parameter in the `Add` trait
usually, youll add two like types, but the `Add` trait provides the ability to
customize beyond that. Using a default type parameter in the `Add` trait
definition means you dont have to specify the extra parameter most of the
time. In other words, a bit of implementation boilerplate isnt needed, making
it easier to use the trait.
The first purpose is similar to the second but in reverse: if we want to add a
type parameter to an existing trait, we can give it a default to let us extend
the functionality of the trait without breaking the existing implementation
code.
The first purpose is similar to the second but in reverse: if you want to add a
type parameter to an existing trait, you can give it a default to allow
extension of the functionality of the trait without breaking the existing
implementation code.
### Fully Qualified Syntax for Disambiguation: Calling Methods with the Same Name
Nothing in Rust prevents a trait from having a method with the same name as
another traits method, nor does Rust prevent us from implementing both traits
another traits method, nor does Rust prevent you from implementing both traits
on one type. Its also possible to implement a method directly on the type with
the same name as methods from traits.
When calling methods with the same name, we need to tell Rust which one we want
to use. Consider the code in Listing 19-24 where weve defined two traits,
When calling methods with the same name, youll need to tell Rust which one you
want to use. Consider the code in Listing 19-24 where weve defined two traits,
`Pilot` and `Wizard`, that both have a method called `fly`. We then implement
both traits on a type `Human` that already has a method named `fly` implemented
on it. Each `fly` method does something different:
on it. Each `fly` method does something different.
<span class="filename">Filename: src/main.rs</span>
@ -257,12 +256,12 @@ impl Human {
}
```
<span class="caption">Listing 19-24: Two traits defined to have a `fly` method
and implementations of those traits on the `Human` type in addition to a `fly`
method on `Human` directly</span>
<span class="caption">Listing 19-24: Two traits are defined to have a `fly`
method and are implemented on the `Human` type, and a `fly` method is
implemented on `Human` directly</span>
When we call `fly` on an instance of `Human`, the compiler defaults to calling
the method that is directly implemented on the type, as shown in Listing 19-25:
the method that is directly implemented on the type, as shown in Listing 19-25.
<span class="filename">Filename: src/main.rs</span>
@ -304,12 +303,12 @@ fn main() {
<span class="caption">Listing 19-25: Calling `fly` on an instance of
`Human`</span>
Running this code will print `*waving arms furiously*`, which shows that Rust
Running this code will print `*waving arms furiously*`, showing that Rust
called the `fly` method implemented on `Human` directly.
To call the `fly` methods from either the `Pilot` trait or the `Wizard` trait,
we need to use more explicit syntax to specify which `fly` method we mean.
Listing 19-26 demonstrates this syntax:
Listing 19-26 demonstrates this syntax.
<span class="filename">Filename: src/main.rs</span>
@ -355,8 +354,9 @@ want to call</span>
Specifying the trait name before the method name clarifies to Rust which
implementation of `fly` we want to call. We could also write
`Human::fly(&person)`, which is equivalent to `person.fly()` that we used in
Listing 19-26 but is a bit longer to write if we dont need to disambiguate.
`Human::fly(&person)`, which is equivalent to the `person.fly()` that we used
in Listing 19-26, but this is a bit longer to write if we dont need to
disambiguate.
Running this code prints the following:
@ -367,15 +367,15 @@ Up!
```
Because the `fly` method takes a `self` parameter, if we had two *types* that
both implement one *trait*, Rust can figure out which implementation of a trait
to use based on the type of `self`.
both implement one *trait*, Rust could figure out which implementation of a
trait to use based on the type of `self`.
However, associated functions that are part of traits dont have a `self`
parameter. When two types in the same scope implement that trait, Rust cant
figure out which type we mean unless we use *fully qualified syntax*. For
figure out which type you mean unless you use *fully qualified syntax*. For
example, the `Animal` trait in Listing 19-27 has the associated function
`baby_name`, the implementation of `Animal` for the struct `Dog`, and the
associated function `baby_name` defined on `Dog` directly:
associated function `baby_name` defined on `Dog` directly.
<span class="filename">Filename: src/main.rs</span>
@ -404,8 +404,8 @@ fn main() {
```
<span class="caption">Listing 19-27: A trait with an associated function and a
type that has an associated function with the same name that also implements
the trait</span>
type with an associated function of the same name that also implements the
trait</span>
This code is for an animal shelter that wants to name all puppies Spot, which
is implemented in the `baby_name` associated function that is defined on `Dog`.
@ -425,7 +425,7 @@ This output isnt what we wanted. We want to call the `baby_name` function tha
is part of the `Animal` trait that we implemented on `Dog` so the code prints
`A baby dog is called a puppy`. The technique of specifying the trait name that
we used in Listing 19-26 doesnt help here; if we change `main` to the code in
Listing 19-28, well get a compilation error:
Listing 19-28, well get a compilation error.
<span class="filename">Filename: src/main.rs</span>
@ -454,9 +454,8 @@ error[E0283]: type annotations required: cannot resolve `_: Animal`
```
To disambiguate and tell Rust that we want to use the implementation of
`Animal` for `Dog`, we need to use *fully qualified syntax*, which is the most
specific we can be when calling a function. Listing 19-29 demonstrates how to
use fully qualified syntax:
`Animal` for `Dog`, we need to use fully qualified syntax. Listing 19-29
demonstrates how to use fully qualified syntax.
<span class="filename">Filename: src/main.rs</span>
@ -504,18 +503,18 @@ In general, fully qualified syntax is defined as follows:
```
For associated functions, there would not be a `receiver`: there would only be
the list of other arguments. We could use fully qualified syntax everywhere
that we call functions or methods. However, were allowed to omit any part of
this syntax that Rust can figure out from other information in the program. We
the list of other arguments. You could use fully qualified syntax everywhere
that you call functions or methods. However, youre allowed to omit any part of
this syntax that Rust can figure out from other information in the program. You
only need to use this more verbose syntax in cases where there are multiple
implementations that use the same name and Rust needs help to identify which
implementation we want to call.
implementation you want to call.
### Using Supertraits to Require One Traits Functionality Within Another Trait
Sometimes, we might need one trait to use another traits functionality. In
this case, we need to rely on the dependent trait also being implemented. The
trait were relying on is a *supertrait* of the trait were implementing.
Sometimes, you might need one trait to use another traits functionality. In
this case, you need to rely on the dependent traits also being implemented.
The trait you rely on is a *supertrait* of the trait youre implementing.
For example, lets say we want to make an `OutlinePrint` trait with an
`outline_print` method that will print a value framed in asterisks. That is,
@ -533,10 +532,10 @@ call `outline_print` on a `Point` instance that has `1` for `x` and `3` for
In the implementation of `outline_print`, we want to use the `Display` traits
functionality. Therefore, we need to specify that the `OutlinePrint` trait will
only work for types that also implement `Display` and provide the functionality
work only for types that also implement `Display` and provide the functionality
that `OutlinePrint` needs. We can do that in the trait definition by specifying
`OutlinePrint: Display`. This technique is similar to adding a trait bound to
the trait. Listing 19-30 shows an implementation of the `OutlinePrint` trait:
the trait. Listing 19-30 shows an implementation of the `OutlinePrint` trait.
<span class="filename">Filename: src/main.rs</span>
@ -561,9 +560,10 @@ requires the functionality from `Display`</span>
Because weve specified that `OutlinePrint` requires the `Display` trait, we
can use the `to_string` function that is automatically implemented for any type
that implements `Display`. If we tried to use `to_string` without adding`:
Display` after the trait name, wed get an error saying that no method named
`to_string` was found for the type `&Self` in the current scope.
that implements `Display`. If we tried to use `to_string` without adding a
colon and specifying the `Display` trait after the trait name, wed get an
error saying that no method named `to_string` was found for the type `&Self` in
the current scope.
Lets see what happens when we try to implement `OutlinePrint` on a type that
doesnt implement `Display`, such as the `Point` struct:
@ -588,7 +588,7 @@ error[E0277]: the trait bound `Point: std::fmt::Display` is not satisfied
|
20 | impl OutlinePrint for Point {}
| ^^^^^^^^^^^^ `Point` cannot be formatted with the default formatter;
try using `:?` instead if you are using a format string
try using `:?` instead if you are using a format string
|
= help: the trait `std::fmt::Display` is not implemented for `Point`
```
@ -617,25 +617,25 @@ Then implementing the `OutlinePrint` trait on `Point` will compile
successfully, and we can call `outline_print` on a `Point` instance to display
it within an outline of asterisks.
### The Newtype Pattern to Implement External Traits on External Types
### Using the Newtype Pattern to Implement External Traits on External Types
In Chapter 10 in the “Implementing a Trait on a Type” section, we mentioned the
orphan rule that states were allowed to implement a trait on a type as long as
either the trait or the type are local to our crate. Its possible to get
around this restriction using the *newtype pattern*, which involves creating a
new type in a tuple struct. (We covered tuple structs in the “Tuple Structs
without Named Fields to Create Different Types” section of Chapter 5.) The
tuple struct will have one field and be a thin wrapper around the type we want
to implement a trait for. Then the wrapper type is local to our crate, and we
can implement the trait on the wrapper. *Newtype* is a term that originates
new type in a tuple struct. (We covered tuple structs in the “Using Tuple
Structs without Named Fields to Create Different Types” section of Chapter 5.)
The tuple struct will have one field and be a thin wrapper around the type we
want to implement a trait for. Then the wrapper type is local to our crate, and
we can implement the trait on the wrapper. *Newtype* is a term that originates
from the Haskell programming language. There is no runtime performance penalty
for using this pattern, and the wrapper type is elided at compile time.
As an example, lets say we want to implement `Display` on `Vec`, which the
As an example, lets say we want to implement `Display` on `Vec<T>`, which the
orphan rule prevents us from doing directly because the `Display` trait and the
`Vec` type are defined outside our crate. We can make a `Wrapper` struct that
holds an instance of `Vec`; then we can implement `Display` on `Wrapper` and
use the `Vec` value, as shown in Listing 19-31:
`Vec<T>` type are defined outside our crate. We can make a `Wrapper` struct
that holds an instance of `Vec<T>`; then we can implement `Display` on
`Wrapper` and use the `Vec<T>` value, as shown in Listing 19-31.
<span class="filename">Filename: src/main.rs</span>
@ -659,21 +659,21 @@ fn main() {
<span class="caption">Listing 19-31: Creating a `Wrapper` type around
`Vec<String>` to implement `Display`</span>
The implementation of `Display` uses `self.0` to access the inner `Vec`,
because `Wrapper` is a tuple struct and `Vec` is the item at index 0 in the
The implementation of `Display` uses `self.0` to access the inner `Vec<T>`,
because `Wrapper` is a tuple struct and `Vec<T>` is the item at index 0 in the
tuple. Then we can use the functionality of the `Display` type on `Wrapper`.
The downside of using this technique is that `Wrapper` is a new type, so it
doesnt have the methods of the value its holding. We would have to implement
all the methods of `Vec` directly on `Wrapper` so it can delegate to `self.0`,
allowing us to treat `Wrapper` exactly like a `Vec`. If we wanted the new type
to have every method the inner type has, implementing the `Deref` trait
(discussed in Chapter 15 in the “Treating Smart Pointers like Regular
References with the `Deref` Trait” section) on the `Wrapper` to return the
inner type would be a solution. If we dont want the `Wrapper` type to have all
the methods of the inner type, in order to restrict the `Wrapper` types
behavior for example, we would have to implement just the methods we do want
manually.
all the methods of `Vec<T>` directly on `Wrapper` such that the methods
delegate to `self.0`, which would allow us to treat `Wrapper` exactly like a
`Vec<T>`. If we wanted the new type to have every method the inner type has,
implementing the `Deref` trait (discussed in Chapter 15 in the “Treating Smart
Pointers like Regular References with the `Deref` Trait” section) on the
`Wrapper` to return the inner type would be a solution. If we dont want the
`Wrapper` type to have all the methods of the inner type—for example, to
restrict the `Wrapper` types behavior—we would have to implement just the
methods we do want manually.
Now you know how the newtype pattern is used in relation to traits; its also a
useful pattern even when traits are not involved. Lets switch focus and look

View File

@ -6,19 +6,18 @@ examine why newtypes are useful as types. Then well move on to type aliases,
feature similar to newtypes but with slightly different semantics. Well also
discuss the `!` type and dynamically sized types.
> Note: The next section assumes youve read the earlier section “The Newtype
> Pattern to Implement External Traits on External Types.”
### Using the Newtype Pattern for Type Safety and Abstraction
> Note: This section assumes youve read the earlier section “The Newtype
> Pattern to Implement External Traits on External Types”.
The newtype pattern is useful for other tasks beyond what weve discussed so
far, including statically enforcing that values are never confused and as an
indication of the units of a value. You saw an example of using newtypes to
indicate units in Listing 19-23: recall that the `Millimeters` and `Meters`
structs wrapped `u32` values in a newtype. If we wrote a function with a
parameter of type `Millimeters`, we couldnt compile a program that
accidentally tried to call that function with a value of type `Meters` or a
plain `u32`.
The newtype pattern is useful for tasks beyond those weve discussed so far,
including statically enforcing that values are never confused and indicating
the units of a value. You saw an example of using newtypes to indicate units in
Listing 19-23: recall that the `Millimeters` and `Meters` structs wrapped `u32`
values in a newtype. If we wrote a function with a parameter of type
`Millimeters`, we couldnt compile a program that accidentally tried to call
that function with a value of type `Meters` or a plain `u32`.
Another use of the newtype pattern is in abstracting away some implementation
details of a type: the new type can expose a public API that is different from
@ -34,7 +33,7 @@ internally. The newtype pattern is a lightweight way to achieve encapsulation
to hide implementation details, which we discussed in the “Encapsulation that
Hides Implementation Details” section of Chapter 17.
### Type Aliases Create Type Synonyms
### Creating Type Synonyms with Type Aliases
Along with the newtype pattern, Rust provides the ability to declare a *type
alias* to give an existing type another name. For this we use the `type`
@ -67,21 +66,21 @@ The main use case for type synonyms is to reduce repetition. For example, we
might have a lengthy type like this:
```rust,ignore
Box<Fn() + Send + 'static>
Box<dyn Fn() + Send + 'static>
```
Writing this lengthy type in function signatures and as type annotations all
over the code can be tiresome and error prone. Imagine having a project full of
code like that in Listing 19-32:
code like that in Listing 19-32.
```rust
let f: Box<Fn() + Send + 'static> = Box::new(|| println!("hi"));
let f: Box<dyn Fn() + Send + 'static> = Box::new(|| println!("hi"));
fn takes_long_type(f: Box<Fn() + Send + 'static>) {
fn takes_long_type(f: Box<dyn Fn() + Send + 'static>) {
// --snip--
}
fn returns_long_type() -> Box<Fn() + Send + 'static> {
fn returns_long_type() -> Box<dyn Fn() + Send + 'static> {
// --snip--
# Box::new(|| ())
}
@ -91,10 +90,10 @@ fn returns_long_type() -> Box<Fn() + Send + 'static> {
A type alias makes this code more manageable by reducing the repetition. In
Listing 19-33, weve introduced an alias named `Thunk` for the verbose type and
can replace all uses of the type with the shorter alias `Thunk`:
can replace all uses of the type with the shorter alias `Thunk`.
```rust
type Thunk = Box<Fn() + Send + 'static>;
type Thunk = Box<dyn Fn() + Send + 'static>;
let f: Thunk = Box::new(|| println!("hi"));
@ -145,7 +144,7 @@ type Result<T> = Result<T, std::io::Error>;
```
Because this declaration is in the `std::io` module, we can use the fully
qualified alias `std::io::Result<T>`; that is, a `Result<T, E>` with the `E`
qualified alias `std::io::Result<T>`that is, a `Result<T, E>` with the `E`
filled in as `std::io::Error`. The `Write` trait function signatures end up
looking like this:
@ -162,9 +161,9 @@ pub trait Write {
The type alias helps in two ways: it makes code easier to write *and* it gives
us a consistent interface across all of `std::io`. Because its an alias, its
just another `Result<T, E>`, which means we can use any methods that work on
`Result<T, E>` with it, as well as special syntax like `?`.
`Result<T, E>` with it, as well as special syntax like the `?` operator.
### The `!` Never Type that Never Returns
### The Never Type that Never Returns
Rust has a special type named `!` thats known in type theory lingo as the
*empty type* because it has no values. We prefer to call it the *never type*
@ -181,9 +180,8 @@ This code is read as “the function `bar` returns never.” Functions that retu
never are called *diverging functions*. We cant create values of the type `!`
so `bar` can never possibly return.
But what use is a type you can never create values for? Recall the code in
Chapter 2 that we added in the “Handling Invalid Input” section; weve
reproduced it here in Listing 19-34:
But what use is a type you can never create values for? Recall the code from
Listing 2-5; weve reproduced part of it here in Listing 19-34.
```rust
# let guess = "3";
@ -211,7 +209,7 @@ let guess = match guess.trim().parse() {
```
The type of `guess` in this code would have to be an integer *and* a string,
and Rust requires that `guess` can only have one type. So what does `continue`
and Rust requires that `guess` have only one type. So what does `continue`
return? How were we allowed to return a `u32` from one arm and have another arm
that ends with `continue` in Listing 19-34?
@ -242,10 +240,10 @@ impl<T> Option<T> {
```
In this code, the same thing happens as in the `match` in Listing 19-34: Rust
sees that `val` has the type `T` and `panic!` has the type `!` so the result of
the overall `match` expression is `T`. This code works because `panic!` doesnt
produce a value; it ends the program. In the `None` case, we wont be returning
a value from `unwrap`, so this code is valid.
sees that `val` has the type `T` and `panic!` has the type `!`, so the result
of the overall `match` expression is `T`. This code works because `panic!`
doesnt produce a value; it ends the program. In the `None` case, we wont be
returning a value from `unwrap`, so this code is valid.
One final expression that has the type `!` is a `loop`:
@ -261,13 +259,13 @@ Here, the loop never ends, so `!` is the value of the expression. However, this
wouldnt be true if we included a `break`, because the loop would terminate
when it got to the `break`.
### Dynamically Sized Types and `Sized`
### Dynamically Sized Types and the `Sized` Trait
Due to Rusts need to know certain details, such as how much space to allocate
for a value of a particular type, there is a corner of its type system that can
be confusing: the concept of *dynamically sized types*. Sometimes referred to
as *DSTs* or *unsized types*, these types let us write code using values whose
size we can only know at runtime.
size we can know only at runtime.
Lets dig into the details of a dynamically sized type called `str`, which
weve been using throughout the book. Thats right, not `&str`, but `str` on
@ -289,26 +287,26 @@ holding a dynamically sized type.
So what do we do? In this case, you already know the answer: we make the types
of `s1` and `s2` a `&str` rather than a `str`. Recall that in the “String
Slices” section of Chapter 4 we said the slice data structure stores the
Slices” section of Chapter 4, we said the slice data structure stores the
starting position and the length of the slice.
So although a `&T` is a single value that stores the memory address of where
the `T` is located, a `&str` is *two* values: the address of the `str` and its
length. As such, we can know the size of a `&str` value at compile time: its
two times the size of a `usize` in length. That is, we always know the size of
a `&str`, no matter how long the string it refers to is. In general, this is
the way in which dynamically sized types are used in Rust: they have an extra
bit of metadata that stores the size of the dynamic information. The golden
rule of dynamically sized types is that we must always put values of
dynamically sized types behind a pointer of some kind.
twice the length of a `usize`. That is, we always know the size of a `&str`, no
matter how long the string it refers to is. In general, this is the way in
which dynamically sized types are used in Rust: they have an extra bit of
metadata that stores the size of the dynamic information. The golden rule of
dynamically sized types is that we must always put values of dynamically sized
types behind a pointer of some kind.
We can combine `str` with all kinds of pointers: for example, `Box<str>` or
`Rc<str>`. In fact, youve seen this before but with a different dynamically
sized type: traits. Every trait is a dynamically sized type we can refer to by
using the name of the trait. In Chapter 17 in the “Using Trait Objects that
Allow for Values of Different Types” section, we mentioned that to use traits
as trait objects, we must put them behind a pointer, such as `&Trait` or
`Box<Trait>` (`Rc<Trait>` would work too).
as trait objects, we must put them behind a pointer, such as `&dyn Trait` or
`Box<dyn Trait>` (`Rc<dyn Trait>` would work too).
To work with DSTs, Rust has a particular trait called the `Sized` trait to
determine whether or not a types size is known at compile time. This trait is
@ -330,7 +328,7 @@ fn generic<T: Sized>(t: T) {
}
```
By default, generic functions will only work on types that have a known size at
By default, generic functions will work only on types that have a known size at
compile time. However, you can use the following special syntax to relax this
restriction:

View File

@ -6,13 +6,13 @@ closures, which include function pointers and returning closures.
### Function Pointers
Weve talked about how to pass closures to functions; you can also pass regular
functions to functions! This technique is useful when we want to pass a
function weve already defined rather than defining a new closure. We do this
using function pointers to allow us to use functions as arguments to other
functions to functions! This technique is useful when you want to pass a
function youve already defined rather than defining a new closure. Doing this
with function pointers will allow you to use functions as arguments to other
functions. Functions coerce to the type `fn` (with a lowercase f), not to be
confused with the `Fn` closure trait. The `fn` type is called a function
pointer. The syntax for specifying that a parameter is a function pointer is
similar to that of closures, as shown in Listing 19-35:
confused with the `Fn` closure trait. The `fn` type is called a *function
pointer*. The syntax for specifying that a parameter is a function pointer is
similar to that of closures, as shown in Listing 19-35.
<span class="filename">Filename: src/main.rs</span>
@ -45,7 +45,7 @@ parameter type directly rather than declaring a generic type parameter with one
of the `Fn` traits as a trait bound.
Function pointers implement all three of the closure traits (`Fn`, `FnMut`, and
`FnOnce`), so we can always pass a function pointer as an argument for a
`FnOnce`), so you can always pass a function pointer as an argument for a
function that expects a closure. Its best to write functions using a generic
type and one of the closure traits so your functions can accept either
functions or closures.
@ -54,7 +54,7 @@ An example of where you would want to only accept `fn` and not closures is when
interfacing with external code that doesnt have closures: C functions can
accept functions as arguments, but C doesnt have closures.
As an example of where we can use either a closure defined inline or a named
As an example of where you could use either a closure defined inline or a named
function, lets look at a use of `map`. To use the `map` function to turn a
vector of numbers into a vector of strings, we could use a closure, like this:
@ -88,12 +88,12 @@ up compiling to the same code, so use whichever style is clearer to you.
### Returning Closures
Closures are represented by traits, which means we cant return closures
directly. In most cases where we might want to return a trait, we can instead
Closures are represented by traits, which means you cant return closures
directly. In most cases where you might want to return a trait, you can instead
use the concrete type that implements the trait as the return value of the
function. But we cant do that with closures because they dont have a concrete
type that is returnable; were not allowed to use the function pointer `fn` as
a return type, for example.
function. But you cant do that with closures because they dont have a
concrete type that is returnable; youre not allowed to use the function
pointer `fn` as a return type, for example.
The following code tries to return a closure directly, but it wont compile:
@ -124,13 +124,14 @@ it will need to store the closure. We saw a solution to this problem earlier.
We can use a trait object:
```rust
fn returns_closure() -> Box<Fn(i32) -> i32> {
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
Box::new(|x| x + 1)
}
```
This code will compile just fine. For more about trait objects, refer to the
“Trait Objects” section in Chapter 17.
“Using Trait Objects That Allow for Values of Different Types” section in
Chapter 17.
## Summary
@ -143,4 +144,3 @@ you to solutions.
Next, well put everything weve discussed throughout the book into practice
and do one more project!

View File

@ -1,34 +1,33 @@
# Final Project: Building a Multithreaded Web Server
Its been a long journey, but here we are! The end of the book. Parting is such
sweet sorrow. But before we go, lets build one more project together, to show
off some of the concepts we covered in these final chapters, as well as recap
some lessons from earlier.
Its been a long journey, but weve reached the end of the book. In this
chapter, well build one more project together to demonstrate some of the
concepts we covered in the final chapters, as well as recap some earlier
lessons.
For our final project were going to make a web server that only says “hello”;
which will look like Figure 20-1 in a web browser:
For our final project, well make a web server that says “hello” and looks like
Figure 20-1 in a web browser.
![hello from rust](img/trpl20-01.png)
<span class="caption">Figure 20-1: Our final shared project together</span>
<span class="caption">Figure 20-1: Our final shared project</span>
Heres the plan of how well build the web server:
Here is the plan to build the web server:
1. Learn a little bit about TCP and HTTP
2. Listen for TCP connections on a socket
3. Parse a small number of HTTP requests
4. Create a proper HTTP response
5. Improve the throughput of our server with a thread pool
1. Learn a bit about TCP and HTTP.
2. Listen for TCP connections on a socket.
3. Parse a small number of HTTP requests.
4. Create a proper HTTP response.
5. Improve the throughput of our server with a thread pool.
Before we get started, however, theres one thing we should mention: the method
we use here will not be the best way to build a web server with Rust. There are
a number of production-ready crates available on *https://crates.io* that
provide much more complete web server and thread pool implementations than we
are going to build.
But before we get started, we should mention one detail: the method well use
wont be the best way to build a web server with Rust. A number of
production-ready crates are available on *https://crates.io/* that provide more
complete web server and thread pool implementations than well build.
However, for this chapter, our intention is to help you learn, not to take the
easy route. Because Rust is a systems programming language, were able to
choose what level of abstraction we want to work with, and can go to a lower
level than is possible or practical in other languages. Well therefore write
the basic HTTP server and thread pool ourselves so you can learn the general
ideas and techniques behind the crates you might use in the future.
However, our intention in this chapter is to help you learn, not to take the
easy route. Because Rust is a systems programming language, we can choose the
level of abstraction we want to work with and can go to a lower level than is
possible or practical in other languages. Well write the basic HTTP server and
thread pool manually so you can learn the general ideas and techniques behind
the crates you might use in the future.

Some files were not shown because too many files have changed in this diff Show More