Link to slides: slides.com/sunjay/intro-to-rust
Talk Outline
- What is Rust?
- A Practical Introduction to Rust
- Advanced Features
- Concluding remarks & Resources
Link to slides: slides.com/sunjay/intro-to-rust
What is Rust?
Rust is a safe, productive, high-performance, and low-level programming language.
Rust is safe
- Automatic memory management without garbage collection
- Ownership and Borrowing
- Memory safe and with no data races!
- No more double frees, use-after-frees, dangling pointers, out-of-bounds accesses, or segfaults!
- Multithreaded programming without fear!
Rust is productive
- You can start writing production ready code in Rust today.
Rust is productive
- You can start writing production ready code in Rust today.
- Rust is designed to be a language that you actually use to write applications -- more than just an obscure research language
- The compiler can check a lot about your code. Just compiling a Rust program means that you have already avoiding a lot of potential bugs
- Rust gives you a lot of confidence to change and refactor your program, even after time has passed, because it checks all of those things every time
Rust is high-performance
- Just like C or C++, Rust gives you complete control
- Compile-time safety checks, correctness checks, and memory management decisions for zero runtime impact
- Automatic memory management without garbage collection
- Zero-cost abstractions so your code runs fast while being fun to write as well
Rust is low-level
- Low-level without some of the worst parts of being a low-level language
- Complete control without unnecessary burden
-
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
Rust is a safe, productive, high-performance, and low-level programming language.
A Practical Introduction to Rust
Tic-Tac-Toe
Example Source Code:
Variables
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
Functions
// 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
}
}
Common Rust Types
- Unsigned Integers: u8, u16, u32, u64, usize
- Signed Integers: i8, i16, i32, i64, isize
- Floating-point: f32, f64
- Boolean: bool (true and false)
- Character: char
- Strings: &str, or String (heap-allocated)
- Unit: ()
- Compound Types: Option<u32>, (i32, f64, &str), [i32; 5]
Creating a new project
To install Rust, go to: https://rustup.rs
Structs
struct Game {
tiles: [[Option<Piece>; 3]; 3], // Syntax: [Type; size]
current_piece: Piece,
winner: Option<Winner>,
}
Enums
enum Piece {
// Access these variants using `Piece::X` or `Piece::O`
X,
O,
}
enum Winner {
X,
O,
Tie,
}
Option
enum Option<T> {
Some(T),
None,
}
Result
enum Result<T, E> {
Ok(T),
Err(E),
}
For when there may or may not be a value
For when an operation might fail
Example: Result
// 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)
Ownership & Borrowing
The key to memory safety and no more data races
Ownership
- Each value in Rust has a variable that's called its owner.
- There can only be one owner at a time.
- When the owner goes out of scope, the value will be dropped.
Borrowing
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
References and Borrowing
`&` vs. `&mut`
- At any given time, you can have either but not both of:
- One mutable reference
- Any number of immutable references
- References must always be valid
Immutable Reference
(cannot modify anything)
Mutable Reference
(can modify things)
Advanced Features: Generics & Traits
Generics
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
}
Traits
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.
Tic-Tac-Toe
Example Source Code:
Rust Resources
- Learn Rust from scratch by drawing pictures
- No prior programming experience required
- Ready in a few weeks!
Turtle
Website: turtle.rs
Thank you!
An Introduction to Rust
By Sunjay Varma
An Introduction to Rust
This talk introduces the Rust programming language.
- 2,906