0% found this document useful (0 votes)
496 views1 page

Rust Cheat Sheet

The document discusses Rust's ownership and borrowing system. It explains that Rust uses ownership with a set of compiler-checked rules to manage memory. Variables stored on the stack have their memory dropped when they go out of scope. Types that can be copied simply by copying bits can have multiple owners. Borrowing allows references to a value, but the owner cannot access the value until the borrow expires. Lifetimes in Rust ensure references are only valid within the scope they are created.

Uploaded by

Lắng Dũng
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
496 views1 page

Rust Cheat Sheet

The document discusses Rust's ownership and borrowing system. It explains that Rust uses ownership with a set of compiler-checked rules to manage memory. Variables stored on the stack have their memory dropped when they go out of scope. Types that can be copied simply by copying bits can have multiple owners. Borrowing allows references to a value, but the owner cannot access the value until the borrow expires. Lifetimes in Rust ensure references are only valid within the scope they are created.

Uploaded by

Lắng Dũng
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1

Var ab es Ownersh p Pass ng m

the two ways of dealing with assigning


or passing value to other variable
Borrow ng L fet mes L fet me errors some simple
examples

Memory is managed through a system of ownership with Cop


default for variables stored on the stack
w m Every reference in Rust has a lifetime, which is the scope m o n op
D w h let foo = 2 a set of rules that the compiler checks at compile time if you mutably borrow out a value, the borrowing scope does not have
for which that reference is valid let r: &usize;
Types whose values can be duplicated simply by copying bits owner will no longer be able to change the ownership so value won't be dropped
Own hp u
will assume /detect something {
Rust has type inference is of certain type value, until the reference goes out of scope when borrow goes out of scope lifetimes checked with compares scopes to determine
Example of copy let x = 5;
1. Each value in Rust has a variable that’s called its owner. borrow checker that all borrows are valid x goes out of scope
Rust has a strong, static comparing vars must be of
let x = 5; both x and y contain a five r = &x;
R n o bo ow b w h&
matching types
type system 2. There can only be one owner at a time. each var owns its value because goal: borrowed must not outlive owner prevents dangling refs }
let y = x;
3. When the owner goes out of scope, the value will be dropped on assigment to y 5 gets copied let x = &7; println!("r: {}", r); so a ref to x is out of scope too
sometimes the compiler cannot figure out type immutable by default &guess &mut guess assert_eq!(*x, 7);
D on lifetime parameters must fn from<'a>(text:&'a str)
m o n un on
let y = &mut 9;

op o b what types are copy? start with an apostrophe '.


then declare with type let guess: u32 = 2 a: &T  immutable
*y = 11;
assert_eq!(*y, 11);

int, float bool, char A (compound) type can implement mut a: &T  can point p to something else fn main() { function fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { The function signature now
fn main() {
or use turbofish ::<type> after name of function within the block it is a: &mut T  can mutate var pointed at by a let mut s = String::from("hello"); When we’re defining this function, fn longest(x: &str, y: &str) -> &str { fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { says that for some lifetime 'a,
returning the type let x: i32 = 17; tuples containing copy types Copy if all of its components mut a: &mut T  can change pointer and var pointed at
change(&mut s);
struct/ struct Borrowed<'a>(&'a i32) we don’t know the concrete values
declared in, which is {
}
if x.len() > y.len() { if x.len() > y.len() { the function will get two
types implementing copy trait implement Copy https://stackoverflow.com/questions/29672373/what- fn change(some_string: &mut String) {
enum struct ImportantExcerpt<'a> { enum Either<'a> { that will be passed into this
parameters, both of which are
::<u32> denoted by brackets let y: i32 = 3; is-difference-between-mut-a-t-and-a-mut-t
}
some_string.push_str(", world");
    part: &'a str, Num(i32), function, so we don’t know x x
string slices that live at least as
println!("x is {} and y is {}", x, y);
when an owning variable whether the if case or the else case } else { } else {
Mo
default for heap variables
Ru o n n bo ow n
} } Ref(&'a i32), long as the lifetime 'a.

V b mmu b b d u
will execute. We also don’t know
goes out of scoped, it is println!("x is {} and y is {}", x, y); // This "there can be only one" } y y
the concrete lifetimes of the
dropped won't work. static lifetime let s: &'static str = "I have a static lifetime." } }
use mut keyword to } everything that is not copy is move you can only have one
mutablereference to a particular
we can use curly brackets to create a new scope,
allowing for multiplemutable references, just not
references that will be passed in,
The 'static lifetime is the entire so we can’t look at the scopes as w } }
let mut bar = 5 examples of move:
duration of the program

h dow n n op
piece of data in a particular scope simultaneous ones
declare var as mutable
assignment let s1 = String::from('hello') s1 no longer has value, We also cannot have a mutable multiple immutable references are okay because no
m o n u nd num
m on p o du
is moved to s2
reference while we have an one who is just reading the data has the ability to
shadowing a name does let x: i32 = 8; let s2 = s1 calling s1 will lead to
when you do not have
immutableone. affect anyone else’s reading of the data to declare lifetimes structs that hold references need to

h dow n b not alter or destroy the


{ println!("{:?}", s1); //ERROR error
struct Holder{ struct Holder<'a>{
println!("{}", x); // Prints "8". have lifetime annotation
value it was bound to assign each parameter its own lifetime, and then no val: &str val: &'a str
with functions
Au om d n
let x = 12; let s = vec![1,2,3,4]; vars without copy trait are

cleaner conversion let x = "12" println!("{}", x); // Prints "12". let the_sum = sum_vector(s);
moved to argument if
passed to function call!!
need to specify lifetimes when: } }
between types with let x: usize = x.parse().unwrap() } println!("{:?}", s); //ERROR s has Deref coercion was added to Rust so that programmers writing function and method Its lifetime gets assigned let four = String::from("four"); let four = String::from("four");
println!("{}",x); //prints 8 moved into sum_vector 1. there is one input parameter.
same variable name calls don’t need to add as many explicit references and dereferences with & and *. to the output let hold_my_four = Holder{val: four}; let hold_my_four = Holder{val: &four};

Cons an s
compiler will insert as many * To print a memory address use :p 2. there are multiple parameters,
with struct and mutability change operations as necessary to get it right
Its lifetime gets assigned
or removes need for mut let x = 5 const THRESHOLD: i32 = 10; placeholder
but one is &self or &mut self. to output
let mut point = Point { x: 0, y: 0 };
let x = x+1 f.foo(); let x = 1;
type of the value must always point.x = 5;
(&f).foo(); println!("x: {}, address: {:p}", &x, &x);
be annotated const T: usize = 20; let point = point; // now immutable
(&&f).foo(); // x: 1, address: #0x7ffc59c6591c
if compiler can't figure out lifetime based on these rules, lifetime
both can use first value when assigning second (or more) time point.y = 6; // this causes an error
always immutable fn main() { annotation is needed
Constants can be declared in any     println!("{}", T);
scope, including the global scope }

Numbers Char Compound types Structs Enums


usefull as function parameter: easier to
a unicode scalar value indexing into string does not give a are derived from combine related field and allow you to define a write a function to take multiple types
char is always four bytes in size. This is a char. See string slices type by enumerating its see spreadsheet
more than one methods into a type or for vec of type EnumType, which then can
different representation than a given possible values contain any type wrapped in the enum example in Vec
character would have as part of a String. primitive type

n m hod on numb Con u o D fin on


struct Point {
enum Animal { enum Shape {
D fin on D fin u
In Rust, "constructors" are just a convention:

Tup es
x: f64,
use single quotes grouping together some number of other values struct StructName{ struct Rectangle {     Dog, Circle(Point, f64),
y: f64,

m m
}
1. define a struct 2. set defaults 3. declare using new or new with update
integers are a combination of: min or max value that u8::min_value() with avariety of types into one compound type Capital case is rust     field: type, width: u32, let c= Config {     Cat, Rectangle(Point, Point),
can be represented by let c = 'a' let c: char = 'A' let heart_eyed_cat = ' ' height: u32,
pub struct Config { impl Config {

signed (i) or unsigned(u) uint and ints only


this integer type. convention ... pub color: Color, pub fn new() -> Config { color: Red,
} }
u8::max_value()
let tup: (i32, f64, u8) = (500, 6.4, 1) type annotation pub size: Size, Config { .. Config::new()

optional } } pub shape: Shape, color: Brown, };


Structs can be nested
Con on D on
} size: Medium,
8, 16, 32, 64, 128 bits i128 u64 etc shape: Square,
let c = Animal::Cat
n.count_ones() n.count_zeros() let mut a: Animal = Animal::Dog
A m mb
Constructors are static (no self) inherent methods
uint and ints only You cannot loop / iterate a tuple for the type that they construct

u32 i16
w
num to char let c = 65u8 as char char::from_digit(4, 10) -> option<char>

dot notation tup.0


D on use mut to make all fields mutable for private fields, use
mm "like a tuple"
2u32.pow(4) 2f32.powf(3.0)
up u
mods + pub
have the added meaning the struct nameprovides,
char to num c.to_digit(radix) -> option<u32> let user1 = User{ let mut user1 = User{ each variant (dog / cat)
u only but don’t have names associated with their fields enum Animal {
4.is_power_of_two() 2u8.next_power_of_two() by destructuring let (x, y, z) = tup;
two special cases
    email:String::from("emailaddress"),     email:String::from("emailaddress"), or a tuple with a name may have different types
isize usize let mut chars = "abc".chars();     Dog(String, f64),
char to string c.to_string() -> String assert_eq!(chars.as_str(), "abc");
    username:String::from("myusername"),     username:String::from("myusername"), extract fields
    [etc]     [etc] struct Color(i32, i32, i32)     Cat(String, f64),
println!("{:?}", red.0); //100
isize, usize : 32 or 64
let x: isize = -12 sign 10i8.is_positive() 10i8.is_negative() "abc".chars() assert_eq!(chars.as_str(),"bc" );
} struct Point(i32, i32, i32)

A ays
} }
dependent on architecture assert_eq!(chars.next(), Some('a')); let red = Color(100, 0, 0) let Color(r,g,b) = red;
i only
10i8.signum() 10i8.abs() char from byte(s) fixed length container of some type declarating using update pattern .. let origin = Point(0, 0, 0) println!("{}", r); //100
let sparkle_heart = vec![240, 159, 146, 150]; let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2)
-> option<char>
let sparkle_heart = str::from_utf8(&sparkle_heart)
flo n po n
.. will copy unspecified field with let mut point = Point3d { x: 0, y: 0, z: 0 }
let a :[type, size] type must have

f32 or f64 m N w p p n distinguish between different


m
copy trait
values from other struct of same type point = Point3d { y: 1, .. point }
-> Option "like a struct"
P nm hn p d
interpretations of an underlying type
let a: [i32,10] = [0;10] let a = [0;10] array with 10 zeros
ints 16.checked_neg() (-32).checked_add(12)
D u u n struct Miles(f64); extract fields
enum Animal {

Boo ean
c.is_digit(radix) c.is_ascii() this function only recognizes the let a = [1, 2, 3, 4, 5]; struct Kilometers(f64); let milage = Miles(20);
    Dog(String, f64),
42.checked_rem(4) 13.checked_div(3) characters 0-9, a-z and A-Z
struct Point { let p = Point{ let Point { x: a, y: b } = p; to declare vars a and b struct Meters(f64); println!("{:?}", milage.0);
c.is_numeric() c.is_ascii_digit()     x: i32, x: 2,     Cat {name: String, weight: f64 },
let Point { x, y } = p; if var names match field names let Mile(m) = milage;
(-25).checked_mul(3) 32.checked_sub(1)     y: i32, y:12, }

u only checked_next_power_of_two()
c.is_alphabetic() c.is_ascii_alphabetic()
A m see also "Methods for slices and vecs" } }

Structs are Move by default use derive to implement let c = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 }
true or false
D fin m hod
c.is_alphanumeric() c.is_asci_alphanumeric() error if out of
a.get(idx) ->option array.len() copy and clone
a[idx] bounds implement by specifying impl block
true casts to 1 and false to 0
Con on c.is_ascii_lowercase() To enable print
use derive to Enum can have custom discriminant
c.is_ascii_uppercase()
c.is_lowercase() c.is_uppercase()
a.get_mut(idx) instance impl StructName{ impl Rectangle {
fn area(&self) -> u32 {
instance
method call:
implement Debug enum Foo { let baz_discriminant = Foo::Baz as u32;
true as i32 false as i32 fn func(&self, ...){..}
string/str <-> digit let four: u32 = "4".parse().unwrap() c.is_whitespace() c.is_ascii_whitespace() self.width * self.height see Traits for hash, defaults, copy Bar, // 0 assert_eq!(baz_discriminant, 123);
instance } } rect.area()
} Baz = 123,// 123
methods take #[derive(Debug, Copy, Clone)]

Boo n op o
c.is_ascii_punctuation()
o
Quux, // 124
let four = "4".parse::<u32>().unwrap() Returns an iterator that yields the lowercase let arr = [1, 2, 3]; self as first three variants, corresponding to the three &self if it’s a &mut self if it’s a self if it’s a value struct Rectangle {
equivalent of a char as one or more chars. kinds of things the struct instance could be: reference on the stack, }
parameter mutable reference width: u32,
u32::from_str_radix("A", 16) ->Ok(10) for c in &arr{...} or for x in arr.iter() { }
and not c.to_lowercase() c.to_uppercase()
}
height: u32,
you can implements methods on the size of an enum will not exceed the largest of
arrays are arrays in Rust have a this will error enums, just like you would on structs its variants plus as much as is needed for the tag
or xor char <-> digit '1'.to_digit(10) -> option<c> c.to_ascii_uppercase() c.to_ascii_lowercase() non-ASCII letters are unchanged let n = 10; static impl StructName{ impl Rectangle { static method call ::
let r1 = Rectangle{x:1,y:1};
stack allocated fixed / constant length let arr = [i32; n]//error!!
no self fn func(...)... fn area(width, height) -> u32 { let r2 = r1; //Copied, not moved thanks to copy, clone
rect::area(10,3) println!("copied, not moved {:?}, {:?}", r1, r2);

o d u u n num fi d m h p on
char::from_digit(4, 10) } width * height
}
c.len_utf8() num bytes in utf8
between 1 and 4 see also structs, vecs, hasmap, string for heap allocated compound types }
this technique is usually used when the
method transforms self into something else
and you want to prevent the caller from using
the original instance after the transformation

Str ngs Str ng s ce & Methods for Str ng / &str Vec<T> Array s ces Methods for s ces and vecs
"UTF-8 encoded growable string" Slices are a view into a block
P =Pattern s.rfind(char::is_whitespace)
heap allocated
has ownership over the contents s.rfind("asd") of memory represented as
char,&str or closure
stored on the heap
s.rfind('A')
containers of one type a pointer and a length

second major different from string:


D on string type it's borrowed
n o m on upp ow m p n let mut chars = "abc".chars();
assert_eq!(chars.as_str(), "abc");
D on let vec : Vec<usize>
p let x : &[usize] = &[1,2,3] nd n h n n m
change case s.to_uppercase() s.to_lowercase() assert_eq!(chars.next(), Some('a')); empty  let mut vec = Vec::new() might panic option: let mut arr = [1,2,3,4]; let mut arr = [1,2,13];
from string literal String::from("Hello there") Iterator chars s.chars() let x : &mut [usize] = &mut [1,2,3]
D on
A string literal is a string slice assert_eq!(chars.as_str(),"bc" );
let slice = &mut arr[2..4]; let item2 = &mut arr[2];
that is statically allocated,
-> String s.to_ascii_uppercase()
non-ASCII letters are
with capacity Vec::with_capacity(10) get v[index] v.get(index) slice[0] = 5; *item2 = 3;
of certain size String::with_capacity(int) meaning that it's saved inside unchanged -> iterator index + char s.char_indices()
our compiled program, and
exists for the entire duration it Vec to slice change vec[index]= 7 v.get_mut(index)
let item0 = arr.get_mut(0);
clone a_string.clone() runs. from string literal let hello_world = "Hello, World!"; remove whitespaces s.trim() lines s.lines() with values let vec = vec![1, 2, 3, 4] if let Some(elem) = x.get_mut(1) { *(item0.unwrap()) = 11;
    *elem = 42;
let s= v.as_slice() v.as_mut_slice()
from string from slice/ array v = sl.to_vec() sl.to_owned()
Con on other indexing
-> &str }
s.trim_start() s.trim_end() words s.split_whitespace()
whole string.as_str() string.as_mut_str() vec![vec![1], vec![2, 3], vec![4, 5, 6]] let s = &v[1..5] let s = &mut v[i..n]
bytes s.bytes() let mut bytes = "bors".bytes();  multidim v.last() v.first() ->option<&T> if let Some(last) = x.last_mut() {
removes matches
assert_eq!( Some( b'b'), bytes.next());
str_slice.to_string() char.to_string() number.to_string() part of panics if out s.trim_matches(P) *last = 10;
let u = &a_string[i..j] hold multiple
enum SpreadsheetCell {
of bound
-> &str s.trim_left_matches(P) s.trim_right_matches(P) Into two at index let (first, last) = s.split_at(index)
    Int(i32),
    Float(f64), Slice to array arr.clone_from_slice(&src[2..])
x.first_mut() v.last_mut() ->option<&mut T> }
string -> bytes  s.into_bytes() -> Vec<u8> v.get(i..j) types in vec     Text(String),
->Option(slice) -> slices }
let src = [1, 2, 3, 4];
consumes string assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); mutable s.split_at_mut(3) let row = vec![
let mut dst = [0, 0];
dst.copy_from_slice(&src[2..])
on on
dst.clone_from_slice(&src[2..]);

bytes -> string v.get_mut(i..j)     SpreadsheetCell::Int(3),


String::from_utf8(vec![240, 159, 146, 150])
P nm hn Ch n od np
    SpreadsheetCell::Text(String::from("blue")),

see also Regex crate Custom iterators


    SpreadsheetCell::Float(10.12),
-> iterator ];
Multidim  &[&v1[..], &v2[..]]
String::from_utf8_lossy
Con on o n Flatten 
will replace any invalid
UTF-8 sequences with � ["hello", "world"].concat()// "helloworld"
-> bool -> option<index> v.sort() v.reverse() let x = &mut [11,2,3];

Add mo m
split s.split(P) s.rsplit(P) [[1, 2], [3, 4]].concat() // [1,2,3,4] x.sort().reverse();

A on inplace if mutable string only (no slice) str_slice.to_string() s.contains(P) s.is_empty() s.find(P) s.rfind(P)
"abc1def2ghi".split(char::is_numeric)
Vec only
with ["hello", "world"].join(" ") //"hello world"
v.sort_by_key(|k| k.abs())
s.starts_with(P) s.ends_with(P) add item vec.push(item)
add string literal hello.push_str("..?!") str <-> bytes s.find(|c:char|(c<'o') && (c>'a'))
let t = "abc1def2ghi".split(char::is_numeric);
vec.clear() seperator [[1, 2], [3, 4]].join(&0) // [1, 2, 0, 3, 4] v.sort_by(|a, b| a.cmp(b))
remove all values does not change capacity

"bors".as_bytes() as_bytes_mut s.is_char_boundary() s.is_ascii() assert_eq!(vec!["abc", "def", "ghi"], t.collect::<Vec<&str>>()); insert item vec.insert(index, item)
add char at end hello.push(char) -> &[u8]
let u:Vec<&str> = "abc1def2ghi".rsplit(char::is_numeric).collect(); v.swap(1, 3)
shorten vec vec.truncate(new_len) keeps the first len elements
and drops the rest
assert_eq!(vec!["ghi", "def", "abc"], u);
remove last item vec.pop()
no
returns item at index,
->option
v.swap_remove(1) vec only
insert str s.insert_str(index, &str)
Replacing patterns
swaps last item to index
str::from_utf8(&vec![240, 159, 146, 150]) -> String "lion::tiger::leopard".split("::").collect() vec.shrink_to_fit() -> bool
remove from index v.remove(index) shrink capacity 
insert char s.insert(index,char) panics if out of index / not
on char boundary
from_utf8_mut -> Result<&str, err> string.replace(P, &str)
let s = "this is old";
assert_eq!("this is new", s.replace("old", "new"));
reserve capacity vec.reserve(10) Reserves capacity for at least
v.is_empty() v.contains(&30) other
splitn
additional more elements
returns at most N items
remove last char s.pop() option<char>
s.replacen(P, &str, count)
let s = "foo foo 123 foo"; remove and iterate slice v.drain(1..).collect() vec.capacity()
number of elements
the vector can hold
assert_eq!("new new 123 foo", s.replacen("foo", "new", 2));
assert_eq!("faa fao 123 foo", s.replacen('o', "a", 3)); let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect();
Creates a draining iterator that removes the Remove consecutive
vec.dedup() v.starts_with(&[10]) v.starts_with(&[10, 40])
from index s.remove(index) char (or panics) let str_slice: &[&str] = &["one", "two", "three"] specified range in the vector and yields the
repeated elements
assert_eq!("foo foo new23 foo", s.replacen(char::is_numeric, "new", 1));
->["Mary", "had", "a little lambda"]
removed items. vec.len()
Iterate matches Removes all but the first of consecutive elements in
vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)) v.ends_with(&[10]) v.ends_with(&[10, 40])
split s.split_off(index_to_split_at) inplace = 0..t,
returned is t..n
append by clone vec1.extend(vec2); the vector satisfying a given equality relation.

s.matches(P) "1abc2abc3".matches(char::is_numeric).collect() leaves vec2 as is Removes all but the first of consecutive elements in
vec.dedup_by_key(|i| *i / 10);
-> ["1", "2", "3"] vec1.extend_from_slice(&[..]) the vector that resolve to the same key
see iter for maps / filters / plus many others
clear s.clear() removes contents, moves vals from vec2
keeps capacity
s.repeat(usize) filter/ retain v.retain(|a| a<10)
Retains only the elements

s.truncate([n]) append by move vec1.append(&mut vec2)


specified by the predicate

limit to size [n] one at a time over n elements of the slice at a time
last slice might for chunk in v.chunks_mut(2) {

for x in &vec{... no overlap  slice.chunks(chunksize) be shorter for elem in chunk.iter_mut() {


*elem += count;
}

for x in &mut vec{.. v.chunks_mut(2) count += 1;


}

overlap slice.windows(2) let slice = ['r', 'u', 's', 't']; ->ru, us, st, None
let mut iter = slice.windows(2);

Funct ons C osures closures can capture their environment and access
variables from the scope in which they’re defined
Match allows us to compare a value against a
series of patterns and then execute
code based on which pattern matches.
p
into iterator
match not in
returned vals
let slice = [10, 40, 33, 20];
let mut iter = slice.split(|num| num % 3 == 0);
assert_eq!(iter.next().unwrap(), &[10, 40]);
assert_eq!(iter.next().unwrap(), &[20]);
assert!(iter.next().is_none()); into two
D on fn add_one(x: usize)-> usize{
    x+1
un on w h n use traits bounds to make sure that code
inside function works on the generic
n let closure = |arg1| {..} |par1, par2, ..| for multiple args
n match VALUE { 
    PATTERN => EXPRESSION, 
Arm = PATTERN => VALUE
ho h nd a match that only cares
about matching one case
does not check
exhaustiveness
only accepts
refutable patterns let mut iter = vec.split(|num|num%3==0) let (left, right) = v.split_at(index)
(slice, slice)
0..index, index..n

    PATTERN => EXPRESSION, 


}     ...etc... if let Some(3) = somevalue {... while let Some(top) = stack.pop(){... slice.split_mut(|num| num % 3 == 0) let (left, right) = v.split_at_mut(index)

Type of a function is a function pointer


n fn foo<A, B>(x: A, y: B) {.. no need for type
annotation for params
fn add_one_v1 (x: u32) -> u32 { x + 1 }
let add_one_v2 = |x: u32| -> u32 { x + 1 };
}
for group in v.splitn(n, predicate ) {... Some((first, rest)) = x.split_first()
There must be an arm Pattern must match Arms are
if let can be combined with or can combine patterns
fn main() {

or return value let add_one_v3 = |x| { x + 1 }; for every possible value type and length of value scoped locally
let favorite_color: Option<&str> = None;
for group in v.splitn_mut(n, predicate) {... if let Some((last, elements)) = x.split_last()
(multiple) else branches testing different variables
let age: Result<u8, _> = "34".parse();
T T T let add_one_v4 = |x| x + 1 ; let is_tuesday = false;
if let Some(color) = favorite_color {
vec.split_off(usize) Splits the collection into vec contains 0..usize,

|| for no args Match can assign a value or do something println!("Using, {}, as the background", color);
} else if is_tuesday {
Returns an iterator over subslices
separated by elements that match pred,
let v = [10, 40, 30, 20, 60, 50];
for group in v.splitn(2, |num| *num % 3 == 0) {
two at the given index returns usize..n

A um n W h bound
x.split_last_mut() x.split_first_mut() option
println!("{:?}", group);
Generics may use traits as doing so will limit use of func to let x = 5; let x = 1; if let Some(x) = 1...4{..} println!("Tuesday is green day!"); limited to returning at most n items
}
} else if let Ok(age) = age {
bounds on their type parameters types that implement trait let number = match x { match x { else if(condition){..}... ....
(i.e. [10, 40], [20, 60, 50]):
Fn traits 1 => "one", } else {
to force closure to take 1 => println!("one"),
Types of parameters must be declared Fn borrows immutably
5 => "five",
println!("Using blue as the background color");

..on argument _ => println!("anything"), }


or ownership use move keyword
fn foo<T: Trait>(x: T) { fn foo(x: impl Trait) { closures can capture values _ => "something else", };
}

an int FnMut borrows mutably


from their environment in
B nd n ubp n w h@
fn add_one(x: i32) -> i32 { }; The at operator @ lets us create a variable that holds
    x + 1
let clos = move |z| z==x
pub fn notify<T: Summarizable>(item: T) { a value at the same time we’re testing that value to
fn printing(to_print: impl Debug ){ three ways
p on n
FnOnce takes ownership and can
}     println!("Breaking news! {}", item.summary()); see whether it matches a pattern
println!("{:?}", to_print) only be called one time let msg = Message::Hello { id: 5 };
a function fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { } } match msg { By specifying id_variable @ before the range 3...7,
    f(arg) + f(arg)
} match a single value 42 => "some value" Message::Hello { id: id_variable @ 3...7 } => { we’re capturing whatever value matched the range

Capturing env
while also testing that the value matched the range
with where syntax fn foo<T>(x: &[T]) where T: Debug { fn main() { println!("Found an id in range: {}", id_variable) pattern
mutliple values 0 | 1 | 2  => "not many" },
let x = 4;
tuple with closures
The pattern code isn’t able to use the value from the
fn measure(measurement:(i32, u32))-> (i32, bool) Message::Hello { id: 10...12 } => {
id field, because we haven’t saved the id value in a
let equal_to_x = |z| z == x; an enum Message::Quit => println!("Quit") println!("Found an id in another range") variable.
struct fn create(person: Person)-> Child
..for multiple trait bounds <T: Summarizable + Display> },
let y = 4; a range 1 ... 5 => println!("got 1 to 5") Message::Hello { id } => {
In the last arm, where we’ve specified a variable But we haven’t applied any test to
assert!(equal_to_x(y)); println!("Found some other id: {}", id)

R u n p
without a range, we do have the value available to the value in the id field in this arm,
with where syntax fn some_function<T, U>(t: T, u: U) -> i32 },
} anything else _ => println!("something else")
}
use in the arm’s code in a variable named id. The
reason is that we’ve used the struct field shorthand
as we did with the first two arms:
any value would match this pattern
    where T: Display + Clone, syntax. .

last expression of writing ; after an expression     U: Clone + Debug{...}


Returning a closure
function is returned will make it a statement
..on return type fn foo() -> impl Trait {..
P n let x = Some(5);
match x { no n u match numbers {
return early from function return expressions do // before rust 1.26
// after rust 1.26 using impl trait
fn foo() -> impl Fn(i32) -> i32 { fn foo() -> Box<Fn(i32) -> i32> {
named variables Some(50) => println!("Got 50"),
underscore as a wildcard
    (first, _, third, _, fifth) => {
by using return keyword need a finishing ; Some(y) => println!("Matched, y = {:?}", y),         println!("Some numbers: {}, {}, {}", first, third, fifth)
are called existential types, return a type that implements some trait(s) pattern that will match any     },
    |x| x + 1     Box::new(|x| x + 1) _ => println!("Default case, x = {:?}", x),
value but not bind to the value
If there is no expression in the function, the unit type () is returned } }
} }
usefull for closures:
and must be the return type fn test(a: usize) ->(){ Guards Some(x) if x < 10 => process_digit(x)
use the .. syntax to use only a fn main() {
fn foo() -> impl Fn(i32) -> i32 { fn foo() -> impl Iterator<Item = i32> { few parts and ignore the rest
}
println!("{}", a)
    |x| x + 1     vec![1, 2, 3] Storing closures using struct Cacher<T> an additional if condition for
the pattern in an arm Some(n) if n == y =>... y scoped from outer
    let numbers = (2, 4, 8, 16, 32);
    match numbers {
where T: Fn(u32) -> u32
generics and Fn
scope, n taken from some
}         .into_iter()         (first, .., last) => {

bou un
        .map(|x| x + 1)
        .filter(|x| x % 2 == 0)
{ Slice patterns fn foo(s: &[u8]) {             println!("Some numbers: {}, {}", first, last);
        },
} calculation: T, slice patterns can     match s {
    }
Functions can be nested Functions are hoisted value: Option<u32>, match on size of slice         [a, b] => (),
}
        [a, b, c] => (),
}         _ => (),
    }
}

Error Hand ng and Opt on<T> represents an


optional value
enum with variants:

None Some<T> Resu t<T E> used for returning and


propagating errors
enum with the variants
Ok(T),  Err(E),  HashMap<K V> use std::collections::HashMap;
Dates
Chrono provides a DateTime external type
type to represent a date and https://docs.rs/chrono/
a time in a timezone. 0.4.0/chrono/index.html
Concepts L ngo
Nu va ues p let x: Option<usize> = Some(4);
fn somefunc()-> Option<usize>
let is_it_a_value = Some(7)
p
let x: Result<u32, &str> = Err("Nothing here")
let x: Result<u32, &str> = Ok(12)
D on let mut map: HashMap<&str, isize> = HashMap::new(); use chrono::prelude::*;
let utc: DateTime<Utc> = Utc::now(); // e.g. `2014-11-28T12:45:59.324310806Z`
Patterns come in two forms:
refutable and irrefutable.
Wrapping problematic situations the enums to fn multiply(num1: &str, num2: &str) -> Result<i32, ParseIntError> using collect on tuples let hash = s.chars().zip(s.chars().rev()).collect::<HashMap<_,_>>();
let local: DateTime<Local> = Local::now(); // e.g. `2014-11-28T21:45:59.324310806+09:00`
Patterns that will match for let x = 5; because x matches anything
into something safe prevent problems Unp u n m h with custom type as key #[derive(Hash, Eq, PartialEq, Debug)] let mut vikings = HashMap::new();
vikings.insert(Viking{name:"Einar".to_string(), country:"Norway".to_string()}, 25); use chrono::prelude::*;
any possible value passed
are irrefutable
and therefore cannot fail to match

H nd u
struct Viking {
do something
vikings.insert(Viking{name:"Olaf".to_string(), country:"Iceland".to_string()}, 13);
assign let f = File::open("hello.txt"); needs to be hashable
let dt = Utc.ymd(2017,7,8); //2014-07-08UTL
h Op on
    name: String, Patterns that can fail to if let Some(x) = a_value
Rust explicates situations where
for (viking, health) in &vikings {
let f = match f {     country: String, println!("{:?} has {} hp", viking, health); let dt = Utc.ymd(2014, 7, 8).and_hms(9, 10, 11); // `2014-07-08T09:10:11Z` match for some possible

w hm h
let some_u8_value = Some(0u8); let n = match opt{ }
}
value are refutable
  Ok(file) => file,
value might not exist (be None)
num match some_u8_value {     Some(x) => x,   Err(error) => {
D od m
Function parameters, let statements, and for loops can only accept

In Rust, in order to have a value that


    Some(3) => println!("three"),
    None => println!("0"),
    None=> 0,     panic!(" problem opening file: {:?}", error) n mo irrefutable patterns, because the program cannot do anything
meaningful when values don’t match
Expressing null/not null in terms of the }   }, None if key was
ymd and_hms and_hms_micro and_hms_nano -> all panic if datetime invalid
can possiblybe null, you must type system means the compilercan } map.insert(37, "a") ->option<oldValue>
not yet present
}; ymd_opt and_hms_opt
explicitly opt in by making the type of check that you’ve handled all the cases map.remove(&1) ->Option<valueAtKey>
-> Option<datetime>
Statements vs expressions
that value Option<T> . you should be handling Ch n wh h num Ch n wh h num map.retain(|&k, _| k % 2 == 0)
Retains only the elements
specified by the predicate.
let dt = Utc.ymd(2014, 7, 8).and_hms(9, 10, 11); // `2014-07-08T09:10:11Z` Statements are instructions that perform
some action and do not return a value.
assignment is a statement and
does not return a value

->bool opt.is_none() opt.is_some() -> bool res.is_ok() res.is_err() G p o d Expressions evaluate to a resulting value

h u Rust expicates situations where


n
entry gets the given key's corresponding Occupied(OccupiedEntry<'a, K, V>)
let dt = Local::now();
you do something that might go entry in the map for in-place manipulation

num Unw pp n h op on Unw pp n h u


Vacant(VacantEntry<'a, K, V>)

wrong let k =3;


Insert ->&'a mut V dt.year() dt.month() dt.day() start at 1 dt.month0(), day0, ordinal0 for zero start
-> val if Some(val).. .. + default when None Some(4).unwrap_or_else(|| 2 * k); ->val if Ok(val).. ..+ panics if error
used as a return type for function
..+ panics if None ..+ return default on error
map.entry("poneyland").or_insert(12) modify ->Self and_modify dt.hour() dt.minute() dt.second() dt.date() dt.time()
By matching the result type you panics if None opt.unwrap() opt.unwrap_or_else(FnOnce) unwraps  ok, else panic res.unwrap() res.unwrap_or_else(FnOnce) -> number of days since January 1, 1 (Day 1)
this gives the possibility to can distinguish and handle a map.entry("poneyland").or_insert_with(FnOnce) map.entry("poneyland") dt.weekday() -> enum Weekday dt.num_days_from_ce() in the proleptic Gregorian calendar
panic with unwraps  ok, else panic
distinguish successes from error success or error opt.expect("custom_msg") opt.unwrap_or(default_val) res.expect("err message") res.unwrap_or_default(default_val)     .and_modify(|e| { *e += 1 })
custom_msg  with custom message dt.timestamp()
default value for type map.entry("poneyland").or_default() dt.ordinal () -> day of year (1-365) the number of non-leap seconds since January 1, 1970 0:00:00 UTC
None.unwrap_or("bike")     .or_insert(42); (aka "UNIX timestamp").

Both Result and option This conversions can only be done by


Con on
let counter = letters.entry(ch).or_insert(0);

need to be converted to its explicating what happens when there


replace
let mut x = Some(2);
let t = x.take();
replaces value with
none, returns new Con on with some(val) or None (if error)
*counter += 1;

N wd w h h n d
opt.take() assert_eq!(x, None); option with value

type generic to be used is either a none value, or an error G h u no


assert_eq!(t, Some(2)); let x: Result<u32, &str> = Ok(2); let x: Result<u32, &str> = Err("Nothing here");
To option result.ok() assert_eq!(x.ok(), Some(2)); assert_eq!(x.ok(), None);
dt.with_year(i32) dt.with_month(u32) dt.with_day(u32
-> to option opt.map(FnOnce) let x: Result<u32, &str> = Ok(2); let x: Result<u32, &str> = Err("Nothing here");
Applies a function to the contained result.err() map.get_mut(&1) map.get(&1) Option<&V> map.len()
value (if any), or returns the provided opt.map_or(defaultVal_if_None, FnOnce)
assert_eq!(x.err(), None); assert_eq!(x.err(), Some("Nothing here"));
dt.with_hour(u32) dt.with_minute(u32) dt.with_second(u32)
default (if not).
Applies a function to the contained
opt.map_or_else(FnOnce_for_none, FnOnce_for_some) To res res.map(FnOnce) Maps a Result<T, E> to Result<U, E> by applying a function
to a contained Ok value, leaving an Err value untouched. map[&'a'] panics if no entry map.capacity()
Returns the number of elements the
map can hold without reallocating
dt.with_ordinal(32)
value (if any), or computes a default (if
not).
Maps a Result<T, E> to Result<T, F> by applying a
res.map_err(FnOnce) function to a contained Err value, leaving an Ok map.contains_key(&1) bool use time::Duration;
-> to result  value untouched

Comb n n u
fn checked_sub_signed(self, rhs:
mapping Some(v) to Ok(v) and
opt.ok_or(err_val) let x = Some("foo"); dt1.signed_Duration_since(dt2) fn checked_add_signed(self, rhs:
OldDuration) ->

oop u
None to Err(err_val) OldDuration) ->
assert_eq!(x.ok_or(0), Ok("foo")); Option<Date<Tz>> Option<Date<Tz>>
order is arbitrary dt1 + Duration::seconds(num) -> dt
mapping Some(v) to Ok(v) and
None to Err(FnOnce())
opt.ok_or_else(FnOnce) let x: Option<&str> = None; -> duration::seconds
assert_eq!(x.ok_or(0), Err(0)); res1.and(res2) res2 if both Ok, else (first
encountered) error res.and_then(FnOnce) Calls fnOnce if the result is Err,
otherwise returns the Ok value of res
for key in map.keys() {.. ->&'a K
res1.or(res2) res2 if res1 is err,
dt.to_string(), "2014-11-28 12:00:09 UTC"
Comb n n op on
first_number_str.parse::<i32>().and_then(|first_number| {
else Ok val res1
second_number_str.parse::<i32>().map(|second_number| first_number * second_number)

res.or_else(FnOnce) Err value if err, }) for val in map.values() { ->&'a V "2014-11-28 12:00:09"
else calls F dt.format("%Y-%m-%d %H:%M:%S").to_string()
returns opt2 if opt1 and opt2 None if opt is None, else calls
opt1.and(opt2) are Some,else none opt.and_then(FnOnce) FnOnce with val in some
fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
fn err(x: u32) -> Result<u32, u32> { Err(x) }
fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
fn err(x: u32) -> Result<u32, u32> { Err(x) }
for val in map.values_mut() { ->&'a mut V
assert_eq!(Ok(2).or_else(sq).or_else(sq), Ok(2)); assert_eq!(Ok(2).and_then(sq).and_then(sq), Ok(16));
returns opt1 if some, Returns the option if it contains
opt1.or(opt2) else opt2 opt.or_else(FnOnce) a value, otherwise calls f and
assert_eq!(Ok(2).or_else(err).or_else(sq), Ok(2));
assert_eq!(Err(3).or_else(sq).or_else(err), Ok(9));
assert_eq!(Ok(2).and_then(sq).and_then(err), Err(4));
assert_eq!(Ok(2).and_then(err).and_then(sq), Err(2));
for (key, val) in map.iter() { for (key, val) in &map { ->(&'a K, &'a V)
returns the result.
assert_eq!(Err(3).or_else(err).or_else(err), Err(3)); assert_eq!(Err(3).and_then(sq).and_then(sq), Err(3));
->(&'a K, &'a mut V)
for (k, val) in map.iter_mut() {

e p ov des he o ow ng
Gener cs Tra ts #[der ve(tra t)] ter
A trait tells the Rust compiler about functionality a particular type has and
are abstract stand-ins for concrete operations for looping over, mapping, searching, filtering a
might share with other types
types or other properties collection of some sort, or something that yields items

A way to handle Generics allow code to


o mp m n Associated type the type of the thing
Reduc on nd m o nd
Associated types connect a type placeholder with a
The behavior of a type Different types share the same Trait definitions are a Rust contains a large some operators / functions deriving is the simplest to iterate over
trait such that the trait method definitions can use
->Option
duplication of concepts operate on abstract types
these placeholder types in their signatures
consists of the methods behavior if we can call the same way to group method
number of traits you may require a trait to be implemented way to comply with this ->bool
o d fin Next function
Searches for an element of an
we can call on that type. methods on all of those types. signatures together
returns next item or None if Tests if every element of the iterator matches a predicate. a.iter().find(|&&x| x == 2) iterator that satisfies the predicate.
let a = [1, 2, 3];
assert_eq!(a.iter().find(|&&x| x == 2), Some(&2));
When you recognize situations in your code with multiple struct or enum definitions that differ only
in the types of the values they hold, you can avoid duplication by using generic types instead use on your types and will not compile without it trait bound
there are no more items
a.iter().any(|&x| x > 0) a.iter().all(|&x| x > 0)
assert_eq!(a.iter().find(|&&x| x == 5), None);
Because find() takes a reference, and many iterators iterate over
a.iter().position(|&x| x == 2) ->index of first "true"

D fin n
references, this leads to a possibly confusing situation where the
trait Iterator { struct Counter { impl Iterator for Counter {

•function (parameters, return type) Traits can be implemented for count: usize,     type Item = usize; argument is a double reference. You can see this effect in the

Generics can be used in


h o ow n nb d d min/max
any data type. -> index (from left) of first examples below, with &&x.
though not possible in all     type Item; }
impl Counter {     fn next(&mut self) -> Option ->option a.iter().rposition(|&x| x == 3) true, when starting from right
•structs field •enums •traits pub trait Summarizable {
declare func signature (summary)
situations for all types     fn next(&mut self) -> Option<Self::Item>;     fn new() -> Counter {         self.count += 1; let arr = vec![1,2,3,4,5,2,7,8,2];

that type with trait summarizable


        Counter { count: 0 }         if self.count < 6 {
a.iter().min() a.iter().max() a.iter().nth(1) consumes iterator upto n let t = arr.iter().rposition(|d| *d==2);
    fn summary(&self) -> String; }     }             Some(self.count) assert_eq!(t, Some(8))

for equality comparisons


n <T> signifies a needs to implement }         } else {
the T is to be substituted you can use any letter,
}             None gives the maximum value with a.min_by(|x, y| x.cmp(y)) a.iter().last() all preceding elements, as well as the returned
though starting at T is a ...
respect to the specified
element, will be consumed from the iterator.
generic in a type for a concrete type
declaration
rust convention Each type that implements this trait can
impl Summarizable for Article{ for ordering comparisons oop n h ou h o comparison function a.max_by(|x, y| x.cmp(y))

wh ho d n
then provide its own custom behavior

n un on T T T implement on types using impl


    fn summary(&self) ->String{..}
} for programmer output for method for c in Counter::new(){...
max or min after some
function has been applied
a.min_by_key(|x| x.abs())
We read this definition as: the function largest is generic over some type T to each element a.max_by_key(|x| x.abs()) Fold / reduce let sum = a.iter().fold(0, |acc, &x| acc + x);
uses into_iter()
You can also give default pub trait Summarizable { for mapping a value to a value of fixed size
n u
struct Point<T> { implementation for some or all *a.iter().min_by(|x, y| x.cmp(y)).unwrap(), -10) Scan takes two arguments: an initial value which seeds
let mut iter = a.iter().scan(1, |state, &x| {
    x: T,     fn summary(&self) -> String{ the internal state, and a closure with two arguments,
// each iteration, we'll multiply the state by the element
methods of a trait the first being a mutable reference to the internal

for default values C n o


    *state = *state * x;
    y: T,         ...default here... state and the second an iterator element. The
closure can assign to the internal state to share
summary
    // the value passed on to the next iteration
} default overridden by
    } state between iterations
    Some(*state)
with impl
implementing specific for type
} for duplicating values });
it.into_iter()
Note that we have to declare T just after impl so You can overrule impl<T> with
impl<T> Point<T> {
which iterates over T a.iter().product() a.iter().count() a.iter().sum()
https://stackoverflow.com/questions/34733811/
we can use it to specify that we’re implementation for a specific type what-is-the-difference-between-iter-and-into-iter
fn x(&self) -> &T { implementing methods on the type Point<T>.
into_iter is a generic method to obtain an iterator, whether this iterator yields
&self.x
it.iter()
od u which iterates over &T
By declaring T as a generic type after impl, Rust values, immutable references or mutable references is context dependent

A o d p
} can identify that the type in the angle brackets and can sometimes be surprising.
in Point is a generic type rather than a concrete iter and iter_mut are ad-hoc methods. This works around the context-
}

Adap e s Cyc es
type dependent bit and, by convention, let you obtain an iterator which will yield

impl Point<f32> { This code means the type Associated types are a way of associating a type using an associated type in stead of a generic, results in not #[derive(Default, Debug)] it.iter_mut() which iterates over &mut T references
functions which take iterator
Repeats an iterator
Point<f32> will have a method
placeholder with a trait such that the trait having to specify the type when using a trait endlessly
fn distance_from_origin(&self) -> f32 { named distance_from_origin and struct SomeOptions { and return other iterator
method definitions can use these placeholder
N m hod
(self.x.powi(2) + self.y.powi(2)).sqrt() other instances of Point<T> where T
is not of type f32 will not have this foo: i32, rev a.iter().rev(); Reverses an reverse from cmp
} method defined
types in their signatures. map a.into_iter().map(|x| 2 * x) iterator's direction rev from iter
} When we use a trait, we have to provide type
bar: f32,
when a trait has a generic parameter, it can be implemented for
} flat_map
let words = ["alpha", "beta", "gamma"];
skip a.iter().skip(2);
a type multiple times, changing the concrete types of the generic annotations to indicate which implementation let merged: String = words.iter()
counter.next() ->Option<item, None>     .flat_map(|s| s.chars())

n num enum Option<T> { let integer = Some(5); type parameters each time. of the trait we want to use fn main() {     .collect();
assert_eq!(merged, "alphabetagamma"); skip_while a.into_iter().skip_while(|x| x.is_negative());
Some(T), let float = Some(5.0);
trait Graph<N, E> { fn distance<N, E, G: Graph<N, E>>(graph: &G, start: &N, end: &N) -> u32 { let options: SomeOptions = Default::default(); //thanks to default
None, let mut iter = a.into_iter() Because the closure passed to skip_while() takes a

o o
fn has_edge(&self, &N, &N) -> bool;
fn edges(&self, &N) -> Vec<E>; ... } println!("{:?}", options); //thanks to debug enumerate for (count, val) in a.iter().enumerate() reference, and many iterators iterate over references,
} .skip_while(|x| **x < 0); this leads to a possibly confusing situation, where the
// etc
} } chain let mut iter = a1.iter().chain(a2.iter()) // need two *s! type of the closure is a double reference:

collect
U n mu p n
let t: Vec<usize> = Counter::new().into_iter().collect() take a.iter().take(2);

Tra t bound
With associated types, we don’t need to fn distance<G: Graph>(graph: &G, start: &G::N, end: &G::N) -> u32 {
filter a.into_iter().filter(|x| x.is_positive())
annotate types because we can’t implement a ... }} limits use of a function to the Transforms an iterator
trait on a type multiple times into a collection let t= Counter::new().into_iter().collect<Vec<usize>>() take_while a.into_iter().take_while(|x| x.is_negative());
struct Point<T, U> { fn foo<A, B>(x: A, y: B) {.. types implementing the trait filter_map
let a = ["1", "lol", "3", "NaN", "5"];
removes option<t> layer 
let mut iter = a.iter().filter_map(|s| s.parse().ok());
(when compared with filter
    x: T, partition
trait Graph { struct Node;
assert_eq!(iter.next(), Some(1));
then map)
type N; struct Edge;
let (even, odd): (Vec<i32>, Vec<i32>) = assert_eq!(iter.next(), Some(3));
    y: U, type E; struct MyGraph;
Consumes an assert_eq!(iter.next(), Some(5));
fn has_edge(&self, &Self::N, &Self::N) -> bool; impl Graph for MyGraph {
    a.into_iter().partition(|&n|n%2==0)
n p
assert_eq!(iter.next(), None);
} T: Trait x: T impl Trait iterator, creating two a.iter()
fn edges(&self, &Self::N) -> Vec<Self::E>; type N = Node;
// etc type E = Edge; let mut iter = a.iter().map(|s| s.parse()).filter(|s| s.is_ok()).map(|s| s.unwrap());
collections from it.     .cloned()
let p = Point { x: 5, y: 10.0 } fn(.....
}
or zip let a1 = [1, 2, 3]; for debugging     .inspect(|x| println!("about to filter: {}", x))
    .filter(|&x| x % 2 == 0)
let a2 = [4, 5, 6];
x: impl Trait let mut iter = a1.iter().zip(a2.iter())     .inspect(|x| println!("made it through filter: {}", x))
    .fold(0, |sum, i| sum + i);
let a = [(1, 2), (3, 4)];
unzip
let (left,right):(Vec<_>,Vec<_>)= a.iter().cloned().unzip()
//left ==[1,3], right==[2,4]

Env Path F e Fs Fmt Sources


contains functions to inspect various aspects such as environment
operations for A reference to an open contains basic methods to manipulate Utilities for formatting
variables, process arguments, the current directory, and various use std::path::Path;
inspecting a path file on the filesystem the contents of the local filesystem and printing Strings
other important directories

G o m n D let path = Path::new("./foo/bar.txt"); Open a file in read-only mode let mut f = File::open("foo.txt") fs::read_to_string("address.txt") -> Result<String> to string format! format!("{},{}", val1, val2)
h u po mm n n u
let foo: SocketAddr = fs:: to stdout println! print! format!("The number is {}", 1); // => "The number is 1"
An iterator over the arguments of get entries https://doc.rust-lang.org/book/index.html
for argument in env::args() {...} a process, yielding a String value for entry read_dir Open a file in write-only mode let mut f = File::create("foo.txt")
read_to_string("address.txt")?.parse()?

in path will overwrite to stderr eprintln!


for each argument fs::copy("foo.txt", "bar.txt")?  copies returns num

Ru b mp
permissions bytes copied contents!!
if exist, will use std::fs::File; use std::fs::File;
to stream write! writeln! use std::io::Write;
n onm n overwrite
use std::io::prelude::*; use std::io::prelude::*; fs::create_dir("/some/dir")
>boo is_file
contents of file
let mut file = File::create("foo.txt")?;
file.write_all(b"Hello, world!")?;
let mut file = File::open("foo.txt")?;
let mut contents = String::new(); fs::create_dir_all("/some/dir") Recursively create a directory and all of its
let mut w = Vec::new();
write!(&mut w, "Hello {}!", "world"); https://doc.rust-lang.org/rust-by-example/index.html
get  match env::var(key) {..  Result<String, VarError>
path.starts_with("/etc") file.read_to_string(&mut contents)?;
parent components if they are missing

placeholders will be filled .. 


assert_eq!(contents, "Hello, world!"); fs::hard_link("a.txt", "b.txt")
set env::set_var(key, "VALUE"); path.ends_with("passwd") fs::remove_dir("/some/dir") ..in order.. format!("{} {}", 1, 2);// => "1 2" h u nd d b
iterate all for (key, value) in env::vars() {
Returns an iterator of (variable,
value) pairs of strings, for all the
environment variables of the exists
nd op n o op nop on fs::remove_dir_all("/some/dir") Removes a directory at this path,
PLUS removing all its contents.
...unless they are... https://doc.rust-lang.org/std/index.html

OpenOp ons
current process.
fs::remove_file("a.txt") ..named or.. format!("{value}", value=4);// => "4"
D o n o h m p
poses the ability to configure how a
is_dir File is opened and what operations
use std::fs::OpenOptions;

are permitted on the open file


fs::rename("a.txt", "b.txt") overwrites!!
..indexed format!("{name} {}", 1, name = 2)
pub fn current_dir() -> < > full filesystem path of the Path::new("/etc/passwd").has_root()) read sets read access www.breakdown-notes.com/make/load/rust_cs_canvas/true
current running executable
let file = OpenOptions::new() Can also be format!("{1} {} {0} {}", 1, 2); // => "2 1 1 2"

D En y
intermingled
write
M d u n B down No
sets write access             .append(true)
pub fn current_exe() -> < >
represents an entry inside of

on w Path::new("/etc").join("passwd")
a directory on the filesystem
append
This option, when true, means that writes will
append to a file instead of overwriting previous             .open("foo.txt");
www.breakdown-notes.com
contents. Returns an iterator over the

pub fn home_dir() -> < > for entry in fs::read_dir(dir) entries within a directory
->option path.with_extension("txt") truncate If a file is successfully opened with this option set it
will truncate the file to 0 length if it already exists let file = OpenOptions::new() use std::fs;
match env::home_dir() { create This option indicates whether a new file will be
           .read(true)
    Some(path) => println!("{}", path.display()),
path.with_file_name("bar.txt") created if the file does not yet already exist.
for entry in fs::read_dir(".")? {
let dir = entry?;
create_new No file is allowed to exist at            .write(true)
println!("{:?}", dir.path());
    None => println!("Impossible to get your home dir!"), the target location
           .create(true)
}
Path::new("tmp/foo.txt").file_name() open Opens a file at path with the }
options specified
           .open("foo.txt");
dir.path() dir.file_name()
path.file_stem()
filename
without ext
dir.file_type()
path.extension()
np m hod dir.metadata() metadata.permissions()

path.display() let file = File::open("foo.txt")?;

let path = Path::new("/tmp/foo.txt");


set_file_name let mut perms = file.metadata()?.permissions();
perms.set_readonly(true);
assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt"));
file.set_permissions(perms)?;
let path = Path::new("/tmp");
assert_eq!(path.with_file_name("var"), PathBuf::from("/var")); set_extension

You might also like