37
loading...
This website collects cookies to deliver better user experience
std
library API is trying to achieve the same thing, and I want to explore what that language is.Option
and Result
, such as or
and or_else
and more simply the use of is
.std
library uses to convey information to us.Convention | Types that use it |
---|---|
snake_case |
Crates, modules, functions, methods, local variables and parameters, lifetimes. |
CamelCase |
Types (including traits and enums), type parameters in generics. |
SCREAMING_SNAKE_CASE |
Constant and static variables. |
YourType
will become your_type
. For example:struct BankAccount {
id: u64,
name: String,
amount: u128,
}
fn find_bank_account(id: u64) -> Rc<BankAccount> { ... }
std
library, but I thought it was worth going over.Type name | Text in methods |
---|---|
&T | ref |
&mut T | mut |
&[T] | slice |
&mut [T] | mut_slice |
&[u8] | bytes |
&str | str |
*const T | ptr |
*mut T | mut_ptr |
set_
is used with the field name. For Getter methods, no prefix is used and just the field's name is. For example:struct Person {
name: String,
age: u16,
}
impl Person {
fn new(name: String, age: u16) -> Self {
Person { name, age }
}
// Getters
fn name(&self) -> &str { &self.name }
fn age(&self) -> u16 { self.age }
// Setters
fn set_name(&mut self, name: &str) { self.name = name.to_string(); }
fn set_age(&mut self, age: u16) { self.age = age; }
}
std
library has a few. Below is a list I've discovered.Suffix | Meaning | Example |
---|---|---|
err | Deals with the error part of a result | Result::map_err() |
in | This function uses a given allocator | Vec::new_in |
move | Owned value version for a method that normally returns a referenced value | |
mut | Mutable borrow version of method that normally returns owned or referenced value | &str::split_at_mut() |
ref | Reference version for a method that normally returns an owned value | Chunks::from_ref() |
unchecked | This function is unsafe - there may be dragons beyond! | &str::get_unchecked() |
foo
returns an immutably borrowed value, then there are sometimes variants that return a mutably borrowed or an ownable copy. The suffixes mut
, move
and ref
are used for this. For example:fn foo() -> &T; // original method
fn foo_mut() -> &mut T; // mutable version
fn foo_move() -> T; // owned version
fn bar() -> T; // original version
fn bar_ref() -> &T; // immutably borrowed version
fn bar_mut() -> &mut T; // mutably borrowed version
into_iter()
is used instead of iter_move()
. Also, if the method contains a type name and it returns a mutable borrow, the mut
appears before the type. For example:fn as_bar(foo: &Foo) -> &Bar;
fn as_mut_bar(foo: &Foo) -> &mut Bar;
err
is used with Results
for methods that work with the error part instead of the OK part.unchecked
states that this method or function is unsafe. Make sure you add your protections around it. This suffix should be a BIG red flag to any user wanting to stay within Rust's safety. Usually, the documentation contains information on what you should do around this function to make sure it's still safe. For example, on &str::get_unchecked(i)
the documentation asks that you:i
, your program has already ensured that these conditions are true; in which case you can go ahead and use get_unchecked
instead of get
because it will be more efficient. However, as a programmer, whenever you see the unchecked
suffix, you should be reaching for the documentation to see what those conditions are.in
is not stable yet and Standard Library methods that use this suffix are only in the nightly compiler as of the time of writing. This indicates a variant that allows the user to pass in their allocator for allocation. For example, whereas Vec::new
creates a vector that will use the default allocator when adding elements, Vec::new_in
requires an allocator object that implements the Allocator
trait that will be responsible for allocations.mut
, the convention is that mut
should be last.Prefix | Meaning | Example |
---|---|---|
as | Free conversion from original | &[u8]::as_bytes() |
into | Conversion that consumes original value | String::into_bytes() |
is | Query method that returns a bool | Vec::is_empty() |
new | Indicates a constructor | Box::new_zeroed() |
to | Expensive conversion from original | &str::to_owned() |
try | This variant returns a Result instead panicking | Box::try_new() |
with | The variant uses a function to provide a value instead of directly | RefCell::replace_with() |
as
, to
and into
prefixes indicate conversions. But there are different types of conversions. There are conversions that are free because they are basically no-ops. There are conversions that are expensive because a new type is constructed from the old. And there are conversions that consume the original value to produce the new one. Rust differentiates between these conversions by using prefixes.as
essentially exposes a view to an underlying representation that is present in the original value. For example, a slice from a vector. as
methods do not affect the original value and usually produce a borrowed reference. This means that the conversion's lifetime must be shorter than the original value.to
is an expensive conversion that constructs a new value from the old one. For example, creating a new String
from a string slice. These methods usually produce an ownable value.into
can be expensive and can be a no-op depending on what it does. However, it consumes the original value. An example of this is converting a String
to a Vec<u8>
using into_bytes()
. The String
contains a Vec<u8>
under the bonnet, and so producing it is effectively a no-op. But because it's given away the underlying structure, the String
cannot exist anymore.into_iter()
, which consumes the original container and produces an iterator that can give back its values. It can do this because the new iterator value owns the values and not the original container.new
is often the complete name of a static method for constructing an instance of a struct. However, sometimes there are different ways to do construction and therefore multiple variants of new
. These all have the new
prefix.try
, often used with new
for the try_new
prefix indicates a version of a method that can fail gracefully. For example:// This function will panic if the id does not exist.
fn get_config(id: u32) -> Config { ... }
// This will not panic and will return a Result instead.
fn try_get_config(id: u3) -> Result<Config, ConfigError> { ... }
Result
version is the only version, then there is no need for the prefix try
. It's only used for variants.with
indicates a method that whereas the original function passed a value as a parameter, this variant will be passed a function that provides that value instead. To be fair, I have not seen this suffix used that often. I have even seen other suffixes used to mean the same thing. For example, should Option::ok_or_else
really be Option::ok_or_with
?