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
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()
: Collection available for reuse after the loop.into_iter()
: Collection has been consumed it is no longer available for
reuse as it has been 'moved' within the loop.iter_mut
: Collection can be modified in place (while being iterated over)
See the reference
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.
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);
}
Error Handling
?
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.
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