メむンコンテンツたでスキップ
最新10d ago

🊀 Google Rust スタむルガむド: 重芁なポむント

Tip: TL;DR: 可読性 > 曞きやすさ。rustfmt + パブリック Rust 芏玄に埓う。魔法マクロ、グロブ、Rc、unsafe、unwrapを避ける。所有暩、゚ラヌ、型に぀いお明瀺的に。


🧭 Step 0: 基本ルヌルを理解する​

すべおのルヌルの背景にある目暙

目暙意味
📖 可読性を優先コヌドは長く存圚する。曞く際にもう少し努力をかける
🀖 自動化に察応䞀貫したコヌドは倧芏暡リファクタリングLSCsを容易にする
🌍 ゚コシステムに合わせる公匏 Rust スタむルガむド + Rust API ガむドラむンに埓うこのガむドず矛盟しない限り
⚖ ルヌルは重みを持぀必芁がある実際の効果があるルヌルのみ
🛑 自転車眮き堎問題を終わらせるよくある意芋の盞違を䞀床解決する

ラむブラリコヌド vs アプリケヌションコヌド

ラむブラリコヌドアプリケヌションコヌド
䜿甚者他のプロゞェクト1぀のアプリ
API 蚭蚈ルヌル拘束力がある匷い掚奚
考え方柔軟、汎甚、再利甚可胜シンプル、盎接的、過床な抜象化なし

📁 Step 1: コヌドを敎理する​

  • 小さなクレヌトを優先Chromium: 理想的には 1 ぀のファむル、1 ぀の抜象。サブモゞュヌルを远加する前に分割する。

  • フラットなファむルレむアりトChromium: 1 ぀のクレヌトの .rs ファむルは 1 ぀のディレクトリに存圚する。サブディレクトリが必芁 = クレヌトが倧きすぎる。

  • ファむル名を䞻芁項目の埌に付ける: struct Foo → foo.rs / mod foo。

  • リヌフでないモゞュヌルは mod 宣蚀ず再゚クスポヌトのみを保持し、実装は含たない少しのグルヌコヌドは OK。リヌフモゞュヌルは mod test ずバむンディングモゞュヌル䟋: #[cxx::bridge]を含むこずができる。

  • ルヌトモゞュヌルはリヌフサブモゞュヌルからパブリック API を再゚クスポヌトできるため、サブモゞュヌルは実装詳现のたたになる。

  • API が同じクレヌトに属するかどうかを最初に決定し、その埌でサブモゞュヌルを怜蚎する。

  • トレむト実装の䞀貫性ルヌルが型ずトレむトを䞀緒に匷制する堎合、たたは倧芏暡な基瀎ラむブラリの堎合、倧きなクレヌトは問題ない。

  • 䟋倖: Cargo でも構築される //third_party コヌドは通垞の Cargo ディレクトリレむアりトを保぀。


📊 Step 2: むンポヌトを正しく曞く​

❌ グロブむンポヌトなし​

蚱可される䟋倖のみ:

  • use super::* むンラむンモゞュヌル内䟋: mod test

  • use MyEnum::* その゚ナムを䞻に扱う関数内

  • pub use submodule::* リヌフでないモゞュヌル内

  • C++ 名前空間を 1 ぀のモゞュヌルにマヌゞマヌゞされたモゞュヌルは公開されおいない必芁がある

  • サヌドパヌティプリルヌドレビュアヌの刀断。独自のプリルヌドを定矩しないでください。

✅ use ステヌトメントごずに 1 ぀のモゞュヌル​

rustfmt 蚭定 imports_granularity = Module に合臎{} 内に ::なし:

// ✅ Good
use foo::Foo;
use foo::bar::{Bar, Baz};

// ❌ Bad
use foo::{Foo, bar::Bar};

✅ トレむトをロヌカルでむンポヌト​

トレむトのメ゜ッドが ファむル党䜓で広く䜿甚されおいる堎合を陀く。

fn foo(s: &str) -> Result<u8, std::num::ParseIntError> {
use std::str::FromStr; // 䜿甚されおいる堎所にスコヌプされおいる
u8::from_str(s)
}

✅ 関数: モゞュヌル名で修食​

// ✅ Good
use std::mem;
let x = mem::transmute(y);

// ❌ Bad
use std::mem::transmute;
let x = transmute(y);

䟋倖: 明確に区別される名前䟋: C++ フリヌ関数、小さな単䞀目的のファヌストパヌティクレヌトChromium、衝突しやすいモゞュヌル名䟋: C++ 名前空間名。

✅ 型: むンポヌトしお非修食で䜿甚​

regex::Regex ではなく Regex ず曞く。䟋倖: あいたいな名前io::Error たたは use std::io::Error as IoError、倧芏暡な型グルヌプ䟋: rustc の hir、マクロ/生成コヌド、倚くの䟝存関係があるため import ブロックが巚倧になるコヌド。

Chromium のみ​

chromium::import!() をむンポヌト機構ずしお䜿甚しおください。


🎚 Step 3: フォヌマット​

  • フォヌマッタヌを実行rustfmt / git cl format。フォヌマットに぀いお手動で議論しないでください。

  • 掚奚される rustfmt オプションコヌドベヌスは安定版 Rust で利甚できないものをスキップできたす:

max_width = 100
hex_literal_case = "Lower" # 0xab12, not 0xAB12
format_macro_matchers = true
imports_granularity = "Module"

  • リテラル内の目に芋えない文字を゚スケヌプ: \u{200D}。

  • #[rustfmt::skip] のみ 意図的な手動配眮䟋: 行列たたは生成されたコヌド甚。個人的な奜みには決しお䜿わないでください。


🔐 Step 4: 所有暩ず借甚​

ルヌル詳现
Rc / Arc を避ける単䞀所有暩 + 借甚を優先。代替案が非垞に耇雑な堎合のみ䜿甚。
.clone() より借甚を優先深いコピヌが本圓に必芁な堎合のみクロヌンする。Rc/Arc のクロヌンは問題ない安䟡なポむンタコピヌ。

🔌 Step 5: 関数入力ず出力​

最も柔軟な参照を受け入れる​

✅ 䜿甚❌ 代わりに
&T&Box<T>
&[T]&Vec<T>
&str&String
Option<&T>&Option<T>

䟋倖: Rope/Cord のような非線圢文字デヌタ。関連する Clippy リント: borrowed_box、ptr_arg。

むテレヌタ vs コレクション​

状況ラむブラリアプリケヌション
戻り倀impl Iterator を優先より単玔な堎合は Vec<T> で問題ない
パラメヌタimpl IntoIterator を受け入れるより単玔な堎合は &[T] で問題ない

次の堎合は Vec を返す: ほずんどの呌び出し元が Vec を必芁ずする、実装が自然に 1 ぀を構築する、結果がランダムアクセスを必芁ずする、for ルヌプがより適切で割り圓おが問題でない、関数の目的がコレクションを䜜成するこずである、たたは既存のベクトルを返す。

その他の入力ルヌル​

  • impl Into<T> パラメヌタ: ラむブラリのみ、呌び出しサむトの䜿いやすさが本圓に重芁な堎合。コヌドブロヌト、耇雑な眲名、掚論の問題に察しおバランスを取る。アプリケヌションコヌド: ほが決しおない。

  • 意味が明確でない堎合、bool より enum を優先する。bool を保持する堎合、呌び出しサむトでコメント:

connect(addr, /* retry= */ true);


🚚 Step 6: ゚ラヌを正しく報告する​

メカニズム時期䟋
Option明癜で予期される倱敗。詳现は䞍芁checked_add() -> Option<u32>
Result回埩可胜な倖郚゚ラヌ。呌び出し元は 理由 を知る必芁があるopen_file() -> Result<File, io::Error>
panic!バグ / 違反した䞍倉条件: コヌドを修正し、実行時に凊理しないむンデックス範囲倖

パニックからの粗粒床の回埩は catch_unwind で可胜Step 14 の制限を参照。䟋倖: 開発甚バむナリずテストはパニックできる。䞀郚のコヌドベヌスはパニックを完党に犁止し、砎損した䞍倉条件でも Result を䜿甚。


🧱 Step 7: 型​

Newtype vs 型゚むリアス。 次の堎合に newtype を䜿甚:

  • セマンティクスが基瀎ずなる型ず異なる

  • 型が独自の API を必芁ずする

  • 埌で基瀎ずなる型を倉曎する可胜性がある

  • 型が混同しやすい䟋: Day、Month、Year

タプルより名前付きフィヌルド:

// ✅ Good
struct Point { x: f64, y: f64 }

// ❌ Avoid (except one-field newtypes or very local use)
let p = (1.0, 2.0); p.0; p.1;


🧩 Step 8: トレむト​

トレむトを定矩する時期​

のみ:

  1. ゞェネリック境界T: Trait

  2. impl Trait / dyn Trait

  3. 拡匵トレむト それ以倖 → 固有の impl。コヌドの敎理にトレむトを䜿甚しないでください。

䞀般的なトレむトルヌル​

  • ラむブラリコヌド: impl をプロアクティブに远加。アプリケヌションコヌド: 必芁な堎合に远加。

  • カスタムメ゜ッドの代わりに std トレむトを実装fn from_str ではなく impl FromStr。メ゜ッドずトレむト impl の䞡方を保持するこずは芋぀けやすさのため問題ないClippy: should_implement_trait。

  • 可胜な限り #[derive(...)] を䜿甚。

  • ラむブラリ: dyn Trait より ゞェネリクスを優先ファットポむンタやvtable怜玢なし、むンラむン可胜。コヌドサむズが問題でない限り。泚意: 䞀郚のトレむトは dyn 互換ではないゞェネリックメ゜ッド、self のない関連関数、Self を返すメ゜ッド。

拡匵トレむト​

  • サフィックス Ext → ForeignTypeExt

  • 型を所有するチヌムが拡匵を所有するメ゜ッド名の衝突を回避。

  • 䟋倖: 基瀎ラむブラリ/フレヌムワヌクで広く有甚な拡匵。

  • 入力トレむト䟋: 倚くの倖郚型で実装される DateLikeず混同されないこず。入力トレむトは問題ない。

  • ブランケット実装も可胜: impl<T: ForeignTrait> ForeignTraitExt for T。

トレむトチヌトシヌト​

トレむトガむダンス
CopyCopy のたたであるこずが明確な堎合に実装。゚ラヌ型: 可胜な限り Copy。
Cloneほずんどの型倖郚リ゜ヌスを衚す型は陀く
Defaultnew() がある、たたはデフォルト状態がある堎合
PartialEq / PartialOrd== / < には これらを優先。Eq / Ord は反射性/党順序を保蚌する堎合のみ远加。
Hash + Eqマップキヌやキャッシュキヌずしお䜿甚される可胜性がある堎合。明確な党順序がある堎合は Ord も远加。
パブリックフィヌルドのある型すべおのサブフィヌルドが実装するトレむトの実装を怜蚎
From䞻なコンストラクタの堎合、new() / from_foo() も远加
オプション構造䜓Default を実装 → ..Default::default() を有効にする

🧵 Step 9: 䞊行性​

  • 決しおポむズンされたミュヌテックスに手を出さない。

  • Chromium: async/.await なし、std::thread なしシヌケンスを䜿甚。

  • Fuchsia: fuchsia_sync::Mutex を䜿甚。


🪄 Step 10: マクロ最埌の手段​

優先順䜍:

  1. プレヌン関数、型、トレむト、モゞュヌル ✅

  2. macro_rules!

  3. その他のコヌド生成䟋: genrule

  4. proc_macro ⚠ 理由: マクロは IDE サポヌトを損なわせ、ミニ蚀語を䜜成し、LSCs を難しくする。コヌド生成が必芁な堎合、macro_rules! は AST で動䜜するため、テキスト生成より脆匱性が䜎い。


🏷 Step 11: 呜名​

項目芏玄
倉換as_..() 安䟡な借甚、to_..() 高䟡、into_..() self を消費
コンストラクタnew()、new_with_foo()、Result を返す堎合は try_new()
倀の倉換from_foo() + マッチング From impl
拡匵トレむトFooExt
ラむフタむム説明的な名前。'a は単玔な入力→出力リンクたたはロヌカル for<'a> 境界で OK最倧 2。'_ は問題ない。Cow のようなゞェネリック抜象化は免陀。
ゞェネリクス短く、意味のある䞻なトレむト境界から。T/U は非境界ゞェネリクス甚。
省略圢䞀般的な堎合Wikipedia 䞊たたは プロゞェクト倖で明確な堎合を陀く避ける䟋: IpAddr。単語内の文字を削陀しない。

ゲッタヌ & セッタヌ​

メ゜ッド目的
foo()&T を返すたたは Copy の堎合は T。get_ プレフィックスなし。
foo_mut()&mut T を返す
set_foo(v)倀を蚭定
take_foo()デフォルト/None をクリア、叀い倀を返す
replace_foo(v)倀を蚭定、叀い倀を返す
with_foo(|f| ..) / with_mut_foo(|f| ..)クロヌゞャアクセス。Mutex/RefCellガヌドをリヌクさせないやガヌドが倉曎埌の怜蚌を必芁ずする堎合に最適。クロヌゞャの戻り倀は返される。アクセサが 1 ぀だけの堎合、with_foo も倉曎できる。

📝 Step 12: ドキュメント​

  • すべおのパブリック API をドキュメント化missing_docs リントを䜿甚。

  • /// は項目、//! はモゞュヌル/クレヌトファむルの先頭、// は実装ノヌトず TODO。混ぜるこずが掚奚。

  • Markdown、倧文字化、句読点を䜿甚。

  • 垞にパニックケヌスをドキュメント化する及び unsafe 䞍倉条件。

  • どこかのクレヌトに䟋を含めるすべおの関数に必芁なわけではない。

  • 蚀語の基本を説明しない䟋: テスト甚モック実装に関する「トレむトのモック実装」。

  • 自明な゚ナム倉皮のドキュメントは省略可胜。

  • マクロから生成されるのではなく、/// / //! で盎接ドキュメント化。

  • 明癜なこずを蚀い盎さない:

// ❌ 無意味省略しお lint を蚱可する方が良い
/// 芁玠を削陀したす。
pub fn remove_element() -> Element {}

// ✅ 有甚: パブリック doc + プラむベヌトノヌト
/// 䞎えられた `name` を持぀最初の `FooItem` を芋぀けるか、存圚しない堎合は `None`。
// TODO: crbug.com/12345 - `name` は String ではなく &str にすべき。
pub fn get_named(items: &[FooItem], name: String) -> Option<&FooItem> { .. }


⚙ Step 13: その他の蚀語機胜​

トピックルヌル
unsafe安党な代替案がない堎合のみ。安党な抜象に分離し、// SAFETY: コメントを远加し、正圓化するパフォヌマンスの堎合はベンチマヌクで。
䞍安定な機胜䜿甚しないこず。䟋倖: Android 組み蟌みニヌズレビュヌ枈み、Chrome 承認リスト、Fuchsia の独自ガむダンス
len()is_empty() も実装
#[doc(hidden)]所有しおいない堎合はプラむベヌトずしお扱う
const fnconst のたたにされる堎合のみ削陀すれば砎壊的倉曎
オペレヌタオヌバヌロヌド実際の数孊/論理的意味がある堎合のみ。構文シュガヌではない。
パブリック゚ナム他のチヌムが䜿甚#[non_exhaustive] セットが固定䟋: Color、二状態゚ナムたたはLSC による砎壊修正をコミット。皀に䜿甚される゚ナムはスキップ可胜。
パブリック構造䜓pub フィヌルド付き#[non_exhaustive] フィヌルドが倉曎されない、LSC 修正をコミット、たたは ..Default::default() が必芁な堎合を陀く
#[must_use]玔粋関数䟋: HashMap::get、重芁な情報を返す関数、゚ラヌ / 遅延型。戻り型が既に #[must_use]䟋: Resultの堎合は䞍芁。
main() 前のコヌド決しおない䟋: ctor クレヌト

🛠 Step 14: 実装習慣​

掚論が隠すずころに明瀺的な型を远加​

特に .into() の埌、.parse() ず耇雑なむテレヌタチェヌン。タヌボフィッシュより倉数の泚釈を優先:

let port: u16 = s.parse()?;

コンパむラがタヌボフィッシュを匷制する堎合、_ マヌカヌは問題ない: collect::<Vec<_>>()。

チェック→アンラップの代わりにパタヌンマッチ​

// ✅ Good
if let Some(value) = option {
use_value(value);
}

// ❌ Bad
if option.is_some() {
use_value(option.unwrap());
}

unwrap より expect​

䞍倉条件がなぜ成立するかドキュメント: .expect("config loaded at startup")。

#[non_exhaustive] ゚ナムのマッチング​

既知の倉皮を明瀺的に列挙し、その埌 _:

match shape {
Shape::Circle => println!("circle"),
Shape::Square => println!("square"),
Shape::Triangle | _ => {}
}

// ✅ 1 ぀の倉皮のみ気にする → if let
if let Shape::Circle = shape { println!("circle"); }

// ❌ 倉皮を _ の埌ろに隠す
match shape {
Shape::Circle => println!("circle"),
_ => {}
}

䟋倖: 䞀郚の倉皮のみ気にし、if let より match がより読みやすい堎合は問題ない。

アサヌションにコンテキストを䞎える​

// ✅ なぜかを説明
assert!(values.is_sorted(), "`values` は PriorityQueue から来おいるため、゜ヌト枈みであるべき");
assert!(refund > 0, "払い戻しは正数である必芁があり、{refund:?} を埗た");
assert!(self.stream.is_some(), "ク゚リを実行する前に connect() を呌び出す");

// ❌ 条件を繰り返すだけ
assert!(values.is_sorted(), "values は垞に゜ヌト枈みであるべき");

むテレヌタチェヌン vs for ルヌプ​

  • ✅ 短く、ロゞック重芖の組み合わせ: values.iter().any(|&v| v > threshold)

  • ❌ 条件や倖郚倉曎を䌎う長いチェヌン → for ルヌプを䜿甚

  • ❌ for ヘッダヌ内のチェヌン → 最初に名前付き倉数に割り圓おる

  • ❌ for_each → 通垞は for ルヌプの方が読みやすい

let urgent_bugs = bug_descriptions
.iter()
.filter_map(|d| parse_bug_description(d).ok())
.filter(|bug| bug.priority <= Priority::P1);

for bug in urgent_bugs {
assign_bug(bug);
}

その他の習慣​

  • panic::catch_unwind なし。防守的な深さずしおのみ蚱可され、コヌドは䜕にも䟝存しない、か぀コヌドが panic=unwind で実行される堎所でのみChrome、Android、Fuchsia は panic=abort を䜿甚。

  • 文字列: a + b + c の代わりに format!("{a}{b}{c}") 割り圓おが少ないたたは str::replace テンプレヌト。独自のテンプレヌト構文を発明しないこず。

  • テスト: コヌドベヌスのフレヌムワヌクを䜿甚Chrome: rust_gtest_interop、Fuchsia: #[fuchsia::test]。


✅ クむックレビュヌチェックリスト​

  • rustfmt 実行枈み、グロブむンポヌトなし、use ごずに 1 ぀のモゞュヌル

  • 関数は module::func() ずしお呌び出し、型は非修食で䜿甚

  • 䞍芁な Rc/Arc/.clone() なし

  • パラメヌタは &str、&[T]、&T、Option<&T> を䜿甚

  • 䞍明確な bool パラメヌタの代わりに enum を䜿甚

  • 正しい゚ラヌ型: Option / Result / panic!

  • タプルより名前付きフィヌルド、意味が異なる堎合は newtype

  • トレむトはゞェネリクス / dyn / 拡匵のみ; #[derive] を䜿甚

  • ゲッタヌは get_ なし、コンストラクタは new / try_new

  • パブリック API をドキュメント化、パニックず unsafe を説明

  • unwrap の代わりに if let / match; 理由付きで expect を䜿甚

  • アサヌションはコンテキストメッセヌゞを含む

  • 読みやすいむテレヌタチェヌン、文字列構築は format! を䜿甚

  • unsafe、䞍安定な機胜、たたはマクロは匷力な正圓化なしなし

Related Articles