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

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

Yuki Toyoda
November 30, 2022
2.7k

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

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

Yuki Toyoda

November 30, 2022
Tweet

Transcript

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


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

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

    や TS 、C++ がメインの会社かも。 
 ◦ 一部コンポーネントに Rust を使用しています。
 ◦ 最近ベラルーシの C++ エンジニアが Rust を書いていたの を観測しはしました。 
 • 高トラフィックなサーバーや検索などに Rust を利用 しています。
 自己紹介
 5
  3. 標準ライブラリへの変更
 • [1.62, 1.63] Mutex の内部実装への変更と const 文脈化
 • [1.63]

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

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

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

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

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

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


    • std::thread::scope ならびにスコープの spawn を経由したスレッドの利用が可能 になりました。これを利用すると static ライフタイムは求められなくなります。
 ◦ GhostCell のように、ライフタイムをきれいに整理して設計し直したよい例だなと思います。 
 ◦ GhostCell: https://zenn.dev/helloyuki/scraps/a242590b32655f
 今年の変更をおさらいする : 標準ライブラリへの変更 
 19
  9. 余談: Rust 1.0 時点での Scoped Thread
 • Rust には昔 Scoped

    Thread が存在していました。
 • が、「Leakpocalypse」と呼ばれる問題が発見され削除されました。
 • 数年の時を経て、標準ライブラリに戻ってくることになりました。
 Scoped Thread が導入された
 22
  10. 余談: 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
  11. 文法機能面への変更
 • [1.65] Generic Associated Types が利用可能に
 • [1.65] let-else

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

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

    これにより Rust 全体の型周りの抽象化の表現力が少し向上することになりました。
 今年の変更をおさらいする : 文法機能への変更
 26
  13. 余談: モナドが実装できる?
 • この手の機能は「高階カインド型(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
  14. [1.65] let-else が利用可能に
 • if let 構文(例: 「if let Some(b)

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

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

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

  17. 余談: ! 型
 • ! として表現される型で、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
  18. [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

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

    add でクレートの依存を追加できるように
 • [1.64] ワークスペースの共通設定が書けるように
 今年の変更をおさらいする 
 37
  20. [1.62] cargo add でクレートの依存を追加できるように
 • コマンド一つでクレートの依存を Cargo.toml に追記してくれます。
 • もともと

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

    などはプロジェクトをまたいでも利用するクレートですが、プロジェ クト間で共通の設定を利用することができ便利です。
 ◦ もちろんプロジェクトごとに個別で設定することも引き続きできます。 
 今年の変更をおさらいする : 周辺ツールへの変更 
 41
  22. 実務での新機能への対応
 • 正直あまりまじめにやっていません😅
 • 先日 let-else を使いたいがために、1.65にバージョンをあげました。
 • 新機能への対応は個人的には下記のスタンス。
 ◦

    標準ライブラリへの変更 : doc くらいは読んでおいて使えるときに思い出して使う。 
 ◦ 文法や機能への変更 : リリースノートは読んでおいて使えるときに思い出して使う。 
 ◦ 周辺ツールへの変更 : 何が入ったかは覚えておいて使えるときに思い出して使う。 
 • つまり、軽くリリースノートに目は通しておいて、使いたいときに使うようにしていま す。
 • バージョン自体はこまめに上げるようにしておいた方がよいかもしれません。
 44