Series: The Rust Annals
Vol. I Issue 18 nlopes.dev
Announcing Rust 1.17
Rust 1.17 is chiefly a quality-of-life release: constants and statics need fewer lifetime annotations, struct construction gains field init shorthand, and Cargo can avoid building targets whose required features are disabled. It also completes Rust’s move to its Cargo-driven build system, expands raw-pointer, collection, cell, networking, and conversion APIs, and makes common string-concatenation errors and default backtraces easier to understand.
Constants, statics, and struct construction shed repetition
The 'static lifetime is now assumed in constants and statics, where it is the only lifetime that makes sense. Explicit annotations remain valid, but code can be shortened as follows:
// old
const NAMES: &'static [&'static str; 2] = &["Ferris", "Bors"];
// new
const NAMES: &[&str; 2] = &["Ferris", "Bors"];Field init shorthand removes another common duplication. When a field name and an in-scope variable have the same name, the field name alone supplies that variable as its value:
// definitions
struct Point {
x: i32,
y: i32,
}
let x = 5;
let y = 6;
// old
let p = Point {
x: x,
y: y,
};
// new
let p = Point {
x,
y,
};
Cargo recognizes conventional build scripts and feature-gated targets
Cargo now assumes a root-level build.rs is the package’s build script, so the usual build = "build.rs" declaration is unnecessary. Cargo had warned about this change for the preceding few releases; packages that contain the file but do not want it used as a build script can set build = false.
The new required-features manifest key specifies features that must be enabled before Cargo builds a target. Previously, a feature-specific binary could need alternate main functions merely to accommodate cargo build attempting every target:
#[cfg(not(all(feature = "postgres", feature = "tools")))]
fn main() {
println!("This tool requires the `postgres` and `tools` features to be enabled.");
}
#[cfg(all(feature = "postgres", feature = "tools"))]
fn main() {
// real code
}A target can now express the constraint in Cargo.toml instead:
[[bin]]
# ...
required-features = ["postgres", "tools"]With that declaration, cargo build builds the target only when both features are set, allowing the binary to use a normal fn main. This is also useful for examples whose feature gating is relevant inside the package rather than to readers reusing the example.
Cargo also adds support for cargo check --all and cargo run --package. Users may opt in to ignoring SSL revocation checks; checking remains the default.
Rust’s Cargo-driven build system becomes the only build system
The old Makefile-based Rust build system has been removed. Its Rust-written replacement, announced in Rust 1.15 and primarily driven by Cargo, is now mature enough to be the sole build system. This also permits crates.io packages inside Rust’s own build process: mdBook was the first addition and now renders The Book, The Reference, and The Nomicon.
Those three books have moved to their own repositories: The Book repository, The Reference repository, and The Nomicon repository. A fourth, still in-tree publication, The Unstable Book, gives an overview of unstable features by name, links to their tracking issues, and may contain initial documentation.
Documentation is installed by default again. Rustup had stopped doing so a few releases earlier to save bandwidth and because not everyone wanted a local copy, but some users discovered the absence only after losing internet access while others wanted local documentation regardless of connectivity.
On Windows, Rust 1.17 cannot automatically detect Visual Studio 2017 because Microsoft changed its installation structure. Work on the necessary detection changes did not reach this release.
The standard library adds pointer, range, cell, conversion, and process APIs
Nineteen APIs stabilize in this release:
Arc::into_rawandRc::into_rawconsume anArcorRcand return a raw pointer.Arc::from_rawandRc::from_rawturn that raw pointer back into anArcorRc.Arc::ptr_eqandRc::ptr_eqreport whether two values point to the same allocation, rather than merely comparing equal.Ordering::thenchains twoOrderingvalues;Ordering::then_withdoes so with a function.BTreeMap::rangeiterates over part of aBTreeMap, whileBTreeMap::range_mutdoes so mutably;collections::Boundprovides additional control.process::abortcompletely terminates a process abnormally.ptr::read_unalignedandptr::write_unalignedcorrespond toptr::readandptr::writewithout alignment requirements.Result::expect_errmirrorsResult::expectfor theErrcase instead of theOkcase.Cell::swapresemblesstd::mem::swapbut operates through&Cellrather than&mut T.Cell::replaceresemblesstd::mem::replacewith the same&Celldistinction.Cell::into_innerconsumes aCelland extracts its value.Cell::takeremoves a value from aCell, leavingDefault::defaultbehind.
Many Cell<T> methods have also substantially relaxed their former T: Copy requirement. Box<T> implements more than a dozen additional From conversions, and SocketAddr and IpAddr gain new conversions.
The address conversions can replace runtime string parsing:
// old
"127.0.0.1:3000".parse().unwrap()
// new
SocketAddr::from(([127, 0, 0, 1], 3000))
// or even
([127, 0, 0, 1], 3000).into()This removes unnecessary runtime parsing and is roughly as readable, depending on preference.
Diagnostics explain string ownership and backtraces become easier to scan
Adding two &str values remains invalid—concatenation supports String + &str—but the compiler now explains the ownership requirement and proposes converting the left operand:
// code
"foo" + "bar"
// old
error[E0369]: binary operation `+` cannot be applied to type `&'static str`
--> <anon>:2:5
|
2 | "foo" + "bar"
| ^^^^^
|
note: an implementation of `std::ops::Add` might be missing for `&'static str`
--> <anon>:2:5
|
2 | "foo" + "bar"
| ^^^^^
// new
error[E0369]: binary operation `+` cannot be applied to type `&'static str`
--> <anon>:2:5
|
2 | "foo" + "bar"
| ^^^^^
|
= note: `+` can't be used to concatenate two `&str` strings
help: to_owned() can be used to create an owned `String` from a string
reference. String concatenation appends the string on the right to the string on
the left and may require reallocation. This requires ownership of the string on
the left.
| "foo".to_owned() + "bar"Default backtraces now elide addresses and symbol hashes, producing a more compact trace. For example, the former full output:
thread 'main' panicked at 'explicit panic', foo.rs:2
stack backtrace:
1: 0x55c39a23372c - std::sys::imp::backtrace::tracing::imp::write::hf33ae72d0baa11ed
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:42
2: 0x55c39a23571e - std::panicking::default_hook::{{closure}}::h59672b733cc6a455
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/panicking.rs:351
3: 0x55c39a235324 - std::panicking::default_hook::h1670459d2f3f8843
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/panicking.rs:367
4: 0x55c39a235afb - std::panicking::rust_panic_with_hook::hcf0ddb069e7beee7
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/panicking.rs:555
5: 0x55c39a22e866 - std::panicking::begin_panic::heb433e9aa28a7408
6: 0x55c39a22e9bf - foo::main::hd216d4a160fcce19
7: 0x55c39a23d44a - __rust_maybe_catch_panic
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libpanic_unwind/lib.rs:98
8: 0x55c39a236006 - std::rt::lang_start::hd7c880a37a646e81
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/panicking.rs:436
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/panic.rs:361
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/rt.rs:57
9: 0x55c39a22e9e9 - main
10: 0x7f5e5ed3382f - __libc_start_main
11: 0x55c39a22e6b8 - _start
12: 0x0 - <unknown>is displayed by default as:
thread 'main' panicked at 'explicit panic', foo.rs:2
stack backtrace:
0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace
at /checkout/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
1: std::sys_common::backtrace::_print
at /checkout/src/libstd/sys_common/backtrace.rs:71
2: std::panicking::default_hook::{{closure}}
at /checkout/src/libstd/sys_common/backtrace.rs:60
at /checkout/src/libstd/panicking.rs:355
3: std::panicking::default_hook
at /checkout/src/libstd/panicking.rs:371
4: std::panicking::rust_panic_with_hook
at /checkout/src/libstd/panicking.rs:549
5: std::panicking::begin_panic
6: foo::main
7: __rust_maybe_catch_panic
at /checkout/src/libpanic_unwind/lib.rs:98
8: std::rt::lang_start
at /checkout/src/libstd/panicking.rs:433
at /checkout/src/libstd/panic.rs:361
at /checkout/src/libstd/rt.rs:57
9: main
10: __libc_start_main
11: _startSet RUST_BACKTRACE=full to request the full backtrace. Further cleanup may be possible in the future.