Homepage / Notes / Computer Science / Programming Languages / Rust
rustc {filename}.rs
./{filename}
fn main() {
}
main
function is special: always the first code that runs in every executable Rust program. Function parameters go inside the parentheses: ()
And code for the function goes inside curly brackets: {}
rustfmt
can be used to automatically format our Rust code. Indent 4 spaces, no tabs.
fn main() {
// This is a comment
}
fn main() {
println!("Hello, World!");
}
Hello, World!
println!()
is a Rust macro. !
means it's a macro and not a function. ;
at the end of the line indicates that the expression is over.
https://doc.rust-lang.org/book/appendix-02-operators.html
cargo run {project_name}
cargo build
, build for release: cargo build --release
(with optimizations)cargo run
cargo check
(faster than cargo build
)Cargo book https://doc.rust-lang.org/stable/cargo/
'a'
, 'b'
…true
or false
()
which is an empty tuplefn main() {
let x = 5 + 5;
+= 5;
x println!("{}", x);
}
error: Could not compile `cargoSivb4X`.
cannot assign twice to immutable variable
fn main() {
let mut x = 5 + 5;
+= 5;
x println!("{}", x);
}
15
Starting from Rust 1.59:
fn main() {
let (a, b) = (1, 2);
println!("{a}");
println!("{b}");
}
1
2
snakecase is the convention for naming functions
fn main() {
println!("{}", "Hello");
;
another_function()}
fn another_function() {
println!("{}", "World!");
}
Hello
World!
Arguments' types have to be specified:
fn greet(name: &str) {
println!("Hello, {name}");
}
"Damien"); greet(
Hello, Damien
Function's return type have to be specified too:
fn sum(x: i32, y: i32) -> i32 {
+ y
x }
println!("{}", sum(4, 5));
9
Function's automatically return the value of the last expression, but can be returned early using the return
keyword:
fn sum(x: i32, y: i32) -> i32 {
return x + y;
}
println!("{}", sum(4, 5));
9
fn main() {
let s = "Damien";
println!("{}", s);
}
Damien
fn main() {
let s = "Damien".chars();
println!("{:?}", s);
}
Chars(['D', 'a', 'm', 'i', 'e', 'n'])
let x = 9;
println!("{x}");
9
let range = 1..5;
for i in range {
println!("{i}");
}
1
2
3
4
Right-inclusive range:
let range = 1..=5;
for i in range {
println!("{i}");
}
1
2
3
4
5
fn main() {
let a = 1 + 1;
println!("{}", a);
}
2
Starting from Rust 1.58:
fn main() {
let a = 1 + 1;
println!("{a}");
}
2
https://www.rustnote.com/blog/format_strings.html
Tuples can contain multiple types. Tuples have a fixed length.
let tup: (i32, f64, u8) = (500, 6.4, 1);
Every element of an array has to have the same type. Array in Rust have a fixed length.
let a = [1, 2, 3, 4, 5];
Arrays are useful when you want your data to be allocated on the stack rather than the heap.
To write an array's type, you have to specify the type AND the number of elements in the array, separated by a colon, and enclosed in square brackets:
let a: [i32; 5] = [1, 2, 3, 4, 5];
It's possible to initialize an array that contains the same value for each element by specifying the initial value, followed by a semicolon, and then the length of the array, enclosed in square brackets:
let a = [3; 5];
println!("{:?}", a);
[3, 3, 3, 3, 3]
By using the index:
let a = [1, 2, 3, 4, 5];
let first = a[0];
let second = a[1];
println!("{:?}", first);
println!("{:?}", second);
1
2
A type has to be specified when creating an empty vec
as type can't be inferred:
let v: Vec<i32> = Vec::new();
println!("{:?}", v);
[]
Not necessary when initializing the vec
with values:
let v = vec![1, 2, 3];
println!("{:?}", v);
[1, 2, 3]
let mut v = vec![1, 2, 3];
println!("{}", &v[0]);
println!("{}", &v[2]);
1
3
When adding values later in the code, Rust can also infer the vec
type
let mut v = Vec::new();
.push(5);
v.push(6);
v.push(7);
v
println!("{:?}", v);
[5, 6, 7]
let mut v = vec![1, 2, 3];
.remove(0);
v
println!("{:?}", v);
[2, 3]
let v = vec![9, 10, 11];
for i in &v {
println!("{}", i);
}
9
10
11
Values can be mutated while iterating, but they have to be de-referenced by using *
let mut v = vec![9, 10, 11];
for i in &mut v {
*i += 1;
}
println!("{:?}", v);
[10, 11, 12]
A double-ended queue implemented with a growable ring buffer.
use std::collections::VecDeque;
let deq: VecDeque<u32> = VecDeque::new();
println!("{:?}", deq);
[]
Initializing with values:
use std::collections::VecDeque;
let deq = VecDeque::from([-1, 0, 1]);
println!("{:?}", deq);
[-1, 0, 1]
use std::collections::VecDeque;
let mut deq: VecDeque<u32> = VecDeque::new();
.push_front(1);
deq.push_front(2);
deqprintln!("{:?}", deq);
[2, 1]
use std::collections::VecDeque;
let mut deq: VecDeque<u32> = VecDeque::new();
.push_back(1);
deq.push_back(2);
deqprintln!("{:?}", deq);
[1, 2]
use std::collections::VecDeque;
let mut deq = VecDeque::from([0]);
.push_front(1);
deq.push_front(2);
deq.push_back(3);
deq.push_back(4);
deq.push_back(5);
deqprintln!("{:?}", deq);
[2, 1, 0, 3, 4, 5]
use std::collections::VecDeque;
let mut deq = VecDeque::from([1, 2, 3]);
.pop_front();
deqprintln!("{:?}", deq);
[2, 3]
use std::collections::VecDeque;
let mut deq = VecDeque::from([1, 2, 3]);
.pop_back();
deqprintln!("{:?}", deq);
[1, 2]
A doubly-linked list with owned nodes.
Allows to store key/value pairs.
use std::collections::HashMap;
let mut map = HashMap::new();
println!("{:?}", map);
.insert("Japan", "Tokyo");
map.insert("France", "Paris");
map.insert("Canada", "Ottawa");
mapprintln!("{:?}", map);
.remove("France");
mapprintln!("{:?}", map);
{}
{"France": "Paris", "Japan": "Tokyo", "Canada": "Ottawa"}
{"Japan": "Tokyo", "Canada": "Ottawa"}
Equivalent to HashMaps
but "sorted".
use std::collections::BTreeMap;
let mut btree = BTreeMap::new();
println!("{:?}", btree);
.insert("Germany", "Berlin");
btree.insert("United Kingdom", "London");
btree.insert("Taiwan", "Taipei");
btreeprintln!("{:?}", btree);
.remove("United Kingdom");
btreeprintln!("{:?}", btree);
{}
{"Germany": "Berlin", "Taiwan": "Taipei", "United Kingdom": "London"}
{"Germany": "Berlin", "Taiwan": "Taipei"}
Set form of HashMap
, meaning no duplicate keys are allowed.
use std::collections::HashSet;
let mut set = HashSet::new();
.insert("key");
set.insert("key");
setprintln!("{:?}", set);
{"key"}
Note how "key" is only present once, not twice.
Set form of BTreeMap
.
use std::collections::BTreeSet;
let set: BTreeSet<u32> = BTreeSet::new();
A struct contains fields. Access value by dot notation.
#[derive(Debug)]
struct User {
: bool,
active: String,
username: String,
email: u64,
sign_in_count}
let mut user1 = User {
: String::from("[email protected]"),
email: String::from("someusername123"),
username: true,
active: 1,
sign_in_count};
println!("{:?}", user1);
println!("{:?}", user1.email);
.email = String::from("[email protected]");
user1println!("{:?}", user1.email);
User { active: true, username: "someusername123", email: "[email protected]", sign_in_count: 1 }
"[email protected]"
"[email protected]"
#[derive(Debug)]
struct User {
: bool,
active: String,
username: String,
email: u64,
sign_in_count}
let email = String::from("[email protected]");
let username = String::from("[email protected]");
let mut user1 = User {
, // instead of email: email,
email, // instead of: username: username,
username: true,
active: 1,
sign_in_count};
println!("{:?}", user1);
User { active: true, username: "[email protected]", email: "[email protected]", sign_in_count: 1 }
#[derive(Debug)]
struct User {
: bool,
active: String,
username: String,
email: u64,
sign_in_count}
let user1 = User {
: String::from("[email protected]"),
email: String::from("someusername123"),
username: true,
active: 1,
sign_in_count};
let user2 = User {
: String::from("[email protected]"),
email..user1
};
println!("{:?}", user2);
User { active: true, username: "someusername123", email: "[email protected]", sign_in_count: 1 }
struct Rectangle {
: u32,
width: u32,
height}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
let rect1 = Rectangle {
: 30,
width: 50,
height};
println!("{:}", rect1.area());
1500
fn sum(x: i32, y: i32) -> i32 {
return x + y;
}
if sum(4, 5) > 10 {
println!("This is impossible");
} else if sum(4, 5) == 9 {
println!("This is correct");
} else {
println!("This is impossible");
}
This is correct
let x = if true { 1 } else { 0 };
println!("{}", x);
1
let mut counter = 0;
loop {
if counter == 5 {
break;
}
+= 1;
counter println!("(:");
}
(:
(:
(:
(:
(:
Loops can return a value by providing it to the break
keyword:
let mut counter = 0;
let nth = loop {
if counter == 5 {
break counter;
}
+= 1;
counter };
println!("Loop has been executed {nth} times");
Loop has been executed 5 times
By default, break
applies to the innermost loop. You can specify a loop label to break a specific loop.
let mut count_one = 0;
let mut count_two = 10;
'loop_one: loop {
println!("count_one = {count_one}");
loop {
println!("count_two = {count_two}");
if count_two == 0 {
break;
}
if count_two == 5 {
break 'loop_one;
}
-= 1;
count_two }
+= 1;
count_one }
count_one = 0
count_two = 10
count_two = 9
count_two = 8
count_two = 7
count_two = 6
count_two = 5
let mut number = 0;
while number != 6 {
println!("{number}");
+= 1;
number }
0
1
2
3
4
5
Since Rust 1.23, no need to call .iter()
fn main() {
for i in [1, 2, 3] {
println!("{}", i);
}
}
1
2
3
https://doc.rust-lang.org/std/iter/trait.Iterator.html
for i in (0..4).rev() {
println!("{i}");
}
3
2
1
0
println!("{}", [1, 2, 3].iter().min().unwrap());
1
println!("{}", [1, 2, 3].iter().max().unwrap());
3
println!("{}", [1, 3, 5].last().unwrap());
5
println!("{:?}", [1, 3, 5].map(|x| 2 * x));
[2, 6, 10]
1..20).filter(|x| x % 3 == 0).for_each(|i| println!("{}", i)); (
3
6
9
12
15
18
let a = [1, 2, 3];
let sum = a.iter().fold(0, |acc, x| acc + x);
println!("{}", sum);
6
Naming conventions: https://doc.rust-lang.org/1.0.0/style/style/naming/README.html
No garbage collection: have to manage memory yourself
Pattern matching through match
:)
https://yew.rs/docs/intro/ http://www.sheshbabu.com/posts/rust-wasm-yew-single-page-application/
Yew is a modern Rust framework for creating multi-threaded front-end web apps using WebAssembly.
https://github.com/ivanceras/sauron
Sauron is a versatile web framework and library for building client-side and/or server-side web applications with strong focus on simplicity. It is suited for developing web application which uses progressive rendering.
A cross-platform GUI library for Rust, inspired by Elm
https://github.com/poem-web/poem
A full-featured and easy-to-use web framework with the Rust programming language.
https://github.com/Wulf/create-rust-app
Set up a modern rust+react web app by running one command.
https://github.com/leptos-rs/leptos
Leptos is a full-stack, isomorphic Rust web framework leveraging fine-grained reactivity to build declarative user interfaces.
https://sycamore-rs.netlify.app/
A reactive library for creating web apps in Rust and WebAssembly
axohtml
(type-checked JSX for Rust) https://github.com/axodotdev/axohtml