Rustはメモリ安全性や並行性を重視するシステムプログラミング言語であり、その一貫した設計思想はコードの記述スタイルにも強く反映されています。
開発者が効率的にコードを読み解き、共通の理解を持ってプロジェクトを進めるためには、Rustコミュニティが定めた標準的な命名規則に従うことが不可欠です。
本記事では、公式のスタイルガイドラインに基づいた基本的なルールから、可読性と保守性を最大化するための実践的なベストプラクティスまでを詳しく解説します。
Rustにおける命名規則の重要性と基本原則
Rustの命名規則は、単なる見た目の好みの問題ではなく、言語の設計思想や標準ライブラリとの親和性を保つために非常に重要な役割を担っています。
Rustコンパイラには、命名規則から外れた記述に対して警告を出す機能が標準で備わっており、開発者が自然と一貫性のあるスタイルを維持できるよう設計されています。
この一貫性は、標準ライブラリや外部のクレート(ライブラリ)を使用する際の学習コストを下げ、コードベース全体の見通しを良くすることに直結します。
Rustでは主に3種類のレターケース(文字の形式)を使い分けることで、その識別子が何を表しているのかを視覚的に判別できるようにしています。
具体的には、変数や関数にはsnake_caseを、型やトレイトにはUpperCamelCaseを、定数にはSCREAMING_SNAKE_CASEを使用することが基本となります。
これらのルールを遵守することで、コードの読み手は定義を確認することなく、そのシンボルがどのような性質を持つものかを即座に理解できるようになります。
公式ガイドラインに基づくケース規則の分類
Rustの公式なスタイルガイド(RFC 430)では、識別子の種類ごとに推奨されるケース規則が明確に定義されています。
まずは、どの要素にどの規則を適用すべきかを整理した以下の表を確認してください。
| 識別子の種類 | 適用されるケース規則 | 具体例 |
|---|---|---|
| クレート(Crate) | snake_case | serde_json |
| モジュール(Module) | snake_case | network_io |
| 関数(Function) / メソッド(Method) | snake_case | calculate_sum |
| 変数(Variable) / 引数(Argument) | snake_case | user_id |
| 構造体(Struct) / 列挙型(Enum) | UpperCamelCase | UserProfile |
| トレイト(Trait) | UpperCamelCase | AsyncRead |
| 型エイリアス(Type Alias) | UpperCamelCase | ResultList |
| 列挙型のバリアント(Enum Variant) | UpperCamelCase | ConnectionError |
| 定数(Constant) / 静的変数(Static) | SCREAMING_SNAKE_CASE | MAX_RETRY_COUNT |
snake_case (蛇形記法) の適用範囲と詳細
関数名、メソッド名、ローカル変数、およびモジュール名には、すべて小文字とアンダースコアを用いた snake_case を使用します。
これは、Rustのコードにおける動的なアクションや具体的なデータを表す要素を統一するためのルールです。
例えば、データを処理する関数を定義する場合、ProcessData ではなく process_data と記述するのが正解です。
また、ファイル名やディレクトリ名もモジュール名として扱われるため、基本的には snake_case で統一する必要があります。
以下のコード例で、正しい snake_case の適用方法を確認してみましょう。
// モジュール名の定義
mod user_manager {
// 変数名と関数名に snake_case を適用
pub fn fetch_active_users(retry_limit: u32) {
let current_count = 0;
// ... 実装 ...
}
}
UpperCamelCase (アッパーキャメルケース) の適用範囲
型に関連する要素、すなわち構造体、列挙型、トレイト、および列挙型のバリアントには、各単語の先頭を大文字にする UpperCamelCase を使用します。
これにより、コードの中で「型」そのものを指しているのか、それとも「変数の値」を指しているのかが明確に区別されます。
特に注意が必要なのは、頭字語(略語)の扱いです。
Rustでは HTTPServer ではなく HttpServer のように、略語であっても1つの単語として扱い、先頭のみを大文字にすることが推奨されています。
これは、複数の略語が連続した際に境界を判別しやすくするための工夫です。
// 構造体とトレイトに UpperCamelCase を適用
trait JsonConfig {
fn load_settings();
}
struct ApiClient {
endpoint_url: String,
}
enum ConnectionStatus {
Connected,
Disconnected,
}
SCREAMING_SNAKE_CASE (絶叫蛇形記法) の適用範囲
プログラムの実行中を通じて不変である定数(const)や静的変数(static)には、すべて大文字とアンダースコアを用いた SCREAMING_SNAKE_CASE を適用します。
これにより、その値がグローバルな定数であることを一目で認識でき、マジックナンバーの回避にも役立ちます。
定数名は、その値の意味を明確に示す名詞にするのが一般的です。
// 定数と静的変数に SCREAMING_SNAKE_CASE を適用
const DEFAULT_TIMEOUT_SECONDS: u64 = 30;
static GLOBAL_COUNTER: i32 = 0;
型変換とメソッド命名のベストプラクティス
Rustの標準ライブラリでは、データの所有権や参照の扱いに基づいて、メソッドの命名に特定のパターンを採用しています。
これらのパターンに従うことで、そのメソッドが呼び出し元にどのような影響を与えるのかを直感的に伝えることができます。
as_, to_, into_ の使い分け
データの型を変換したり、特定のビューを取得したりするメソッドには、以下の接頭辞を使い分けるルールがあります。
as_ 接頭辞は、コストがほとんどかからない参照から参照への変換に使用されます。
例えば、as_str() や as_bytes() は、所有権を移動させずに中身を特定の型として参照する場合に用いられます。
to_ 接頭辞は、新しいデータを生成(コピーやクローン)するコストのかかる変換に使用されます。
to_string() や to_vec() など、変換後の値を新しくメモリ上に確保する場合に適しています。
into_ 接頭辞は、所有権を消費(ムーブ)して別の型に変換する場合に使用されます。
この接頭辞がついたメソッドを呼び出すと、元の変数は使用できなくなることを示唆します。
struct RawData(Vec<u8>);
impl RawData {
// 参照を返す (低コスト)
fn as_slice(&self) -> &[u8] {
&self.0
}
// 新しい所有権を持つデータを生成 (高コスト)
fn to_hex_string(&self) -> String {
// ... 実装 ...
String::from("deadbeef")
}
// 所有権を消費して変換 (ムーブ)
fn into_inner(self) -> Vec<u8> {
self.0
}
}
GetterとSetterの命名ルール
他の言語で見られる get_field_name という命名は、Rustではあまり好まれません。
Rustの慣習では、Getterメソッドには単にフィールド名を使用します。
一方で、Setterメソッドには set_field_name という形式を使用することが一般的です。
これにより、データの取得がより自然な関数呼び出しとして記述でき、コードが簡潔になります。
struct User {
username: String,
}
impl User {
// Getter: get_username ではなく username と命名
fn username(&self) -> &str {
&self.username
}
// Setter: set_username と命名
fn set_username(&mut self, name: String) {
self.username = name;
}
}
特殊なケースとアンダースコアの活用
Rustではアンダースコア _ に特別な意味を持たせる命名ルールが存在します。
最も一般的なのは、使用しない変数や引数の名前をアンダースコアで始めるというルールです。
Rustコンパイラはデフォルトで使用されていない変数を検知して警告を出しますが、名前を _unused_var のように記述することで、意図的に使用していないことをコンパイラと他の開発者に伝えることができます。
また、完全なアンダースコア単体 _ は、パターンマッチングなどで値を完全に無視(破棄)する場合に使用されます。
トレイトのメソッド実装において、引数が必要だが中身を使わない場合などに非常に有用です。
fn process_event(event_id: u32, _payload: String) {
// payload は使わないが、インターフェース上必要な場合にアンダースコアを付ける
println!("Processing event: {}", event_id);
}
fn main() {
// 未使用変数の警告を抑制
let _unused_connection = "connected";
}
クレートとモジュールの命名における注意点
ライブラリを公開したり、大規模なプロジェクトを構築したりする際、クレート名やモジュール名の付け方には特に注意が必要です。
クレート名は、その機能が何であるかを端的に表す名詞、またはプロジェクトのブランド名にすることが推奨されます。
モジュール名は、内部に保持する型や関数と名前が重複しないように工夫するのがコツです。
例えば、user モジュールの中に User 構造体を配置するのは一般的ですが、user_manager モジュールの中に UserManager という構造体を作るのは、呼び出し側で user_manager::UserManager と冗長になるため避けるべきです。
この場合、user_manager モジュールの中には単に Manager という名前で構造体を定義し、外部からは user_manager::Manager として利用させるのがスマートな設計です。
RustfmtとClippyによる自動チェック
命名規則を手動ですべて覚えるのは大変ですが、Rustにはこれらを自動でチェック・修正してくれる強力なツール群が存在します。
rustfmt はコードの整形を行うツールであり、インデントやスペースだけでなく、基本的なスタイルの統一に役立ちます。
さらに強力なのが clippy です。
ClippyはRustのリンターであり、命名規則違反(例えば UpperCamelCase であるべき場所に snake_case を使っている場合など)を検知し、適切な修正案を提示してくれます。
開発ワークフローの初期段階で cargo clippy を実行する習慣をつけることで、自然とコミュニティ標準に準拠した美しいコードを書くことができるようになります。
warning: method `GetID` should have a snake case name
--> src/main.rs:10:8
|
10 | fn GetID(&self) {}
| ^^^^^ help: convert the identifier to snake case: `get_id`
|
= note: `#[warn(non_snake_case)]` on by default
上記のように、Clippyは具体的な修正案を提示してくれるため、迷った際はツールの指示に従うのが最も確実な道と言えます。
まとめ
Rustの命名規則は、言語の安全性や表現力と深く結びついており、一貫性のあるコードを維持するための基盤となっています。
基本的な snake_case、UpperCamelCase、SCREAMING_SNAKE_CASE の使い分けをマスターすることは、Rustプログラミングにおける第一歩です。
また、as_、to_、into_ などの接頭辞を正しく使い分けることで、所有権の動きを明確にし、バグの少ない堅牢なプログラムを構築できるようになります。
まずは公式のガイドラインを意識しつつ、Clippyなどのツールを活用しながら、読みやすく美しいRustコードを目指していきましょう。
これらの習慣を身につけることは、あなた自身だけでなく、あなたのコードを読む世界中の開発者にとっても大きな利益となります。
