Rust 2018のリリース前情報

Rustに導入される予定の新しいエディション、Rust 2018について、リリース前に得られる情報をご紹介します。


Rust 2018とは何か

Rust公式ブログの What is Rust 2018?より、大雑把に要約してみます。

Rust 2018とは、簡単に言えばC++におけるC++11みたいなものです。これまでのRustはRust 2015と呼ばれることになり、Rust 2018ではRust 2015からの破壊的変更が含まれます。12/6にリリース予定のRust 1.31が、Rust 2018の最初のリリースとなる予定です。Cargo.toml内でエディションを指定することにより、Rust 2018の機能が利用できるようになります。


Rust 2015との互換性

Rust 2018のリリース後も、RustコンパイラはRust 2015で書かれたコードをコンパイルできます。また、Rust 2018からRust 2015で書かれたライブラリを使うことも、その逆も可能です。コンパイラは異なるエディションのコードをリンクすることができます。また、Rust 2015から2018へと自動変換するためのツールcargo fixが提供される予定です。


Rust 2018リリース後の開発について

Rust 2018のリリースというのは、あくまで最初のリリースであるに過ぎません。Rust 2018がリリースされた後でも、Rust 2018への機能の追加は続けて行われます。また、必要であればRust 2015にも変更が加えられます。


なぜエディションという形をとるのか

ユーザのコードを破壊することなく、破壊的変更を取り入れることのできる方法だからです。

また、Rustでは6週間ごとのリリースで細かい変更を積み重ねてきましたが、これはRustの変化を追い続けることを難しくしています。エディションという密なパッケージにすることで、これまで行われた変更を大きな視点から知ることができます。


Rust 2018での変更点

The Rust Edition Guideを読めば、今の所予定されている変更点を伺い知ることができます。いくつか以下に紹介しますが、この文書自体が書きかけで、確定ではありません。

追記(2018/11/30)

The Rust Edition Guideがかなり整備され、どの機能がどのバージョンのrustcから導入されるかわかるようになりました。また、async,await構文はRust 1.31時点では導入されず、安定化はRust 2018リリースより後となりました。


非同期処理

async、await構文が追加されます。


モジュール

extern crateが不要になり、use文で他クレートのシンボルを直接インポートできるようになります。

パス指定がクレート名で始まった場合、絶対パスとして認識されます。つまり、次のような書き方が可能になります。

mod foo {

fn bar() {
let a = std::boxed::Box::new(1);
}
}

Rust 2015では相対パスのため、fooの中のstdという名前のモジュールを探してしまいますが、Rust 2018では期待通りにstdクレート内のパスをたどってくれるようになります。パスがcrateで始まった場合、現在のクレートの先頭からのパス指定となります。同様に、selfは現在のモジュール、superは親モジュールからのパス指定となります。

pub(crate)crateに変更され、短く書けるようになります。

マクロがuse文でインポートできるようになるなど、Rustの他のシンボルと同様にモジュールベースで扱えるようになります。


ライフタイム

いくつかの省略した書き方が導入されます。

例えば、fnimpl宣言において、<>内でのライフタイムの宣言が省略できるようになります。

また、Non-lexical lifetime(NLL)が導入されます。Rust 2015では、スコープ範囲をベースにライフタイムを管理していましたが、NLLによりスコープに縛られないもっと柔軟な書き方が可能になります。


トレイト

impl Trait構文とdyn Trait構文が導入されます。Rust 2018では、トレイトオブジェクトを使う時は、dyn Trait構文が推奨されます。つまり、&Traitよりも&dyn Traitを使うことになります。これらの構文はRust 2015にもすでに導入されています。


Rust 2018を試す

Nightlyコンパイラで、#![feature(rust_2018_preview)]を追加します。

#![feature(rust_2018_preview)]

fn main() {
}

mod a {
pub fn foo() {
let _ = std::boxed::Box::new(1); // 新しいパス指定方法
}
}

Cargoを使う場合は、以下をCargo.tomlに追記します。こちらもNightlyが必要です。main.rsへのfeatureの指定は不要のようです。

cargo-features = ["edition"]

[package]
edition = '2018'

ただし、以上の指定をしても、予定されている機能が全て有効になるわけではないようです。例えば、NLLを有効にするためには#![feature(nll)]の追加が必要です。


Rust 2018がリリースされた後でも、これまでのRust(Rust 2015)で書かれたコードは引き続き使えるようですので、とりあえずひと安心というところでしょうか。Rust 2018で起こる変更は確定ではなく、issueやフォーラムで活発な議論が行われている最中です。