プロンプトとスコープ
あるチームが複数のクレートをRust 2021からRust 2024に移行しようとしています。関数、モジュール、フィールド、マクロの出力で識別子genが使われています。Rust 2024ではこれがキーワードとして予約されているため、一部のクレートがパース時に失敗します。検出、修正、CIゲート、およびロールバックを設計してください。
エディション移行に焦点を当ててください。genブロックが安定化していると仮定せず、コンパイラのアップグレードとエディションの切り替えは分けて扱ってください。
面接官が見ているポイント
- エディションによってパース規則が変わる一方で、異なるエディションのクレート同士が相互に依存できることを説明できるか。
keyword_idents_2024リントとcargo fix --editionを使用してgen識別子を検出できるか。- 互換性のために、リネームと生識別子の使用を適切に比較検討できるか。
- マクロ、公開API、ビルドスクリプト、テスト、ワークスペースの依存関係を網羅できるか。
確認すべき質問
- 各クレートが使用しているエディション、MSRV、ツールチェーンは何ですか?
genは公開API、シリアライズ名、または外部マクロインターフェースに現れますか?- 影響を受けるトークンはソースコード、手続き型マクロ(proc macro)、ビルドスクリプトのどこから生成されていますか?
- この移行はRust 2021と2024を同時にサポートする必要がありますか?
- CIは機能フラグ(feature)の組み合わせ全体で両エディションを実行できますか?
30秒の回答
「ワークスペースのエディション、ツールチェーン、およびgenのすべての発生箇所を把握し、keyword_idents_2024を有効化します。内部シンボルはリネームし、公開APIで名前を維持する必要がある場合は生識別子r#genを使用して両エディションの呼び出し側を検証します。機械的な変更にはcargo fix --editionを実行し、マクロと公開インターフェースをレビューした上でCargoマニフェストを手動で更新し、Rust 2021、Rust 2024、および全featureマトリクスでcheck、test、docs、lintを実行します。各クレートは依存関係順に、ロールバック可能なコミットと互換性レポートを伴って移行します。」
ステップバイステップの設計
1. コンパイラとエディションの変更を分離する
コンパイラは古いエディションをビルドできます。エディションはクレートに対するパース規則を選択するものです。ツールチェーンとロックファイルを固定し、Rust 2021のベースラインを確立した上で、クレートのeditionフィールドを1つずつ変更します。これにより、コンパイラ、依存関係、言語仕様の変更が1つの差分に紛れ込むのを防ぎます。
2. genのすべての発生箇所を特定する
keyword_idents_2024を有効にして、古いエディションでは有効だったが2024では衝突する識別子が報告されるようにします。静的な検索に加えて、マクロ展開、proc-macroトークン、ビルドスクリプト、テストも補完して調査する必要があります。生成された出力を直接編集するのではなく、生成コードの元となるテンプレートを修正します。
3. リネームか生識別子の選択
長期的な明瞭性を高めるために、内部の関数、ローカル変数、モジュールはリネームします。公開API、シリアライズ名、またはクレート間呼び出しでgenを維持する必要がある場合、生識別子を使用することで必要なエディションでシンボルを参照可能な状態に保ちます。これを移行の架け橋として扱い、分かりにくい内部名を永久に残す口実にしないでください。
pub fn r#gen() -> IteratorType {
// implementation
}
fn call() {
let _items = r#gen();
}4. レビューを伴う修正の自動化
cargo fix --editionは該当するリントを警告に引き上げ、genをr#genに変更するなどのコンパイラの提案を適用します。これは製品の命名やAPIポリシーを判断することはできず、コミットされていない作業を上書きすべきではありません。クリーンなブランチで実行し、マクロ、doctest、生成コード、公開APIの差分をレビューした上で、マニフェストのエディションを手動で更新します。
5. エディション境界の検証
異なるエディションのクレート同士はリンク可能であるため、ワークスペースのクレートを段階的に移行します。CIでは、2021および2024向けにcargo check、cargo test、cargo doc、clippy、およびfeatureの組み合わせを実行する必要があります。生識別子やリネームによって呼び出し側にリグレッションが生じないよう、公開API用のコンパイル時サンプルを追加します。
6. 観測、バッチ処理、およびロールバック
リントの検出、エディション、ツールチェーン、クレート、feature、マクロのソース、失敗したテストを記録します。認証情報や機密入力は絶対にログに記録しないでください。広く依存されているクレートよりも先にリーフクレートを移行します。バッチごとに古いタグ、ロックファイル、再現可能なビルドを保持します。ダウンストリームが壊れた場合は、部分的な修正を手動で混在させるのではなく、そのバッチをリバートします。
模範解答例
「エディションはパース規則を変更しますが、コンパイラのアップグレードは別の変数であるため、ツールチェーンを固定してRust 2021のベースラインを確立します。keyword_idents_2024を有効にし、genを生成するソース、マクロ、proc macro、ビルドスクリプト、テストを洗い出します。内部シンボルはリネームし、名前の維持が必要な公開APIにはr#genを使用し、シリアライズとクレート間呼び出しをテストします。cargo fix --editionを実行して差分をレビューし、マニフェストを更新して、2021、2024、およびfeatureの組み合わせでcheck、test、docs、clippyを実行します。クレートは依存関係順に切り替え、リントと失敗のテレメトリ、および再現可能なロールバックポイントを確保します。」
よくあるミス
- コンパイラのみをアップグレードする → エディションのパースが検証されていない → ベースラインを固定し、エディションの切り替えを個別に実施する。
- ソースファイルのみをgrepする → マクロや生成コードが依然として
genを出力する → トークン生成元でリントを適用し、展開結果をテストする。 - すべての名前をr#genに変更する → 長期的なAPIの可読性が低下する → 内部はリネームし、生識別子は互換性の境界にのみ限定する。
- レビューなしでcargo fixを受け入れる → 公開APIやドキュメントが破損する可能性がある → すべての差分をレビューし、クロスエディションのCIを実行する。
- ワークスペース全体を一度に切り替える → ダウンストリームのリグレッション箇所の特定が困難になる → ロールバックポイントを設けて依存関係のトポロジー順に移行する。
フォローアップの質問と回答
Rust 2024ではすでにgenブロックを使用できますか?
genは将来のgenブロックのための構文スペースを残すために予約されました。移行にあたってはその機能が安定していると仮定してはなりません。現在のツールチェーンのドキュメントと機能ステータスを確認してください。
生識別子はABIやシリアライズ名を変更しますか?
生識別子は主にパーサーが名前をどう読み取るかを変更します。ABI、リフレクション、シリアライズ、FFIが変更されるかどうかは実際の公開シンボルと生成ツールに依存するため、それらの境界を検証してください。明示的な通信用名前(wire name)と互換性テストにより外部プロトコルを保護してください。
cargo fixの後にCargo.tomlを手動で編集するのはなぜですか?
cargo fix --editionはコードレベルのリント提案を適用しますが、エディションフィールドには依然として慎重な確認とコミットが必要です。マニフェストの変更をテスト結果とともにレビューし、ワークスペースのクレートが誤って切り替えられたり省略されたりしないようにします。