Slide 1

Slide 1 text

年末ですし、今年の
 Rustの進捗の話をしましょう
 TechFeed Experts Night #9


Slide 2

Slide 2 text

アジェンダ
 2 自己紹介
 本発表の前提と目的
 2022年編: 今年の変更をおさらいする
 実務での新機能への対応
 まとめ


Slide 3

Slide 3 text

アジェンダ
 3 自己紹介
 本発表の前提と目的
 2022年編: 今年の変更をおさらいする
 実務での新機能への対応
 まとめ


Slide 4

Slide 4 text

4 自己紹介
 yuki
 ソフトウェアエンジニア 
 公認エキスパート(Rust)
 @helloyuki_
 所属: マップボックスジャパン合同会社 
 
 執筆
 ● 実践Rustプログラミング入門(共著) 
 ● WEB+DB PRESS vol.131(レビュワー)
 ● 日経クロステック連載 
 
 その他
 ● Rust Tokyo の運営をしています。 
 ● This Week in Rust の日本語記事レビュワーをしています。 
 ● ツイッターランドでRustお役立ち情報ボットをしています。 
 
 スプラトゥーン3の chill season が楽しみで仕方ない人 


Slide 5

Slide 5 text

Mapbox で何をしてるの?
 ● 地図技術等を作るアメリカの会社。
 ● Rust がメインというわけではありません。
 ○ というか JS や TS 、C++ がメインの会社かも。 
 ○ 一部コンポーネントに Rust を使用しています。
 ○ 最近ベラルーシの C++ エンジニアが Rust を書いていたの を観測しはしました。 
 ● 高トラフィックなサーバーや検索などに Rust を利用 しています。
 自己紹介
 5

Slide 6

Slide 6 text

アジェンダ
 6 自己紹介
 本発表の前提と目的
 2022年編: 今年の変更をおさらいする
 実務での新機能への対応
 まとめ


Slide 7

Slide 7 text

本発表の前提
 ● Rust の中上級者向けの発表です。
 ● Rust の基礎文法に習熟していることを前提とします。
 ○ 「習熟」といっても、Rust において「構造体」「enum」「パターンマッチ」などがどういう風に書かれるか をご存知であれば楽しめると思います。 
 ● 既存の文法や機能の解説はほぼしません。
 7

Slide 8

Slide 8 text

本発表の目的
 ● 発表者が今年「入って嬉しかった」「入った背景がおもしろかった」と思った機能や変 更を紹介します。
 ● 嬉しさやおもしろさは主観的なものです。
 ● この発表自体しゃべりたいだけなので深い意図を持ちません。
 ● みなさんの「嬉しかった」や「おもしろかった」も教えてください!
 8

Slide 9

Slide 9 text

アジェンダ
 9 自己紹介
 本発表の前提と目的
 2022年編: 今年の変更をおさらいする
 実務での新機能への対応
 まとめ


Slide 10

Slide 10 text

今年の変更をおさらいする
 10

Slide 11

Slide 11 text

みなさんのハイライトはなんでしたか?
 今年の変更をおさらいする 
 やはりGATs?
 let-else便利?
 cargo add 嬉 しくない?
 Mutex周り?
 今年は豊作な1年でしたね!💛
 11

Slide 12

Slide 12 text

今年の変更をおさらいする
 標準ライブラリへの変更
 1
 文法機能面への変更
 2
 周辺ツールへの変更
 3
 12

Slide 13

Slide 13 text

今年の変更をおさらいする
 標準ライブラリへの変更
 1
 文法機能面への変更
 2
 周辺ツールへの変更
 3
 13

Slide 14

Slide 14 text

標準ライブラリへの変更
 ● [1.62, 1.63] Mutex の内部実装への変更と const 文脈化
 ● [1.63] Scoped Thread が導入された
 今年の変更をおさらいする 
 14 調べてておもしろかった 


Slide 15

Slide 15 text

[1.62, 1.63] Mutex の内部実装への変更と const 文脈化
 ● Mutex (と Condvar、RwLock)の内部実装が変更され、Linux のシステムコール の一つである futex を使うように修正されました(他のOSでも相応に修正されました) 。
 ● これにより、メモリ使用量の削減とパフォーマンスの向上が見込めます。
 ● さらに副産物として、ヒープ領域を使用する必要がなくなるため、Mutex が const 文 脈で使用できるようになりました。
 ○ = OnceCell や lazy_static を使わなくて済むようになりました。 
 今年の変更をおさらいする : 標準ライブラリへの変更 
 15

Slide 16

Slide 16 text

futex を利用するように実装を調整した
 従来、Mutex は `Box` をラップしたものでしたが、 (Linux では) futex というシステムコー ルを利用することにより、 Box を剥がすことに成功します。 
 Mutex の内部実装への変更と const 文脈化
 修正前の実装
 修正後の実装
 📝 AtomicI32 には、0, 1, 2 が入る。futex の制御に利用され る。
 16

Slide 17

Slide 17 text

futex を利用するように実装を調整した
 Rust コアチームの Mara Bos 氏が中心となってこの修正を行いましたが、そのときの話が RustConf 2021 にて されています。経緯を知ることができます。 
 Mutex の内部実装への変更と const 文脈化
 https://www.youtube.com/watch?v=DnYQKWs_7EA
 17

Slide 18

Slide 18 text

Mutex を const 文脈で使用できるようになった
 内部実装に Box は必要なくなったため、従来 OnceCell などのクレートと組み合わせて static で利用していた Mutex は、その必要がなくなりました。 
 Mutex の内部実装への変更と const 文脈化
 18

Slide 19

Slide 19 text

[1.63] Scoped Thread が導入された
 ● 従来の std::thread::spawn によるスレッドの利用では、キャプチャする変数に ’static ライフタイムが求められるため不便な場面がありました。
 ● std::thread::scope ならびにスコープの spawn を経由したスレッドの利用が可能 になりました。これを利用すると static ライフタイムは求められなくなります。
 ○ GhostCell のように、ライフタイムをきれいに整理して設計し直したよい例だなと思います。 
 ○ GhostCell: https://zenn.dev/helloyuki/scraps/a242590b32655f
 今年の変更をおさらいする : 標準ライブラリへの変更 
 19

Slide 20

Slide 20 text

[1.63] Scoped Thread が導入された
 std::thread::spawn はクロージャーのライフタイムに static を求めています。つまりスレッドはローカル変 数を借用できなかったので、clone が(あるいは Arc に包む)必要な場面がありました。
 今年の変更をおさらいする : 標準ライブラリへの変更 
 20

Slide 21

Slide 21 text

[1.63] Scoped Thread が導入された
 scoped_thread を利用するとクローンは不要になります。ついでにスコープを抜ける瞬間に join が走るの で、join の呼び出しも不要になります。
 今年の変更をおさらいする : 標準ライブラリへの変更 
 21

Slide 22

Slide 22 text

余談: Rust 1.0 時点での Scoped Thread
 ● Rust には昔 Scoped Thread が存在していました。
 ● が、「Leakpocalypse」と呼ばれる問題が発見され削除されました。
 ● 数年の時を経て、標準ライブラリに戻ってくることになりました。
 Scoped Thread が導入された
 22

Slide 23

Slide 23 text

余談: Leakpocalypse
 ● 「参照カウンタで循環参照を作ってJoinGuardをリークさせると、Scoped Threadが 解放されたメモリにアクセスできてしまう」
 ● Rust は静的検査などでメモリリークを防ぐことを保証していませんが、それはこうし た事例が理由となっています。
 ● 詳しくは下記の記事や Issue を参照。
 ○ Pre-Pooping Your Pants With Rust: https://cglab.ca/~abeinges/blah/everyone-poops/
 ○ 超焦ってる様子がわかる当時の Issue: https://github.com/rust-lang/rust/issues/24292
 余談: Rust 1.0 時点での Scoped Thread
 23

Slide 24

Slide 24 text

今年の変更をおさらいする
 標準ライブラリへの変更
 1
 文法機能面への変更
 2
 周辺ツールへの変更
 3
 24

Slide 25

Slide 25 text

文法機能面への変更
 ● [1.65] Generic Associated Types が利用可能に
 ● [1.65] let-else が利用可能に
 ● [1.62] enum のデフォルトのヴァリアントを指定可能に
 ● [1.64] await は IntoFuture::into_future に脱糖されるように
 今年の変更をおさらいする 
 25 便利すぎる!! 


Slide 26

Slide 26 text

[1.65] Generic Associated Types が利用可能に
 ● 関連型に型パラメータないしはライフタイム注釈を付与できるようになりました。
 ● 略して「GATs」などと呼ばれています。
 ● これにより Rust 全体の型周りの抽象化の表現力が少し向上することになりました。
 今年の変更をおさらいする : 文法機能への変更
 26

Slide 27

Slide 27 text

イテレータを新しく実装し直してみる例
 下記はトレイトの関連型「 Item」にライフタイム注釈を付与し、 Item 単位でライフタイムをもたせるように実装した 例です。
 Generic Associated Types が利用可能に
 27 「Self の全ての参照は、’a より長生きでなくてはならない」


Slide 28

Slide 28 text

余談: モナドが実装できる?
 ● この手の機能は「高階カインド型(higher-kinded types)」と呼ばれるもので、関数 型プログラミングが好きな人からすると「お?モナドいける?」とテンションが上がるか もしれません。
 ● が、Monad から Applicative を導出する際に、GATs では若干制約が足りない都 合上、GATs だけでモナドを実装し切るのは難しそうです。
 ○ 実験してくださった方がいました : https://zenn.dev/yyu/articles/f60ed5ba1dd9d5
 ● RFC にも、GATs がすぐさまモナドを実装可能にするものではないという記述がありま す。
 ○ https://rust-lang.github.io/rfcs/1598-generic_associated_types.html
 Generic Associated Types が利用可能に
 28

Slide 29

Slide 29 text

[1.65] let-else が利用可能に
 ● if let 構文(例: 「if let Some(b) = a {} else {}」)が「let Some(b) = a else {}」のよ うに書けるようになりました。
 ○ 「a」にはパターンマッチ可能なパターンが入ります。 
 ○ Swift にすでに導入されている guard という記法が元ネタのようです。 
 ● これによりネストが減って見た目がスッキリする、処理の流れが読みやすくなるなど のメリットが享受できるようになります。
 文法機能面への変更 
 29

Slide 30

Slide 30 text

[1.65] let-else が利用可能に
 if let Some を let-else で書き換えてみた例。この場合 None のケースはケアしなくてもよいが、そうしたケース においてわざわざネストを 1つ増やさなくてよくなります。 
 文法機能面への変更 
 30

Slide 31

Slide 31 text

else の中には発散する型を返す式を書く必要がある
 私も最初ハマりましたが、 else の中には発散する式( never 型; `!`)を返す処理を書く必要があります。 else 側の 型合わせの際に、返す型の不一致でコンパイルエラーにならないようにするためです。 
 let-else が利用可能に
 31 return をなくしてみたが、これはダメ。


Slide 32

Slide 32 text

余談: ! 型
 ● ! として表現される型で、Rust では never 型といいます。loop や continue などが実はこ の型を返しています。値を何も返さないことを表現します。 
 ● 雑にいうと、どの型にでもなることができます(型強制といいます)。 
 ○ たとえば返り値の型として i32 型を要求する関数内で never 型を返しても問題はありません。 
 ■ todo! マクロなどはこの仕組みを利用しています。 
 ○ let-else の else 側も同様の理屈で型合わせが行われています。 
 ● コンパイル時のデータフロー解析に使われます。
 ○ たとえば never 型を返す関数の後にある処理は決して到達しないので、以降の処理に関する命令は一切成果 物に含める必要はない、などの判断をできます。 
 ● 発展
 ○ https://doc.rust-jp.rs/book-ja/ch19-04-advanced-types.html#never%E5%9E%8B%E3%81%AF%E 7%B5%B6%E5%AF%BE%E3%81%AB%E8%BF%94%E3%82%89%E3%81%AA%E3%81%84
 ○ https://blog-dry.com/entry/2020/11/02/000313
 let-else が利用可能に
 32

Slide 33

Slide 33 text

[1.62] enum のデフォルトのヴァリアントを指定可能に
 ● #[default] というアトリビュートを追加すると、Default::default を使用した際に使 われるヴァリアントを指定できるようになりました。
 ● ユニット型のヴァリアントにのみ付与できるという制約があります。
 ○ 付与したDefault が自動導出する実装に問題がある場合があるらしい。 (rust-lang/rust #26925)
 文法機能面への変更 
 33

Slide 34

Slide 34 text

[1.64] await は IntoFuture::into_future に脱糖されるように
 ● for 式は裏で Iterator に脱糖されますが、同様に await でも IntoFuture トレイト を実装しておけば脱糖されるようになります。
 ● HTTP クライアントのクレートなどで「send」を呼び出して Future 化していた部分は await と書くだけでよくなります。
 文法機能面への変更 
 34 📝 reqwest を使った例。send 関数は実質 Future に直しているだけだが、こういう関 数の呼び出しが将来不要になるらしい。
 https://github.com/yuk1ty/connpass-rs/blob/dce6d73d5d7d387bcad028d6091877348bb0c2b3/src/client.rs#L77-L78


Slide 35

Slide 35 text

[1.64] await は IntoFuture::into_future に脱糖されるように
 .await が呼び出されると、「 into_future」メソッドが呼び出しされるよう、コンパイル時に裏で処理が書き変わるイ メージです。
 文法機能面への変更 
 35 async 関数を定義して使用した例 
 脱糖のイメージ


Slide 36

Slide 36 text

今年の変更をおさらいする
 標準ライブラリへの変更
 1
 文法機能面への変更
 2
 周辺ツールへの変更
 3
 36

Slide 37

Slide 37 text

周辺ツールへの変更
 ● [1.60] cargo build –timings が安定化
 ● [1.62] cargo add でクレートの依存を追加できるように
 ● [1.64] ワークスペースの共通設定が書けるように
 今年の変更をおさらいする 
 37

Slide 38

Slide 38 text

[1.60] cargo build --timings が安定化
 ● どのクレートのビルドにどれくらい時間がかかったかや、ビルド時のリソースの使用状 況などを計測できます。
 ● nightly にはすでにありましたが、安定化しました。
 今年の変更をおさらいする : 周辺ツールへの変更 
 38

Slide 39

Slide 39 text

[1.60] cargo build --timings が安定化
 たとえば、どのクレートのビルドにどのくらい時間がかかったかを知ることができます。ビルドのパフォーマンス チューニングに利用できるかもしれません。 
 今年の変更をおさらいする : 周辺ツールへの変更 
 39

Slide 40

Slide 40 text

[1.62] cargo add でクレートの依存を追加できるように
 ● コマンド一つでクレートの依存を Cargo.toml に追記してくれます。
 ● もともと cargo-edit というプラグインでしたが、Rust 本体に取り込まれたようです。
 ○ ただし、本体の挙動とはいくつか微妙に異なる。ならびに、ないコマンドもある。 
 今年の変更をおさらいする : 周辺ツールへの変更 
 40

Slide 41

Slide 41 text

[1.64] ワークスペースの共通設定が書けるように
 ● ワークスペースを使用している場合、ワークスペースのルート側の Cargo.toml に ワークスペース内の共通設定や共通依存クレートを定義できるようになりました。
 ● たとえば anyhow などはプロジェクトをまたいでも利用するクレートですが、プロジェ クト間で共通の設定を利用することができ便利です。
 ○ もちろんプロジェクトごとに個別で設定することも引き続きできます。 
 今年の変更をおさらいする : 周辺ツールへの変更 
 41

Slide 42

Slide 42 text

プロジェクト単位で共通設定を使える
 ワークスペースのルートに共通設定を書き、使用したいプロジェクト側で「 xxx.workspace = true」とすると、共 通する設定項目を引き出せます。下記はクレートのメタ情報と一部依存クレートに適用してみた例です。 
 ワークスペースの共通設定が書けるように 
 42

Slide 43

Slide 43 text

アジェンダ
 43 自己紹介
 本発表の前提と目的
 2022年編: 今年の変更をおさらいする
 実務での新機能への対応
 まとめ


Slide 44

Slide 44 text

実務での新機能への対応
 ● 正直あまりまじめにやっていません😅
 ● 先日 let-else を使いたいがために、1.65にバージョンをあげました。
 ● 新機能への対応は個人的には下記のスタンス。
 ○ 標準ライブラリへの変更 : doc くらいは読んでおいて使えるときに思い出して使う。 
 ○ 文法や機能への変更 : リリースノートは読んでおいて使えるときに思い出して使う。 
 ○ 周辺ツールへの変更 : 何が入ったかは覚えておいて使えるときに思い出して使う。 
 ● つまり、軽くリリースノートに目は通しておいて、使いたいときに使うようにしていま す。
 ● バージョン自体はこまめに上げるようにしておいた方がよいかもしれません。
 44

Slide 45

Slide 45 text

アジェンダ
 45 自己紹介
 本発表の前提と目的
 2022年編: 今年の変更をおさらいする
 実務での新機能への対応
 まとめ


Slide 46

Slide 46 text

まとめ
 ● 2022年に Rust に入った機能を駆け足で振り返りました。
 ● 本発表では時間の都合上細かい議論は省略しましたが、そうした話は下記の Zenn のスクラップにまとめています。
 ○ https://zenn.dev/helloyuki/scraps/bede736a081b0a
 46