命名
大文字・小文字の使い分けがRFC430に従っている (C-CASE)
Rustにおける基本的な命名規則はRFC 430に記述されています。
Rustは「型レベル」のもの(型やトレイト)にCamelCase
、
「値レベル」のものにsnake_case
を使用する傾向があります。
正確には、次表のように命名します。
アイテム | 規則 |
---|---|
クレート | 不明 |
モジュール | snake_case |
型 | CamelCase |
トレイト | CamelCase |
Enumのバリアント | CamelCase |
関数 | snake_case |
メソッド | snake_case |
一般のコンストラクタ | new または with_more_details |
変換を行うコンストラクタ | from_some_other_type |
マクロ | snake_case! |
ローカル変数 | snake_case |
スタティック変数 | SCREAMING_SNAKE_CASE |
定数 | SCREAMING_SNAKE_CASE |
型パラメータ | 簡潔なCamelCase 、大抵は大文字で1文字: T |
ライフタイム | 短いlowercase 、大抵は1文字: 'a , 'de , 'src |
Feature | 不明、ただしC-FEATUREを参照 |
頭字語や複合語は、CamelCase
では一語に数えます。例えばUUID
ではなくUuid
を使い、USize
ではなくUsize
、StdIn
ではなくStdin
を使って下さい。
snake_case
ではis_xid_start
のように小文字にします。
snake_case
またはSCREAMING_SNAKE_CASE
では、
それが最後の文字を除いて一文字で区切ってはいけません。
例えば、b_tree_map
ではなくbtree_map
としますが、PI2
ではなくPI_2
とします。
クレート名の前後に-rs
や-rust
を付けるべきではありません。
全てのクレートがRust製であることは分かりきっています!
そのことをユーザに常に知らせ続ける必要はありません。
(訳注: レポジトリ名等ではなく、Cargo.tomlで指定するクレート名についての指針です)
標準ライブラリでの例
この規則は標準ライブラリの全体に渡って使用されています。
変換メソッドにas_
, to_
, into_
を使っている (C-CONV)
変換メソッドの名前には次のプレフィクスを付けるべきです。
プレフィクス | コスト | 所有権 |
---|---|---|
as_ | 低い | 借用 -> 借用 |
to_ | 高い | 借用 -> 借用 借用 -> 所有 (Copyでない型) 所有 -> 所有 (Copy型) |
into_ | 可変 | 所有 -> 所有 (Copyでない型) |
以下に例を挙げます。
str::as_bytes()
はコストなしに、str
をUTF-8バイト列として見たビューを返します。 入力は借用された&str
で出力は借用された&[u8]
です。Path::to_str
はOSの与えるパスのバイト列に対し、コストの高いUTF-8チェックを行います。 入出力はともに借用されています。小さくない実行時コストがあるため、これをas_str
と呼ぶことはできません。str::to_lowercase()
はUnicode規格に沿ってstr
を小文字に変換したものを返します。 この処理は文字列のデコードを含み、またメモリの確保も行うでしょう。 入力は借用された&str
で出力は所有されたString
です。f64::to_radians()
は浮動小数点数で表された角度を度からラジアンに変換します。 入力はf64
です。これが&f64
でないのは、コピーに殆どコストが掛からないためです。 入力が消費されないので、このメソッドをinto_radians
と呼ぶのはミスリーディングです。String::into_bytes()
はString
がラップしているVec<u8>
を取り出します。 この処理にコストは掛かりません。このメソッドはString
の所有権を得て、所有されたVec<u8>
を返します。BufReader::into_inner()
はバッファリングされたreaderの所有権を得て、ラップされていたreaderを取り出します。 この処理にコストは掛かりません。バッファ内のデータは破棄されます。BufWriter::into_inner()
はバッファリングされたwriterの所有権を得て、ラップされていたwriterを取り出します。 この処理にはコストの掛かるバッファのフラッシングが必要なことがあります。
as_
やinto_
の付くような変換メソッドは一般に抽象を弱めます。
内部表現を公開したり(as
)、データを内部表現に分解したり(into
)することになるからです。
一方で、to_
と付くような変換メソッドは一般に抽象レベルを保てることが多いですが、
内部で何らかの処理を行いデータの表現方法を変換する必要があります。
ある値をラップして高レベルの意味を持たせるような型において、
ラップされた型にアクセスさせる手段はinto_inner()
メソッドによって提供されるべきです。
これは例えば、バッファリングを提供するBufReader
や、
エンコード・デコードを行うGzDecoder
、
アトミックなアクセスを提供するAtomicBool
といった型のようなセマンティクスを持つ型に適用できます。
変換メソッドの名前にmut
を含めるときは、返り値の型の記述と同じ順番にしてください。
例えばVec::as_mut_slice
はミュータブルは名前の通りスライスを返します。
例えばas_slice_mut
等よりもこのような命名が推奨されます。
# #![allow(unused_variables)] #fn main() { // Return type is a mut slice. fn as_mut_slice(&mut self) -> &mut [T]; #}
標準ライブラリでのさらなる例
Getterの名前がRustの規則に従っている (C-GETTER)
後述するような例外を除き、getterの名前をget_
で始めるべきではありません。
# #![allow(unused_variables)] #fn main() { pub struct S { first: First, second: Second, } impl S { // Not get_first. pub fn first(&self) -> &First { &self.first } // Not get_first_mut, get_mut_first, or mut_first. pub fn first_mut(&mut self) -> &mut First { &mut self.first } } #}
get
という命名は、getterによって得られるものが自明である場合にのみ使用されるべきです。
例えば、Cell::get
はCell
の中身を返します。
境界検査といった、実行時のバリデーションが必要なgetterには、
unsafeな_unchecked
版も用意できないか検討してください。
そのようなメソッドの宣言はふつう、以下のようになります。
# #![allow(unused_variables)] #fn main() { fn get(&self, index: K) -> Option<&V>; fn get_mut(&mut self, index: K) -> Option<&mut V>; unsafe fn get_unchecked(&self, index: K) -> &V; unsafe fn get_unchecked_mut(&mut self, index: K) -> &mut V; #}
getterと変換(C-CONV)の間の違いは往々にして微かなもので、
常に境界がハッキリしている訳ではありません。
例えばTempDir::path
は一時ディレクトリのファイルシステム上のパスのgetterとして捉えられますが、
TempDir::into_path
は一時ディレクトリを削除する責任を呼び出し側に移す変換メソッドです。
このような場合path
はgetterなので、get_path
やas_path
と呼ぶことは正しくありません。
標準ライブラリでのさらなる例
std::io::Cursor::get_mut
std::ptr::Unique::get_mut
std::sync::PoisonError::get_mut
std::sync::atomic::AtomicBool::get_mut
std::collections::hash_map::OccupiedEntry::get_mut
<[T]>::get_unchecked
イテレータを生成するメソッドの名前がiter
, iter_mut
, into_iter
となっている ([C-ITER])
RFC 199に従ってください。
U
という型の要素を持つコンテナの場合、イテレータを生成するメソッドは次のように命名するべきです。
# #![allow(unused_variables)] #fn main() { fn iter(&self) -> Iter // Iter implements Iterator<Item = &U> fn iter_mut(&mut self) -> IterMut // IterMut implements Iterator<Item = &mut U> fn into_iter(self) -> IntoIter // IntoIter implements Iterator<Item = U> #}
この指針は全ての要素が同質であると意味付けられたコレクションに対して適用されます。
例えばstr
はバイト列ですが、有効なUTF-8であるという保証があるため、この指針は適用できません。
従ってiter
/iter_mut
/into_iter
といったメソッド群ではなく、
バイト列としてイテレートするstr::bytes
、キャラクタ列としてイテレートするstr::chars
を持ちます。
このガイドラインはメソッドにのみ適用され、関数は対象外です。
例えばurl
クレートのpercent_encode
は文字列をパーセントエンコーディングしていくイテレータを返します。
この場合、iter
/iter_mut
/into_iter
といった命名を使うことに利点はありません。
標準ライブラリでの例
イテレータの型名が、それを生成するメソッドと揃っている (C-ITER-TY)
into_iter
というメソッドはIntoIter
という型を返すべきです。
他のイテレータを返すメソッドでも同様です。
この指針は主にメソッドに対して適用されますが、関数に対しても大抵は適用できます。
例えばurl
クレートのpercent_encode
関数はPercentEncode
という型名のイテレータを返します。
このような命名法はvec::IntoIter
のようにモジュール名を付けて呼ぶ際に最も有用です。
標準ライブラリでの例
Vec::iter
はIter
を返す。Vec::iter_mut
はIterMut
を返す。Vec::into_iter
はIntoIter
を返す。BTreeMap::keys
はKeys
を返す。BTreeMap::values
はValues
を返す。
Featureの名前に余計な単語が入っていない (C-FEATURE)
Cargoのfeatureの名前に意味のない単語を付けないでください。
use-abc
やwith-abc
などとせず、単にabc
とするべきです。
標準ライブラリへの依存がオプションである場合が最もよく目にする例でしょう。 これを指針に従って行うと、以下のようになります。
# In Cargo.toml
[features]
default = ["std"]
std = []
# #![allow(unused_variables)] #fn main() { // In lib.rs #![cfg_attr(not(feature = "std"), no_std)] #}
このfeatureにstd
以外の、use-std
やwith-std
あるいはその他の独創的な名前を付けないでください。
そうすることで、Cargoが暗黙的に追加するオプショナルな依存性のfeatureと沿った形になります。
例えばx
というクレートがSerdeと標準ライブラリに対する依存をオプションとして持つとき、
[package]
name = "x"
version = "0.1.0"
[features]
std = ["serde/std"]
[dependencies]
serde = { version = "1.0", optional = true }
のようになります。そして、さらにx
に依存するとき、Serdeへの依存を
features = ["serde"]
で有効化できます。
また、同じように標準ライブラリへの依存をfeatures = ["std"]
で有効化できます。
Cargoによって暗黙的に追加されるfeatureはserde
であり、use-serde
でもwith-serde
でもありません。
ですから、明示的なfeatureに対しても同じようにするべきなのです。
関連事項として、Cargoのfeatureは追加式ですから、
no-abc
といったfeatureは大きな間違いです。
命名時に単語を並べる順番が揃っている (C-WORD-ORDER)
標準ライブラリにおけるエラー型をいくつか示します。
JoinPathsError
ParseBoolError
ParseCharError
ParseFloatError
ParseIntError
RecvTimeoutError
StripPrefixError
全て、動詞-オブジェクト-エラーの順番で並んでいます。
もし新たにアドレスのパースに失敗したことを表すエラーを追加するならば、
AddrParseError
等ではなく、
一貫性を考えて動詞-オブジェクト-エラーの順に並べParseAddrError
とすべきです。
どの順番を選ぶかは大して重要ではありませんが、クレート内での一貫性、 標準ライブラリの似た機能との整合性には注意してください。