こんにちは、R&Dチームの齋藤(@aznhe21)です。
さて、本日、日本時間2/12(金)、Rust 1.50がリリースされました。 この記事ではRust 1.50での変更点を詳しく紹介します。
ピックアップ
個人的に注目する変更点を「ピックアップ」としてまとめました。 全ての変更点を網羅したリストは変更点リストをご覧ください。
なお、定数ジェネリクスは1.51に延期されていました。残念!
Rust財団が誕生
Rust 1.50のリリースとは関係ありませんが、直近のビッグニュースなのでここで紹介します。
先日2021/2/8にRust財団が設立されました。Rust財団は、Rust言語とその周辺環境を支援するために設立された独立の非営利組織です。 設立メンバー企業として、AWS、Huawei、Google、Microsoft、そしてMozillaが名を連ねています。
これまでMozillaが管理していた知財(商標・ロゴなど)やインフラ(crates.io含む)は既に財団に移管されており、 より独立した運営がスタートしています。 昨年のMozillaの大規模レイオフによって不安視されていた金銭面への不安もこれで払拭されるでしょう。
設立メンバーの各企業による声明は以下の記事にまとめられています。
ディレクトリ内容を変更した際のbuild.rsの再実行
build.rsにprintln!("cargo:rerun-if-changed:path/to/file")
と書くことで、ファイルが更新された際はbuild.rsを再実行する機能があります。
これはコード生成などに使う機能ですが、これまではディレクトリパスを指定しても、ディレクトリ内のファイルの変更ではbuild.rsの再実行はされませんでした。
Rust 1.50からはディレクトリパスを指定するとディレクトリ内のファイルを再帰的にチェックし、 変更されたファイルがあればbuild.rsを再実行されるようになりました。
boolの値でOptionを返す関数
真偽値が真(true
)のとき、クロージャーを呼び出してSome
に包む関数bool::then
が使えるようになりました。
無駄なif
式が消えてスッキリします。
fn safe_div(a: u32, b: u32) -> Option<u32> { // Rust < 1.50 // if b > 0 { // Some(a / b) // } else { // None // } // Rust >= 1.50 (b > 0).then(|| a / b) }
値域を制限する関数
数値の最小値、最大値を指定するとその範囲内に収めてくれる関数Ord::clamp
、f32::clamp
及びf64::clamp
が使えるようになりました。
これもまたコードをスッキリさせる便利関数です。
これはOrd
及びf32
・f64
に実装されています。
fn clamp_array(f: &[f32]) -> Vec<f32> { // Rust < 1.50 // f.iter().map(|&v| if v < 0. { 0. } else if v > 1. { 1. } else { v }).collect() // Rust >= 1.50 f.iter().map(|v| v.clamp(0., 1.)).collect() }
配列を同じ値で埋める関数
配列をループせず、同じ値で埋める関数slice::fill
が使えるようになりました。
こちらも嬉しい便利関数ですね。
struct Image { pub data: Vec<u8>, pub width: u32, pub height: u32, } impl Image { pub fn make_white(&mut self) { self.data.fill(0xFF); } }
安定化されたAPIのドキュメント
安定化されたAPIのドキュメントを独自に訳して紹介します。リストだけ見たい方は安定化されたAPIをご覧ください。
bool::then
#[lang = "bool"] impl bool { #[stable(feature = "lazy_bool_to_option", since = "1.50.0")] #[inline] pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> }
bool
がtrue
であればSome(f())
を返し、そうでない場合はNone
を返す。
サンプル
assert_eq!(false.then(|| 0), None); assert_eq!(true.then(|| 0), Some(0));
btree_map::Entry::or_insert_with_key
impl<'a, K: Ord, V> Entry<'a, K, V> { #[inline] #[stable(feature = "or_insert_with_key", since = "1.50.0")] pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V }
エントリが空の場合、default
関数の結果を挿入することでエントリに値があることを確定させる。
この関数により、.entry(key)
の呼び出しによってムーブされたキーをdefault
関数から参照することで、キーに由来した値を挿入することが出来る。
.or_insert_with(|| ... )
を使うのとは違ってムーブされたキーを参照できるため、キーのクローンやコピーが不要。
サンプル
use std::collections::BTreeMap; let mut map: BTreeMap<&str, usize> = BTreeMap::new(); map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); assert_eq!(map["poneyland"], 9);
f32::clamp
#[lang = "f32"] #[cfg(not(test))] impl f32 { // メソッドは元の値を変更せず、新しい値を返す #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] #[inline] pub fn clamp(self, min: f32, max: f32) -> f32 }
値がNaNで無い限り、値を指定された区間に限定させる。
self
がmax
より大きい場合はmax
を、self
がmin
より小さい場合はmin
を、それ以外はself
を返す。
初期値がNaNの場合はNaNを返すことに注意されたい。
パニック
min > max
の場合、あるいはmin
かmax
がNaNの場合はパニックする。
サンプル
assert!((-3.0f32).clamp(-2.0, 1.0) == -2.0); assert!((0.0f32).clamp(-2.0, 1.0) == 0.0); assert!((2.0f32).clamp(-2.0, 1.0) == 1.0); assert!((f32::NAN).clamp(-2.0, 1.0).is_nan());
f64::clamp
#[lang = "f64"] #[cfg(not(test))] impl f64 { // メソッドは元の値を変更せず、新しい値を返す #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] #[inline] pub fn clamp(self, min: f64, max: f64) -> f64 }
値がNaNで無い限り、値を指定された区間に限定させる。
self
がmax
より大きい場合はmax
を、self
がmin
より小さい場合はmin
を、それ以外はself
を返す。
初期値がNaNの場合はNaNを返すことに注意されたい。
パニック
min > max
の場合、あるいはmin
かmax
がNaNの場合はパニックする。
サンプル
assert!((-3.0f64).clamp(-2.0, 1.0) == -2.0); assert!((0.0f64).clamp(-2.0, 1.0) == 0.0); assert!((2.0f64).clamp(-2.0, 1.0) == 1.0); assert!((f64::NAN).clamp(-2.0, 1.0).is_nan());
hash_map::Entry::or_insert_with_key
impl<'a, K, V> Entry<'a, K, V> { #[inline] #[stable(feature = "or_insert_with_key", since = "1.50.0")] pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V }
エントリが空の場合、default
関数の結果を挿入することでエントリに値があることを確定させる。
この関数により、.entry(key)
の呼び出しによってムーブされたキーをdefault
関数から参照することで、キーに由来した値を挿入することが出来る。
.or_insert_with(|| ... )
を使うのとは違ってムーブされたキーを参照できるため、キーのクローンやコピーが不要。
サンプル
use std::collections::HashMap; let mut map: HashMap<&str, usize> = HashMap::new(); map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); assert_eq!(map["poneyland"], 9);
Ord::clamp
#[doc(alias = "<")] #[doc(alias = ">")] #[doc(alias = "<=")] #[doc(alias = ">=")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd<Self> { #[must_use] #[stable(feature = "clamp", since = "1.50.0")] fn clamp(self, min: Self, max: Self) -> Self where Self: Sized, }
値を指定された区間に限定させる。
self
がmax
より大きい場合はmax
を、self
がmin
より小さい場合はmin
を、それ以外はself
を返す。
パニック
min > max
の場合はパニックする。
サンプル
assert!((-3).clamp(-2, 1) == -2); assert!(0.clamp(-2, 1) == 0); assert!(2.clamp(-2, 1) == 1);
RefCell::take
impl<T: Default> RefCell<T> { #[stable(feature = "refcell_take", since = "1.50.0")] pub fn take(&self) -> T }
内包する値を取り出し、Default::default()
で返る値と入れ替える。
パニック
値が借用されている場合はパニックする。
サンプル
use std::cell::RefCell; let c = RefCell::new(5); let five = c.take(); assert_eq!(five, 5); assert_eq!(c.into_inner(), 0);
slice::fill
#[lang = "slice"] #[cfg(not(test))] impl<T> [T] { #[doc(alias = "memset")] #[stable(feature = "slice_fill", since = "1.50.0")] pub fn fill(&mut self, value: T) where T: Clone, }
self
の各要素を、value
を複製して埋める。
サンプル
let mut buf = vec![0; 10]; buf.fill(1); assert_eq!(buf, vec![1; 10]);
UnsafeCell::get_mut
impl<T: ?Sized> UnsafeCell<T> { #[inline] #[stable(feature = "unsafe_cell_get_mut", since = "1.50.0")] pub fn get_mut(&mut self) -> &mut T }
保持しているデータへの可変参照を返す。
この呼び出しによってUnsafeCell
は可変で(コンパイル時に)借用されるため、唯一の参照を所有することが保証される。
サンプル
use std::cell::UnsafeCell; let mut c = UnsafeCell::new(5); *c.get_mut() += 1; assert_eq!(*c.get_mut(), 6);
変更点リスト
公式リリースノートをベースに意訳・編集・追記をした変更点リストです。
言語
- 配列の
[x; N]
の記法において定数値を使えるようになった。技術的にはRust 1.38.0から可能だったもので、うっかり安定化されていたものを事後承認した。 ※訳注:const EMPTY = Vec::new()
のように定義されている時、[EMPTY; N]
と書くことは可能だが、[Vec::new(); N]
と書くことは(依然として)出来ない - 共用体(
union
)のManuallyDrop<T>
フィールドへの代入は安全と見做されるようになった
コンパイラ
armv5te-unknown-linux-uclibceabi
ターゲットがティア3でサポートされるようになったaarch64-apple-ios-macabi
ターゲットがティア3でサポートされるようになったx86_64-unknown-freebsd
が完全なツールセットでビルドされるようになった
※Rustのティアで管理されるプラットフォームの詳細はPlatform Supportのページ(英語)を参照
ライブラリ
proc_macro::Punct
がPartialEq<char>
を実装するようになった- あらゆる長さの固定長配列が
ops::{Index, IndexMut}
を実装するようになった - Unix環境において、
std::fs::File
が-1
の「窪み(niche)」を持つようになった。 正常なファイル記述子はこの値にはならず、これによりOption<File>
がFile
と同じ量の領域だけ使うようになった。 ※訳注:nicheについては用語集(英語)を参照。言い換えるなら「盲点」としても良いかもしれない
安定化されたAPI
※各APIのドキュメントを独自に訳しています。安定化されたAPIのドキュメントもご参照ください。
bool::then
btree_map::Entry::or_insert_with_key
f32::clamp
f64::clamp
hash_map::Entry::or_insert_with_key
Ord::clamp
RefCell::take
slice::fill
UnsafeCell::get_mut
また、以前から安定化されていたAPIのうち以下のものが定数化された。
IpAddr::is_ipv4
IpAddr::is_ipv6
Layout::size
Layout::align
Layout::from_size_align
- 全ての整数型の
pow
- 全ての整数型の
checked_pow
- 全ての整数型の
saturating_pow
- 全ての整数型の
wrapping_pow
- 全ての符号なし整数型の
next_power_of_two
- 全ての符号なし整数型の
checked_power_of_two
Cargo
- オプション
[build.rustc-workspace-wrapper]
を追加した。 このオプションはワークスペース限定の、rustc
の代わりに実行するラッパーを設定する cargo:rerun-if-changed
にディレクトリが指定された時、変更の確認を全ファイルに対して実行するようになった
→ピックアップcargo update
コマンドに--workspace
フラグを追加した
その他
互換性メモ
- 原子型(アトミック型)の
compare_and_swap
メソッドの使用が推奨されなくなった。 代わりにcompare_exchange
やcompare_exchange_weak
の使用が推奨される TokenStream
のチェック方法を変更し、非衛生的なmacro_rules!
が書ける場合があったのを修正した- 他のマクロ属性と同じ様に、内部の属性としての
#![test]
の使用が不安定と見做されるようになった。デフォルトではsoft_unstable
リントによってエラーが発される - 同一レベルでの
forbid
リントの上書きでコンパイルエラーが発されるようになった - 全てのcloudabiターゲットのサポートを終了した
- 独自のマクロを使った
panic!
の呼び出しの横取りが出来なくなった。代わりに#[panic_handler]
属性を使った実装が推奨される - アイテム文直後のセミコロン(
struct Foo {};
など)で警告が発されるようになった
関連リンク
さいごに
次のRust 1.51は2021/3/26(金)に予定されています。 今度こそ定数ジェネリクスが使えるようになる他、配列の各要素の所有権を奪ってイテレートするための機能などが入るようです。
オプティムでは進化するエンジニアを募集しています。
ライセンス表記
- この記事はApache 2/MITのデュアルライセンスで公開されている公式リリースノートを翻訳・追記をしています
- 冒頭の画像中にはRust公式サイトで配布されているロゴを使用しており、 このロゴはRust財団によってCC-BYの下で配布されています
- 冒頭の画像はいらすとやさんの画像を使っています。いつもありがとうございます
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Apache License
Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*1:"A man who dares to waste an hour of time has not discovered the value of life." - Charles Darwin https://www.darwinproject.ac.uk/letter/DCP-LETT-306.xml
*2:"A language which dares to waste a word of memory has not discovered the value of lifetime." - Rust 1.50を早めに深堀り