Rust 2018のロードマップに続くRust 1.36で最も待ち望まれていた新機能は、同言語でasync/await
を実現するための最初のステップとなる、Future
トレイトのサポートだ。さらに、ボローチェッカの向上を目的としてNLL(non-lexical lifetime)がバックポートされた他、std
を必要としないメモリ割り当て依存ライブラリの構築を可能にするために、新たなalloc
クレートが導入されている。
Rustでは、フューチャはFuture
トレイトを通じてサポートされており、そのコアメソッドであるpoll
がフューチャの解決に使用される。最終値がまだ準備できていない場合、poll
は現在のタスクを一時停止し、その後poll
が可能になった時点で再起動する。ポーリングタスクでは、Future
の再起動に使用するWaker
を指定することができる。解決した後は、Future
はポーリングされない。このためパニックが発生したり、呼び出しタスクを無期限にブロックするなどの問題が発生する可能性がある。重要なのは、しかしながら、poll
がsafe
メソッドであって、どのような条件下でもメモリ破壊しない実装であるという保証をすることだ。
Rust 1.31(Rust 2018)で導入されたNLLが、Rust 2015でも使用できるようになった。Rust 2015でNLLがサポートされたため、古いボローチェッカは間もなく言語から削除されることになる。この移行を安全に行なうために、新たなボローチェッカでは、古いボローチェッカでは受け入れられていたが、新たなボローチェッカでは違反になるコードに対して、警告を発するようになる予定だ。NLLによって、レキシカルスコープにバインドする必要なく、変数の実際の有効期間が考慮されるようになる。これはRustのボローチェッカにとって大きな改善だ。
もうひとつの新たな安定機能はalloc
クレートである。これは、グローバルメモリアロケータを分析し、それに依存するすべてのタイプをstd
から取り出す作業を行った成果だ。結果としてstd
は、これらのタイプをすべてalloc
からインポートし、互換性維持のために再びエクスポートするようになる。メモリ割り当てを必要とするライブラリクレートは、同じようにalloc
直接インポートできるので、std
に依存関係を持つ必要がなくなる。std
は非常に大規模なクレートであるため、組み込みシステムなど、すべての環境で必ずしも使用できるとは限らないのだ。Rustチームによると、これは、より大きな#![no_std]
ライブラリエコシステムを構築可能にする上での重要なステップになる。alloc
のサポートは、ライブラリクレートに対してのみ安定化されていることに注意が必要である。つまり#![no_std]
バイナリでalloc
を使用可能にするためには、引き続き夜間ビルド(非安定版)のRustが必要となる。結果として、次のように記述することで、グローバルメモリアロケータに依存する#![no_std]
ライブラリを作成することができる。
#![no_std]
extern crate alloc;
Rust 1.36にはさらに、mem::uninitialized
を廃止するための道筋も用意されている。このメソッドは言語に残すには危険過ぎるものと考えられており、より安全なMaybeUninit<T>
の使用に置き換えられる予定である。mem::uninitialized
は従来、Rustの初期化チェックをバイパスして遅延割り当てを実装する目的で使用されていた。ただひとつ問題なのは、この機能を使用することで、その値が正しく初期化されるものとコンパイラが想定するため、Rustの持つ安全性が台無しになることだ。新たに用意されたMaybeUninit<T>
型は、サポートする動作はほぼ同じだが、プログラマに対して、可能であれば正常な初期化の後で、.assume_init()
を使ってその値を使用する意図を明示的に表現するように要求する点が異なる。
最後に注目すべき点として、Rust 1.36ではHashMap<K,V>
の実装が新しくなり、SwissTableを使用することによって、平均速度の向上と、メモリオーバヘッドの低減が実現されている。