rust
Local Documentation
rustup doc
brings up all the local documentation including- The Rust book
- Rust by Example
- Cargo book
- Inside your project,
cargo doc --open
opens your project's documentation- Without
--open
will just generate the documentation, which can be potentially shared with others as required.
- Without
Data Types
- Arrays : Fixed size
- When defining say days of the week, months of the year etc.
- Initialize as :
let a = [3; 5];
is same aslet a = [3, 3, 3, 3, 3];
- Vector : Like array but can shrink and/or grow
- If unsure, use Vector
- Use
new()
orvec!
to create
let mut numbers: Vec<i32> = Vec::new();
let mut magic_numbers = vec![7i32, 42, 47, 45, 54];
push
to add at the end,pop
remove from the end
Enum
- Similar to Enum in python
- But variants can contain data like
struct
- Data fields can be named/labeled (like
title: String
) or unlabeled- labeled ones improve readability though
Control Flow
rust does not have
truthy
values. e.g. ifx
is1
, thenif x
does not compile.x
must be booleanloop
can have optional label. See the documentation
'outer: loop {
. ...
loop { // inner, unlabeled loop
...
if some_condition {
break; // Will break from inner/unlabeled loop
}
...
...
if some_other_condition {
break 'outer'; // will break out of the outer loop
}
...
}
}
Statements Vs Expressions
Statements do not return a value, expressions do.
C and Ruby, where the assignment returns the value of the assignment.
In those languages, you can write x = y = 6 and have both x and y have
the value 6; that is not the case in Rust.
In a function, last expression is also a return value.
If you add a semicolon to the end of an expression, you turn it into
a statement, and it will then not return a value.
Three types of iterators
iter()
: Gives read-only reference inside the loop- Collection available for reuse after the loop.
into_iter()
: Gives ownership of the element inside the loop- Collection has been consumed it is no longer available for reuse as it has
been 'moved' within the loop.
- Collection has been consumed it is no longer available for reuse as it has
iter_mut
: Gives mutable reference inside the loop- Collection can be modified in place (while being iterated over)
See the reference
Iterator consumer
for
loopelements.iter().for_each( | element | println!("{}", element));
collect()
collect()
automagically decides what data structure to output to, based on- The return type.
- return type of the function if
collect
is the last statement - explicit instruction like
collect::<Vec<String>>()
find
: Callsnext
till it finds an element that returns truthy value- So the loop may not complete, if any of the element matches the condition
- If not found, returns
None
- else
Some(value)
Iterator Adaptors
.map(|element| <do something to the element)
- Modifies
element
but does not callnext
- So after
.map
,.for_each
must be called - output of
map
is then passed tofor_each
- Modifies
map_or
: Takes 2 args- First is returned if it gets
None
(From sayfind
) - Second is used if it gets
Some(value)
- First is returned if it gets
Ownership
- Cloning avoids Moves
- Useful when we need to reference the "original" data after it the ownership is moved
.clone
create a copy (which is used to move the oownership,leaving the original intact)
Slice
We create slices using a range within brackets by specifying
[starting_index..ending_index]
, wherestarting_index
is the first position
in the slice andending_index
is one more than the last position in the slice.
&str
is called a String Slice
- There is also Vector slice. Same as String slice.
- We can point to just portion of the Vector
- So when passing a Vector, prefer to use
&[<data type of contents of a vector>]
e.g.&[String]
Implementations
impl
keyword is used to assign methods (mostly) tostruct
- return type
Self
indicates, it will return the same type
for which the implementation is being added. - Associated function : Directly associated with
struct
(Mostlynew
or constructor)- Called using
Struct::function()
- Called using
- Method: Associated with instance of struct
- Called using
instance.method()
- First arg is
&self
- Called using
Mutability
- Indicate mutability using
mut
keyword for the variable. - Mutable references :
- use
&mut type_goes_here
in the function definition to indicate function expects mutable reference. - Call using
&mut variable_goes_here
- use
Sample code:
fn change_num(number: &mut usize) {
*number = 1;
}
fn main() {
let mut num: usize = 10;
println!("{:#?}", num);
change_num(&mut num);
println!("{:#?}", num);
}
Rules
- You can make a mutable reference to a value only if there are no read-only references currently in use. One mutable ref to a value can exist at a time
- You can't mutate a value through the owner when any ref (mutable or immutable) to the value exists
Error Handling
When return value is Option
(or Result
), preferred ways to deal with it are :
match
forSome
andNone
explicitly. (OrOk
andErr
)- We can deal with the error in a meaningful way (like having fallback value)
if let
andelse
unwrap
: By itself, Avoid using unless temporary code or debugging.expect
: When you expect the value to be present, like environment variableunwrap_or
: If there can be a fallback value (like say missing config)?
when we can not handle the error in the current function (Caller may have more information to deal with the error, so no need topanic
in current function)Error::other
creates new instance ofError
(likenew()
)
?
operator
- Error is propagated back to the caller.
- Our function does not need to handle the error. It assumes happy path, but if there is an error, using
?
will short circuit the execution, and will return from that point to the caller. - Also called as
Try
operator
Generics
struct State<T> {
data: T,
}
let state_int: State<i32> = State { data: 5 }; // State holding an integer
let state_str: State<&str> = State { data: "hello" }; // State holding a string
Here State
is a generic type. Defining it as State<i32>
makes it specific
Resources
Strings
- Use
String
when- Want ownership
- Want text that can grow or shrink
&String
- rarely used
- Rust automatically converts it to
&str
(String slice)
- Use
&str
- No ownership needed
- Need part/slice of the string