Movatterモバイル変換


[0]ホーム

URL:


Rust API Guidelines

    Naming

    Casing conforms to RFC 430 (C-CASE)

    Basic Rust naming conventions are described inRFC 430.

    In general, Rust tends to useUpperCamelCase for "type-level" constructs (types andtraits) andsnake_case for "value-level" constructs. More precisely:

    ItemConvention
    Cratesunclear
    Modulessnake_case
    TypesUpperCamelCase
    TraitsUpperCamelCase
    Enum variantsUpperCamelCase
    Functionssnake_case
    Methodssnake_case
    General constructorsnew orwith_more_details
    Conversion constructorsfrom_some_other_type
    Macrossnake_case!
    Local variablessnake_case
    StaticsSCREAMING_SNAKE_CASE
    ConstantsSCREAMING_SNAKE_CASE
    Type parametersconciseUpperCamelCase, usually single uppercase letter:T
    Lifetimesshortlowercase, usually a single letter:'a,'de,'src
    Featuresunclear but seeC-FEATURE

    InUpperCamelCase, acronyms and contractions of compound words count as one word: useUuid rather thanUUID,Usize rather thanUSize orStdin rather thanStdIn. Insnake_case, acronyms and contractions are lower-cased:is_xid_start.

    Insnake_case orSCREAMING_SNAKE_CASE, a "word" should never consist of asingle letter unless it is the last "word". So, we havebtree_map rather thanb_tree_map, butPI_2 rather thanPI2.

    Crate names should not use-rs or-rust as a suffix or prefix. Every crateis Rust! It serves no purpose to remind users of this constantly.

    Examples from the standard library

    The whole standard library. This guideline should be easy!

    Ad-hoc conversions followas_,to_,into_ conventions (C-CONV)

    Conversions should be provided as methods, with names prefixed as follows:

    PrefixCostOwnership
    as_Freeborrowed -> borrowed
    to_Expensiveborrowed -> borrowed
    borrowed -> owned (non-Copy types)
    owned -> owned (Copy types)
    into_Variableowned -> owned (non-Copy types)

    For example:

    • str::as_bytes() gives a view of astr as a slice of UTF-8 bytes, whichis free. The input is a borrowed&str and the output is a borrowed&[u8].
    • Path::to_str performs an expensive UTF-8 check on the bytes of anoperating system path. The input and output are both borrowed. It would not becorrect to call thisas_str because this method has nontrivial cost atruntime.
    • str::to_lowercase() produces the Unicode-correct lowercase equivalent of astr, which involves iterating through characters of the string and mayrequire memory allocation. The input is a borrowed&str and the output is anownedString.
    • f64::to_radians() converts a floating point quantity from degrees toradians. The input isf64. Passing a reference&f64 is not warrantedbecausef64 is cheap to copy. Calling the functioninto_radians would bemisleading because the input is not consumed.
    • String::into_bytes() extracts the underlyingVec<u8> of aString,which is free. It takes ownership of aString and returns an ownedVec<u8>.
    • BufReader::into_inner() takes ownership of a buffered reader and extractsout the underlying reader, which is free. Data in the buffer is discarded.
    • BufWriter::into_inner() takes ownership of a buffered writer and extractsout the underlying writer, which requires a potentially expensive flush of anybuffered data.

    Conversions prefixedas_ andinto_ typicallydecrease abstraction, eitherexposing a view into the underlying representation (as) or deconstructing datainto its underlying representation (into). Conversions prefixedto_, on theother hand, typically stay at the same level of abstraction but do some work tochange from one representation to another.

    When a type wraps a single value to associate it with higher-level semantics,access to the wrapped value should be provided by aninto_inner() method. Thisapplies to wrappers that provide buffering likeBufReader, encoding ordecoding likeGzDecoder, atomic access likeAtomicBool, or any similarsemantics.

    If themut qualifier in the name of a conversion method constitutes part ofthe return type, it should appear as it would appear in the type. For exampleVec::as_mut_slice returns a mut slice; it does what it says. This name ispreferred overas_slice_mut.

    #![allow(unused)]fn main() {// Return type is a mut slice.fn as_mut_slice(&mut self) -> &mut [T];}
    More examples from the standard library

    Getter names follow Rust convention (C-GETTER)

    With a few exceptions, theget_ prefix is not used for getters in Rust code.

    #![allow(unused)]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    }}}

    Theget naming is used only when there is a single and obvious thing thatcould reasonably be gotten by a getter. For exampleCell::get accesses thecontent of aCell.

    For getters that do runtime validation such as bounds checking, consider addingunsafe_unchecked variants. Typically those will have the followingsignatures.

    #![allow(unused)]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;}

    The difference between getters and conversions (C-CONV) can be subtleand is not always clear-cut. For exampleTempDir::path can be understood asa getter for the filesystem path of the temporary directory, whileTempDir::into_path is a conversion that transfers responsibility fordeleting the temporary directory to the caller. Sincepath is a getter, itwould not be correct to call itget_path oras_path.

    Examples from the standard library

    Methods on collections that produce iterators followiter,iter_mut,into_iter (C-ITER)

    PerRFC 199.

    For a container with elements of typeU, iterator methods should be named:

    #![allow(unused)]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>}

    This guideline applies to data structures that are conceptually homogeneouscollections. As a counterexample, thestr type is slice of bytes that areguaranteed to be valid UTF-8. This is conceptually more nuanced than ahomogeneous collection so rather than providing theiter/iter_mut/into_iter group of iterator methods, it providesstr::bytes to iterate as bytes andstr::chars to iterate as chars.

    This guideline applies to methods only, not functions. For examplepercent_encode from theurl crate returns an iterator over percent-encodedstring fragments. There would be no clarity to be had by using aniter/iter_mut/into_iter convention.

    Examples from the standard library

    Iterator type names match the methods that produce them (C-ITER-TY)

    A method calledinto_iter() should return a type calledIntoIter andsimilarly for all other methods that return iterators.

    This guideline applies chiefly to methods, but often makes sense for functionsas well. For example thepercent_encode function from theurl cratereturns an iterator type calledPercentEncode.

    These type names make the most sense when prefixed with their owning module, forexamplevec::IntoIter.

    Examples from the standard library

    Feature names are free of placeholder words (C-FEATURE)

    Do not include words in the name of aCargo feature that convey zero meaning,as inuse-abc orwith-abc. Name the featureabc directly.

    This arises most commonly for crates that have an optional dependency on theRust standard library. The canonical way to do this correctly is:

    # In Cargo.toml[features]default = ["std"]std = []
    #![allow(unused)]fn main() {// In lib.rs#![no_std]#[cfg(feature = "std")]extern crate std;}

    Do not call the featureuse-std orwith-std or any creative name that is notstd. This naming convention aligns with the naming of implicit featuresinferred by Cargo for optional dependencies. Consider cratex with optionaldependencies on Serde and on the Rust standard library:

    [package]name = "x"version = "0.1.0"[features]std = ["serde/std"][dependencies]serde = { version = "1.0", optional = true }

    When we depend onx, we can enable the optional Serde dependency withfeatures = ["serde"]. Similarly we can enable the optional standard librarydependency withfeatures = ["std"]. The implicit feature inferred by Cargo forthe optional dependency is calledserde, notuse-serde orwith-serde, sowe like for explicit features to behave the same way.

    As a related note, Cargo requires that features are additive so a feature namednegatively likeno-abc is practically never correct.

    Names use a consistent word order (C-WORD-ORDER)

    Here are some error types from the standard library:

    All of these use verb-object-error word order. If we were adding an error torepresent an address failing to parse, for consistency we would want to name itin verb-object-error order likeParseAddrError rather thanAddrParseError.

    The particular choice of word order is not important, but pay attention toconsistency within the crate and consistency with similar functionality in thestandard library.


    [8]ページ先頭

    ©2009-2025 Movatter.jp