Upgrade to Pro — share decks privately, control downloads, hide ads and more …

年末ですし、今年のRustの進捗の話をしましょう

Yuki Toyoda
November 30, 2022
2.3k

 年末ですし、今年のRustの進捗の話をしましょう

TechFeed Experts Night #9 で使用した発表資料です。2022年の Rust になされた変更やアップデートから、個人的に気になったものをピックアップした発表です。

Yuki Toyoda

November 30, 2022
Tweet

Transcript

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


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


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


  4. 4 自己紹介
 yuki
 ソフトウェアエンジニア 
 公認エキスパート(Rust)
 @helloyuki_
 所属: マップボックスジャパン合同会社 


    
 執筆
 • 実践Rustプログラミング入門(共著) 
 • WEB+DB PRESS vol.131(レビュワー)
 • 日経クロステック連載 
 
 その他
 • Rust Tokyo の運営をしています。 
 • This Week in Rust の日本語記事レビュワーをしています。 
 • ツイッターランドでRustお役立ち情報ボットをしています。 
 
 スプラトゥーン3の chill season が楽しみで仕方ない人 

  5. Mapbox で何をしてるの?
 • 地図技術等を作るアメリカの会社。
 • Rust がメインというわけではありません。
 ◦ というか JS

    や TS 、C++ がメインの会社かも。 
 ◦ 一部コンポーネントに Rust を使用しています。
 ◦ 最近ベラルーシの C++ エンジニアが Rust を書いていたの を観測しはしました。 
 • 高トラフィックなサーバーや検索などに Rust を利用 しています。
 自己紹介
 5
  6. アジェンダ
 6 自己紹介
 本発表の前提と目的
 2022年編: 今年の変更をおさらいする
 実務での新機能への対応
 まとめ


  7. 本発表の前提
 • Rust の中上級者向けの発表です。
 • Rust の基礎文法に習熟していることを前提とします。
 ◦ 「習熟」といっても、Rust において「構造体」「enum」「パターンマッチ」などがどういう風に書かれるか

    をご存知であれば楽しめると思います。 
 • 既存の文法や機能の解説はほぼしません。
 7
  8. 本発表の目的
 • 発表者が今年「入って嬉しかった」「入った背景がおもしろかった」と思った機能や変 更を紹介します。
 • 嬉しさやおもしろさは主観的なものです。
 • この発表自体しゃべりたいだけなので深い意図を持ちません。
 • みなさんの「嬉しかった」や「おもしろかった」も教えてください!


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


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

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


    今年は豊作な1年でしたね!💛
 11
  12. 今年の変更をおさらいする
 標準ライブラリへの変更
 1
 文法機能面への変更
 2
 周辺ツールへの変更
 3
 12

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

  14. 標準ライブラリへの変更
 • [1.62, 1.63] Mutex の内部実装への変更と const 文脈化
 • [1.63]

    Scoped Thread が導入された
 今年の変更をおさらいする 
 14 調べてておもしろかった 

  15. [1.62, 1.63] Mutex の内部実装への変更と const 文脈化
 • Mutex (と Condvar、RwLock)の内部実装が変更され、Linux

    のシステムコール の一つである futex を使うように修正されました(他のOSでも相応に修正されました) 。
 • これにより、メモリ使用量の削減とパフォーマンスの向上が見込めます。
 • さらに副産物として、ヒープ領域を使用する必要がなくなるため、Mutex が const 文 脈で使用できるようになりました。
 ◦ = OnceCell や lazy_static を使わなくて済むようになりました。 
 今年の変更をおさらいする : 標準ライブラリへの変更 
 15
  16. futex を利用するように実装を調整した
 従来、Mutex は `Box<pthread_mutex_t>` をラップしたものでしたが、 (Linux では) futex というシステムコー

    ルを利用することにより、 Box を剥がすことに成功します。 
 Mutex の内部実装への変更と const 文脈化
 修正前の実装
 修正後の実装
 📝 AtomicI32 には、0, 1, 2 が入る。futex の制御に利用され る。
 16
  17. futex を利用するように実装を調整した
 Rust コアチームの Mara Bos 氏が中心となってこの修正を行いましたが、そのときの話が RustConf 2021 にて

    されています。経緯を知ることができます。 
 Mutex の内部実装への変更と const 文脈化
 https://www.youtube.com/watch?v=DnYQKWs_7EA
 17
  18. Mutex を const 文脈で使用できるようになった
 内部実装に Box は必要なくなったため、従来 OnceCell などのクレートと組み合わせて static

    で利用していた Mutex は、その必要がなくなりました。 
 Mutex の内部実装への変更と const 文脈化
 18
  19. [1.63] Scoped Thread が導入された
 • 従来の std::thread::spawn によるスレッドの利用では、キャプチャする変数に ’static ライフタイムが求められるため不便な場面がありました。


    • std::thread::scope ならびにスコープの spawn を経由したスレッドの利用が可能 になりました。これを利用すると static ライフタイムは求められなくなります。
 ◦ GhostCell のように、ライフタイムをきれいに整理して設計し直したよい例だなと思います。 
 ◦ GhostCell: https://zenn.dev/helloyuki/scraps/a242590b32655f
 今年の変更をおさらいする : 標準ライブラリへの変更 
 19
  20. [1.63] Scoped Thread が導入された
 std::thread::spawn はクロージャーのライフタイムに static を求めています。つまりスレッドはローカル変 数を借用できなかったので、clone が(あるいは

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


    今年の変更をおさらいする : 標準ライブラリへの変更 
 21
  22. 余談: Rust 1.0 時点での Scoped Thread
 • Rust には昔 Scoped

    Thread が存在していました。
 • が、「Leakpocalypse」と呼ばれる問題が発見され削除されました。
 • 数年の時を経て、標準ライブラリに戻ってくることになりました。
 Scoped Thread が導入された
 22
  23. 余談: 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
  24. 今年の変更をおさらいする
 標準ライブラリへの変更
 1
 文法機能面への変更
 2
 周辺ツールへの変更
 3
 24

  25. 文法機能面への変更
 • [1.65] Generic Associated Types が利用可能に
 • [1.65] let-else

    が利用可能に
 • [1.62] enum のデフォルトのヴァリアントを指定可能に
 • [1.64] await は IntoFuture::into_future に脱糖されるように
 今年の変更をおさらいする 
 25 便利すぎる!! 

  26. [1.65] Generic Associated Types が利用可能に
 • 関連型に型パラメータないしはライフタイム注釈を付与できるようになりました。
 • 略して「GATs」などと呼ばれています。
 •

    これにより Rust 全体の型周りの抽象化の表現力が少し向上することになりました。
 今年の変更をおさらいする : 文法機能への変更
 26
  27. イテレータを新しく実装し直してみる例
 下記はトレイトの関連型「 Item」にライフタイム注釈を付与し、 Item 単位でライフタイムをもたせるように実装した 例です。
 Generic Associated Types が利用可能に


    27 「Self の全ての参照は、’a より長生きでなくてはならない」

  28. 余談: モナドが実装できる?
 • この手の機能は「高階カインド型(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
  29. [1.65] let-else が利用可能に
 • if let 構文(例: 「if let Some(b)

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

    のケースはケアしなくてもよいが、そうしたケース においてわざわざネストを 1つ増やさなくてよくなります。 
 文法機能面への変更 
 30
  31. else の中には発散する型を返す式を書く必要がある
 私も最初ハマりましたが、 else の中には発散する式( never 型; `!`)を返す処理を書く必要があります。 else 側の

    型合わせの際に、返す型の不一致でコンパイルエラーにならないようにするためです。 
 let-else が利用可能に
 31 return をなくしてみたが、これはダメ。

  32. 余談: ! 型
 • ! として表現される型で、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
  33. [1.62] enum のデフォルトのヴァリアントを指定可能に
 • #[default] というアトリビュートを追加すると、Default::default を使用した際に使 われるヴァリアントを指定できるようになりました。
 • ユニット型のヴァリアントにのみ付与できるという制約があります。


    ◦ 付与したDefault が自動導出する実装に問題がある場合があるらしい。 (rust-lang/rust #26925)
 文法機能面への変更 
 33
  34. [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

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

    
 35 async 関数を定義して使用した例 
 脱糖のイメージ

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

  37. 周辺ツールへの変更
 • [1.60] cargo build –timings が安定化
 • [1.62] cargo

    add でクレートの依存を追加できるように
 • [1.64] ワークスペースの共通設定が書けるように
 今年の変更をおさらいする 
 37
  38. [1.60] cargo build --timings が安定化
 • どのクレートのビルドにどれくらい時間がかかったかや、ビルド時のリソースの使用状 況などを計測できます。
 • nightly

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

    周辺ツールへの変更 
 39
  40. [1.62] cargo add でクレートの依存を追加できるように
 • コマンド一つでクレートの依存を Cargo.toml に追記してくれます。
 • もともと

    cargo-edit というプラグインでしたが、Rust 本体に取り込まれたようです。
 ◦ ただし、本体の挙動とはいくつか微妙に異なる。ならびに、ないコマンドもある。 
 今年の変更をおさらいする : 周辺ツールへの変更 
 40
  41. [1.64] ワークスペースの共通設定が書けるように
 • ワークスペースを使用している場合、ワークスペースのルート側の Cargo.toml に ワークスペース内の共通設定や共通依存クレートを定義できるようになりました。
 • たとえば anyhow

    などはプロジェクトをまたいでも利用するクレートですが、プロジェ クト間で共通の設定を利用することができ便利です。
 ◦ もちろんプロジェクトごとに個別で設定することも引き続きできます。 
 今年の変更をおさらいする : 周辺ツールへの変更 
 41
  42. プロジェクト単位で共通設定を使える
 ワークスペースのルートに共通設定を書き、使用したいプロジェクト側で「 xxx.workspace = true」とすると、共 通する設定項目を引き出せます。下記はクレートのメタ情報と一部依存クレートに適用してみた例です。 
 ワークスペースの共通設定が書けるように 
 42

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


  44. 実務での新機能への対応
 • 正直あまりまじめにやっていません😅
 • 先日 let-else を使いたいがために、1.65にバージョンをあげました。
 • 新機能への対応は個人的には下記のスタンス。
 ◦

    標準ライブラリへの変更 : doc くらいは読んでおいて使えるときに思い出して使う。 
 ◦ 文法や機能への変更 : リリースノートは読んでおいて使えるときに思い出して使う。 
 ◦ 周辺ツールへの変更 : 何が入ったかは覚えておいて使えるときに思い出して使う。 
 • つまり、軽くリリースノートに目は通しておいて、使いたいときに使うようにしていま す。
 • バージョン自体はこまめに上げるようにしておいた方がよいかもしれません。
 44
  45. アジェンダ
 45 自己紹介
 本発表の前提と目的
 2022年編: 今年の変更をおさらいする
 実務での新機能への対応
 まとめ


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

    https://zenn.dev/helloyuki/scraps/bede736a081b0a
 46