Link to slides: slides.com/sunjay/intro-to-rust
Link to slides: slides.com/sunjay/intro-to-rust
unsafe allows you to tell the Rust compiler that you know better!
let mut num = 5;
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;
unsafe {
// Dereferencing raw pointers can be unsafe!
println!("r1 is: {}", *r1);
println!("r2 is: {}", *r2);
}
Example from the Rust book: Chapter 19 - Unsafe Rust
Example Source Code:
let x = 12;
let y = "Hello, world!";
// Type annotations are optional
let x: i32 = 12; // i32 = 32-bit integer
let y: &str = "Hello, world!"; // &str = string
// Though type annotations are not often required,
// functions must always be explicit about their types
fn max(x: i32, y: i32) -> i32 {
if x >= y {
x
}
else {
y
}
}
To install Rust, go to: https://rustup.rs
struct Game {
tiles: [[Option<Piece>; 3]; 3], // Syntax: [Type; size]
current_piece: Piece,
winner: Option<Winner>,
}
enum Piece {
// Access these variants using `Piece::X` or `Piece::O`
X,
O,
}
enum Winner {
X,
O,
Tie,
}
enum Option<T> {
Some(T),
None,
}
enum Result<T, E> {
Ok(T),
Err(E),
}
For when there may or may not be a value
For when an operation might fail
// Takes a string (e.g. "1c") and converts it into its position on the board (e.g. (0, 2))
fn parse_move(input: &str) -> Result<(usize, usize), InvalidMove> {
if input.len() != 2 {
return Err(InvalidMove(input.to_string()));
}
let row = match &input[0..1] {
"1" => 0,
"2" => 1,
"3" => 2,
_ => return Err(InvalidMove(input.to_string())),
};
let col = match &input[1..2] {
"A" | "a" => 0,
"B" | "b" => 1,
"C" | "c" => 2,
invalid => return Err(InvalidMove(invalid.to_string())),
};
Ok((row, col))
}
struct InvalidMove(String);
(0, 2)
The key to memory safety and no more data races
let x = "Hello, world!".to_string();
do_something(x);
println!("{}", x);
fn do_something(x: String) {
// ...
}
x is moved
let x = "Hello, world!".to_string();
do_something(&x);
println!("{}", x);
fn do_something(x: &String) {
// ...
}
x is borrowed
error[E0382]: use of moved value: `x`
--> src/main.rs:4:16
|
2 | do_something(x);
| - value moved here
3 | println!("{}", x);
| ^ value used here after move
|
It works!
moved to preserve "one owner" rule
Immutable Reference
(cannot modify anything)
Mutable Reference
(can modify things)
fn add<T>(x: T, y: T) -> T {
x + y
}
For when your code works for a variety of types
error[E0369]: binary operation `+` cannot be applied to type `T`
--> src/main.rs:2:5
|
2 | x + y
| ^^^^^
|
= note: `T` might need a bound for `std::ops::Add`
fn add<T: Add>(x: T, y: T) -> T {
x + y
}
For when you need to say more about your generics
* This example won't actually exactly compile as-is, but it is a good enough demonstration of the concept for our purposes.
Example Source Code: