16/12/2022
Loïc BRANSTETT
loic.branstett@epitech.eu
60 minutes for the basics
(mostly)
feel free to ask questions
Rust?
Reliable
Performant
Productive
(no memory mis-use)
(think C++)
(think 🤖)
Rust's path?
Control vs. Safety
CONTROL
SAFETY
C
C++
Go
Python
Java
PHP
Haskell
Rust
C#
This Dark Magic
Ownership and Borrowing
Explaining your intent at compile-time
Immutability
Concept #1
let x = 5;
let x = 5;
x = 2;
error[E0384]: cannot assign twice to immutable variable `x`
--> src/main.rs:3:5
|
2 | let x = 5;
| -
| |
| first assignment to `x`
| help: consider making this binding mutable: `mut x`
3 | x = 2;
| ^^^^^ cannot assign twice to immutable variable
Immutability
Concept #1
let mut x = 5;
x = 2;
⚠️️ Immutability != Constant ⚠️
Concept #2
Everything is expressions
let my_integer = { 5 };
let my_complex_algorthim = {
let c = 20 + 2;
c + 20
};
{ }
Concept #3
Shadowing
let x = 5; // 1st declaration
let x = 5 + x; // 2nd declaration
// In a CLI or web-app, one could do something like this
let age = app.get("age"); // age is a String
let age: i32 = age.parse().expect("unbale to convert to i32");
Concept #3
Shadowing
let mut espaces = " ";
// try to assign a integer to a string.
// will not work because the type are different.
espaces = espaces.len();
let espaces = " ";
let espaces = espaces.len();
Concept #4
Ownership
Concept #4
Ownership
- Each value in Rust has an owner.
- There can only be one owner at a time.
- When the owner goes out of scope, the value will be dropped.
Concept #4
Ownership
- Each value in Rust has an owner.
let a = 5; // here 5 is owned by `a`
5; // here 5 is owned by an anonymous variable
let _anon_5 = 5;
Concept #4
Ownership
- There can only be one owner at a time.
let a = 5;
let b = a;
println!("{a}"); // error: a no longer exist, it's value is now owned by b
println!("{b}"); // no problem
Concept #4
Ownership
- When the owner goes out of scope, the value will be dropped.
{
let a = 5;
}
// in reality
{
let a = 5;
drop(a);
}
Concept #5
Borrowing
Concept #5
Borrowing
🎉 References 🎉
&
&mut
Concept #5
Borrowing
let a = 5;
let b = &a;
println!("{b}");
let mut a = 5;
let b = &mut a;
println!("{b}");
Concept #5
Borrowing
let a = 5;
let b = &a;
let c = &a;
println!("{a} {b} {c}");
Concept #5
Borrowing
let mut a = 5;
let b = &mut a;
let c = &mut a;
println!("{a} {b} {c}");
error[E0499]: cannot borrow `a` as mutable more than once at a time
--> src/main.rs:4:9
|
3 | let b = &mut a;
| ------ first mutable borrow occurs here
4 | let c = &mut a;
| ^^^^^^ second mutable borrow occurs here
5 |
6 | println!("{a} {b} {c}");
| - first borrow later used here
Concept #5
Borrowing
&
&mut
&
&
&
&
XOR
Abbrev #1
Function
fn my_function(x: i32) -> i32 {
x + 2
}
fn my_print_int(x: i32) {
println!("{x}");
}
Concept #6
Lifetimes
fn dangle() -> &i32 {
let s = 15;
&s
}
fn dangle() -> &i32 { // dangle returns a reference to a i32
let s = 15; // s is a new integer
&s // we return a reference to the i32, s
} // Here, s goes out of scope, and is dropped.
// Its memory goes away.
// Danger!
Concept #6
Lifetimes
fn ref(x: &i32) -> &i32 {
x
}
fn ref_explicit<'a>(x: &'a i32) -> &'a i32 {
a
}
'something
It's time for
kahoot.it
Data types
Signed integer
Type | Min | Max |
---|---|---|
i8 | -128 | 127 |
i16 | -32_768 | 32_767 |
i32 | -2_147_483_64 | 2_147_483_63 |
i64 | -9_223_372_036_854_775_808 or -2^63 | 9_223_372_036_854_775_807 or 2^63-1 |
i128 | -170_141_183_460_469_231_731_687_303_715_884_105_728 or -2^127 | 170_141_183_460_469_231_731_687_303_715_884_105_727 or 2^127-1 |
Data types
Unsigned integer
Type | Min | Max |
---|---|---|
u8 | 0 | 255 |
u16 | 0 | 65_535 |
u32 | 0 | 4_294_967_295 |
u64 | 0 | 18_446_744_073_709_551_615 or 2^64-1 |
u128 | 0 | 340_282_366_920_938_463_463_374_607_431_768_211_455 or 2^128-1 |
Abbrev #2
overflow
fn main() {
let a: i8 = 128; // ERROR: overflow
}
error: literal out of range for `i8`
--> test.rs:2:16
|
2 | let a: i8 = 128;
| ^^^
|
= note: `#[deny(overflowing_literals)]` on by default
= note: the literal `128` does not fit into the type `i8` whose range is `-128..=127`
error: aborting due to previous error
Abbrev #3
gcc madness
#include <stdint.h>
int main(void) {
int8_t a = 128; // int8_t signed on 8bits
return 0;
}
$ gcc -Wall -Wextra
⚠️ No warnings !!! ⚠️
Abbrev #3
gcc madness
$ gcc -Wall -Wextra -Wstrict-overflow -Wconversion test.c
test.c: In function ‘main’:
test.c:5:14: warning: conversion from ‘int’ to ‘int8_t’ {aka ‘signed char’} changes value from ‘128’ to ‘-128’ [-Wconversion]
5 | int8_t a = 128;
| ^~~
Data types
Floating point numbers
f32 and f64
pub const PI: f32 = 3.14159274f32;
pub const PI: f32 = 3.14159274_f32;
Data types
Boolean
Simply bool! With true/false;
/// Returns `true` if `temperature` less or equal to 30°C
/// and greater than 19°C.
fn is_temperature_ok_for_working(temperature: i32) -> bool {
temperature < 30 && temperature >= 19
}
Data types
Boolean
️But remember:
⚠️ no implicit conversion! ⚠️
let a = if 5 { '👻' } else { '🦀' };
error[E0308]: mismatched types
--> test.rs:2:16
|
2 | let a = if 5 { '👻' } else { '🦀' };
| ^ expected `bool`, found integer
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
Data types
Character
char!
but size_of::<char>() = 32
char = Unicode Scalar Point
it's complicated, there is no one thruth defintion of what a character is, so Rust just used the closest avalaible thing
Data types
Tuple
(), (T1), (T1, T2) or (T1, T2, ...)
let a = ('🤖', 3i32); // tuple of (char, i32)
let c = (); // empty type () aka unit type
Function without return type explicitly return a unit! 🤖
Data types
String
&str
Borrowed variant
Owned variant
or String
Data types
Option<T>
pub enum Option<T> {
None,
Some(T),
}
Data types
Option<T>
fn is_power_of_two(x: u32) -> Option<u32> {
if x & 1 == 0 {
Some(x)
} else {
None
}
}
Data types
Result<T, E>
pub enum Result<T, E> {
Ok(T),
Err(E),
}
Data types
&[T] / slice
let a = [1, 2, 3, 4, 5]; // array
let slice = &a[1..3]; // slice
assert_eq!(slice, &[2, 3]);
Reference to a contiguous sequence of elements
Data types
Vec
let mut a = Vec::new(); // vec
a.extend([1, 2, 3, 4, 5]);
let slice = &a[1..3]; // slice
assert_eq!(slice, &[2, 3]);
(Owned) Contiguous sequence of elements
Custom type
Struct
pub struct MyStruct {
x: i32,
yz: (i32, i64),
pub(crate) print: Option<bool>
}
fn my_struct() -> MyStruct {
let x = 5;
MyStruct { x, yz: (1, 2), print: Some(true) }
}
Custom type
Enum
pub enum MyEnum {
Hugo,
Julien,
Parot
}
pub fn my_enum() -> MyEnum {
MyEnum::Julien
}
use MyEnum::Julien;
pub fn my_enum_2() -> MyEnum {
Julien
}
Custom type
Enum
ADT (Algebric Data Type)
enum MyEnum {
None,
X(i32),
YZ { x: i32, z: i32 },
Other(MyStruct)
}
If/else
Control flow
if my_condition {
// my code
} else if my_other_condition {
// my other code
} else {
// last resort, right?
}
If let
Control flow
let a = Some(...);
if a = ? { ... }
let a = Some(...);
if let Some(e) = a {
println!("{e}");
}
Control flow
Match
let a = Some(...);
match a {
Some(a) => dbg!(a),
None => eprintln!("nothing"),
}
Control flow
let/else
let a = Some(5);
// ...
let Some(a) = a else {
panic!("nothing!");
}
eprintln!("something!");
Control flow
return
fn my_int(a: i32) -> i32 {
if a < 100 {
return 1;
}
return a;
}
Looping
while
while my_condition {
// in code
}
while my_int != 5 {
println!("not equal to 5");
}
Looping
loop
while true {
println!("looping...");
}
loop {
println!("looping...");
}
Looping
for
for val in iterator {
// ...
}
for a in &[1, 2, 3, 4, 5] {
dbg!(a);
}
let v = vec![1, 2, 3];
for a in &v {
dbg!(a);
}
(part 2)
It's time for
Tools
Cargo
Package manager
Build system
$ cargo check
$ cargo build
$ cargo run
// Cargo.toml
[package]
name = "my_package"
version = "0.1.0"
[dependencies]
serde = "1.0"
clap = "1.0.15"
Tools
rustfmt
$ cargo fmt
// or directly
$ rustfmt main.rs
Formatter of Rust code
Rust Style guidelines
Tools
rustdoc
Automatic documentation generator from source code
with doc-comment
/// This is a doc-comment
///
/// # It's markdown
///
/// It's also different from comment
/// because it has 3 slash
// this isn't a doc-comment
fn my_function() {}
Tools
rust-analyzer
Language Server Protocol
Ressources
Rust Book
RustLings
Rust By Exemple
Rust Standard Library
Questions?
Iterator
Definition
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// ...
}
Iterator
Combination
trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
fn count(self) -> usize { ... }
fn last(self) -> Option<Self::Item> { ... }
fn nth(&mut self, n: usize) -> Option<Self::Item> { ... }
fn step_by(self, step: usize) -> StepBy<Self>ⓘ { ... }
fn skip(self, n: usize) -> Skip<Self>ⓘ { ... }
fn take(self, n: usize) -> Take<Self>ⓘ { ... }
// ...
}
Iterator
Exemple
let v = vec![1, 2, 3, 4, 5];
for a in v.iter()
.filter(|a| a < 2)
.nth(3)
{
dbg!(a);
}
// will print: 2, 3, 4
Rust Basics
By urgau-1
Rust Basics
- 105