A Bite of RUST
> whoami
michele.damico@gmail.com
https://github.com/la10736
https://www.linkedin.com/in/damico/
@PhenoCoder

Perchè RUST?
- Pericolosi (non Type Safe)
- Muti-Threading difficile e Error prone
C/C++
Obiettivi di RUST
- Veloce
- Astrazzione a costo zero
- Accesso sicuro alla memoria (Type Safe)
- Vietare i Data-Race in compilazione
- Eliminare (il più possibile) i comportamenti indefiniti

Ecosistema
rustc
cargo
rustup
- crates.io


michele@DartVader:~/bite_of_rust$ cargo init hello --bin
Created binary (application) project
michele@DartVader:~/bite_of_rust$ cd hello/
michele@DartVader:~/bite_of_rust/hello$ cargo run
Compiling hello v0.1.0 (file:///home/michele/bite_of_rust/hello)
Finished dev [unoptimized + debuginfo] target(s) in 0.54 secs
Running `target/debug/hello`
Hello, world!
michele@DartVader:~/bite_of_rust/hello$ echo "
#[test]
fn ok() { assert!(true) }
#[test]
fn ko() { assert!(false) }
" >> src/main.rs
michele@DartVader:~/bite_of_rust/hello$ cargo test
Compiling hello v0.1.0 (file:///home/michele/bite_of_rust/hello)
Finished dev [unoptimized + debuginfo] target(s) in 0.37 secs
Running target/debug/deps/hello-e41301c0dacd96ed
running 2 tests
test ok ... ok
test ko ... FAILED
failures:
---- ko stdout ----
thread 'ko' panicked at 'assertion failed: false', src/main.rs:8
note: Run with `RUST_BACKTRACE=1` for a backtrace.
failures:
ko
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured
error: test failed
Alcune Caratteristiche
-
Variabili (move, copy, borrowing)
-
Ownership
-
Mutabilità per istanza
-
inferenza di tipo
- Gestione stringhe
-
Gestione memoria
-
....


Alcune Caratteristiche (Cont)
-
Enum ++(+)
-
Gestione Errori (no eccezioni)
- Derivano solo le interfacce
-
Generic (Trait) con bound
-
Destrutturazione (pattern)
-
Closure e First-Class functions
-
macro (hygenic)


Tutta questa fatica per...

my_list = [1, 3, 5, 7, 9]
for index, val in enumerate(my_list):
if val > 4:
del my_list[index]
print("Output: ")
print(my_list)
Output:
[1, 3, 7]

fn main() {
let mut my_vec = vec![1, 3, 5, 7, 9];
for (index, &val) in my_vec.iter().enumerate() {
if val > 4 {
my_vec.remove(index);
}
}
println!("Output:\n{:?}", my_vec);
}

... non compila ...
Compiling vspython_remove v0.1.0 (file:///home/michele/learning/rust/vspython_remove)
error[E0502]: cannot borrow `my_vec` as mutable because it is also borrowed as immutable
--> src/main.rs:5:13
|
3 | for (index, &val) in my_vec.iter().enumerate() {
| ------ immutable borrow occurs here
4 | if val > 4 {
5 | my_vec.remove(index);
| ^^^^^^ mutable borrow occurs here
6 | }
7 | }
| - immutable borrow ends here
error: aborting due to previous error
... dobbiamo fare i bravi!
fn main() {
let mut my_vec = vec![1, 3, 5, 7, 9];
my_vec = my_vec.into_iter().filter(|val| *val <= 4).collect();
println!("Output:\n{:?}", my_vec);
}
/home/michele/.cargo/bin/cargo run --color=always
Compiling vspython_remove v0.1.0 (file:///home/michele/learning/rust/vspython_remove)
Finished dev [unoptimized + debuginfo] target(s) in 0.49 secs
Running `target/debug/vspython_remove`
Output:
[1, 3]
Process finished with exit code 0

Thread safe?


import threading
import time
N = 10000
a = [0]
threads = []
def update():
v = a[0]
time.sleep(0)
a[0] = v + 1
for i in range(N):
t = threading.Thread(target=update)
t.start()
threads.append(t)
for t in threads:
t.join()
assert a[0] == N, "a = {} != N = {}".format(a[0], N)import kotlin.concurrent.thread
fun main(args : Array<String>) {
val N = 10000
var a = 0
val threads = (1..N).map {
thread { a += 1 }
}
threads.map { it.join() }
assert(a == N) {
"$a != $N"
}
}
Traceback (most recent call last):
File "/home/michele/learning/python/concurrent/concurrent.py", line 21, in <module>
assert a[0] == N, "a = {} != N = {}".format(a[0], N)
AssertionError: a = 9988 != N = 10000Exception in thread "main" java.lang.AssertionError: 9998 != 10000
at ConcurrentKt.main(concurrent.kt:11)E RUST?

use std::thread::spawn;
fn main() {
static N: usize = 10000;
let mut val = 0;
let r_val = &mut val;
let mut handlers: Vec<_> = Default::default();
for _ in 0..N {
handlers.push(spawn(|| {
*r_val += 1;
}
));
}
for h in handlers {
h.join().unwrap();
}
print!("Sum = {}", val);
assert_eq!(N, val);
} Compiling concurrent2 v0.1.0 (file:///home/michele/learning/rust/concurrent2)
error: `val` does not live long enough
--> src/main.rs:6:22
|
6 | let r_val = &mut val;
| ^^^ does not live long enough
...
20 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
error[E0373]: closure may outlive the current function, but it borrows `r_val`, which is owned by the current function
--> src/main.rs:10:29
|
10 | handlers.push(spawn(|| {
| ^^ may outlive borrowed value `r_val`
11 | *r_val += 1;
| ----- `r_val` is borrowed here
|
help: to force the closure to take ownership of `r_val` (and any other referenced variables), use the `move` keyword, as shown:
| handlers.push(spawn(move || {
error: aborting due to 2 previous errors
.... Si arrabbia un casino
Assecondiamo...

for _ in 0..N {
handlers.push(spawn(move || {
*r_val += 1;
}
));
}usiamo move come suggerito
Compiling concurrent2 v0.1.0 (file:///home/michele/learning/rust/concurrent2)
error: `val` does not live long enough
--> src/main.rs:6:22
|
6 | let r_val = &mut val;
| ^^^ does not live long enough
...
20 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
error[E0382]: capture of moved value: `r_val`
--> src/main.rs:11:14
|
10 | handlers.push(spawn(move || {
| ------- value moved (into closure) here
11 | *r_val += 1;
| ^^^^^ value captured here after move
|
= note: move occurs because `r_val` has type `&'static mut usize`, which does not implement the `Copy` trait
error: aborting due to 2 previous errors...Reference Counting?

use std::thread::spawn;
fn main() {
static N: usize = 10000;
let r_val = std::rc::Rc::new(0);
let mut handlers: Vec<_> = Default::default();
for _ in 0..N {
let r_val = r_val.clone();
handlers.push(spawn(move || {
*r_val += 1;
}
));
}
for h in handlers {
h.join().unwrap();
}
print!("Sum = {}", r_val);
assert_eq!(N, *r_val);
} Compiling concurrent2 v0.1.0 (file:///home/michele/learning/rust/concurrent2)
error[E0277]: the trait bound `std::rc::Rc<usize>: std::marker::Send` is not satisfied in
`[closure@src/main.rs:10:29: 12:10 r_val:std::rc::Rc<usize>]`
--> src/main.rs:10:23
|
10 | handlers.push(spawn(move || {
| ^^^^^ within `[closure@src/main.rs:10:29: 12:10 r_val:std::rc::Rc<usize>]`,
the trait `std::marker::Send` is not implemented for `std::rc::Rc<usize>`
|
= note: `std::rc::Rc<usize>` cannot be sent between threads safely
= note: required because it appears within the type `[closure@src/main.rs:10:29: 12:10 r_val:std::rc::Rc<usize>]`
= note: required by `std::thread::spawn`
error: aborting due to previous error
Rc non è thread safe :(
...Asincrono?

use std::thread::spawn;
fn main() {
static N: usize = 10000;
let r_val = std::sync::Arc::new(0);
let mut handlers: Vec<_> = Default::default();
for _ in 0..N {
let r_val = r_val.clone();
handlers.push(spawn(move || {
*r_val += 1;
}
));
}
for h in handlers {
h.join().unwrap();
}
print!("Sum = {}", r_val);
assert_eq!(N, *r_val);
} Compiling concurrent2 v0.1.0 (file:///home/michele/learning/rust/concurrent2)
error: cannot assign to immutable borrowed content
--> src/main.rs:11:13
|
11 | *r_val += 1;
| ^^^^^^^^^^^ cannot borrow as mutable
error: aborting due to previous error
Ci siamo quasi ma clone() torna un
valore non mutabile ....
Arc al posto di Rc ...
mut(able) o mut(ex) ?

use std::thread::spawn;
fn main() {
static N: usize = 10000;
let r_val = std::sync::Arc::new(std::sync::Mutex::new(0));
let mut handlers: Vec<_> = Default::default();
for _ in 0..N {
let r_val = r_val.clone();
handlers.push(spawn(move || {
let mut r_val = r_val.lock().unwrap();
*r_val += 1;
}
));
}
for h in handlers {
h.join().unwrap();
}
let result = r_val.lock().unwrap().clone();
print!("Sum = {}", result);
assert_eq!(N, result);
}Wrappiamo il valore con un mutex
Compiling concurrent2 v0.1.0 ......
Finished dev [unoptimized ...
Running `target/debug/concurrent2`
Sum = 10000
Process finished with exit code 0WOW!!!!!!!!!!!!!!
String Calculator Kata

Modulo string_calculator con funzione add():
prende una stringa e torna un intero.
add("") == 0
String Calculator Kata

Data una stringa contenente un intero torna il numero intero rappresentato
add("3") == 3
add("5") == 5
String Calculator Kata

Somma i numeri separati da virgola
add("1,2") == 3
add("1,2,3") == 6
String Calculator Kata

Accetta anche \n come separatore
add("1\n2") == 3
add("1,3\n2,12,1\n4\n3,1") == 27
String Calculator Kata

La prima riga può contenere un header che definisce un separatore diverso
//[delimiter]\n[numbers…]
add("//[;]\n1;2") == 3
add("//[;]\n1;2\n3;4\n7") == 17
String Calculator Kata

I numeri negativi non sono ammessi: Se presenti mostrare l'errore
“negatives not allowed: <negatives>”
add("-1") == Err("negatives not allowed: -1")
add("1,-3,4,-2") == Err("negatives not allowed: -3,-2")
GRAZIE!



Special Guests...


A Bite of Rust
By Michele D'Amico
A Bite of Rust
- 347