Rust
Why do you care about Rust? Who has the time to learn all these new languages? It seems like a new one is popping up every other week and this trend is growing at an exponential rate. Good news, a fair number of them are crafted really well and efficiently solve specific problems. Bad news, how do you keep up with all of this, let alone decide which languages to include in your companies technology portfolio.
Despite the challenges of all these new languages, a majority of developers are intrigued about the idea of becoming a polyglot, but don't know where to begin or don't have the time. In my polyglot travels, there is one language of late that is the sure-fire answer to the above questions, Rust.
In this talk I’ll explore the value behind becoming more polyglotic as a developer, how to pick languages to learn, and then dive deep in the the language of Rust. Which in my opinion, is hands down the best up and coming languages to learn.
About the Presenter
Anthony Broad-Crawford has been a developer since the year 2000 with a short side stint as a semi-professional poker player. Since his transition to software development Anthony has...
1. Built 8 patent receiving technologies
2. Founded two global companies
3. Been a CTO (3x), CPO (1x), and CEO (1x)
and is currently the CTO at Fooda where he manages product, user experience, and engineering. Fooda is predominantly web and mobile technology company focused on bringing great & healthy food from the best restaurant's to people while at the office.
Through his career, in production applications Anthony has used Ruby, Java, Jave (Android), Objective-C and Swift, .NET, Erlang, Scala, Node.JS, LISP, Smalltalk, and even assembly, with his recent favorite, Rust . No, not all at the same time in the same application.
Anthony now spends his time building great teams, that leverage great technology, to build great products, but still looks to codes every chance he can get :)
12. Using cargo to create projects
Rust's package manager
Usage:
cargo <command> [<args>...]
cargo [options]
Options:
-h, --help Display this message
-V, --version Print version info and exit
--list List installed commands
-v, --verbose Use verbose output
Some common cargo commands are:
build Compile the current project
clean Remove the target directory
doc Build this project's and its dependencies' documentation
new Create a new cargo project
run Build and execute src/main.rs
test Run the tests
bench Run the benchmarks
update Update dependencies listed in Cargo.lock
14. primatives
fn main() {
//integers
let i: i8 = 1; // i16, i32, i64, and i are available
//unsigned
let u: u8 = 2; // u16, u32, u64, and u are available
//floats
let f: f32 = 1.0; // f64 also available
//booleans
let b: bool = true; // false also available, duh
//string and characters
let c: char = 'a';
let s: &str = "hello world";
}
15. variable bindings
fn main() {
let x: int = 1; //explicitly declare type
let y = 2i; //type inference
let (a,b,c) = (1i,2i,3i); //variable declaration via patterns
let a = [1, 2, 3]; //array literals
let s = "hello"; //string literal
println!("*_^ x = {}, y = {}, a,b,c = {},{},{}", x,y,a,b,c);
}
//> Cargo run
//> *_^ x = 1, y = 2, a,b,c = 1,2,3
//
16. variable mutability
fn main() {
let x: int = 1;
x = 10;
println!("The value of x is {}", x);
}
//Cargo run
//error: re-assignment of immutable variable `x`
// x = 10;
// ^~~~~~~
17. variable mutability
fn main() {
let mut x: int = 1;
x = 10;
println!("The value of x is {}", x);
}
//Cargo run
//warning: value assigned to `x` is never read
// let mut x: int = 1;
// ^~~~~~~
18. The Rust compiler is SUPER helpful
fn main() {
let mut x: int = 1;
x = 10;
println!("The value of x is {}", x);
}
//Cargo run
//warning: value assigned to `x` is never read
// let mut x: int = 1;
// ^~~~~~~
19. stack vs. heap
fn main() {
let y: int = 1; //allocated on the stack
let x: Box<int> = Box::new(10); //allocated on the heap
println!("Heap {}, Stack {}", x, y);
}
//> Cargo run
//> Heap 10, Stack 1
//
20. heap allocation creates pointers
fn main() {
let x: Box<int> = box 10; //allocated on the heap
x = 11;
println!("The Heaps new value is {}, x");
}
//Cargo run
//error: mismatched types: expected `Box<int>`
// x = 11;
// ^~~~~~~
21. memory mutability
fn main() {
let x: Box<int> = box 10; //allocated on the heap
*x = 11;
println!("The Heaps new value is {}, x");
}
//Cargo run
//error: cannot assign to immutable dereference of `*x`
// x = 11;
// ^~~~~~~
22. memory mutability
fn main() {
let mut x: Box<int> = box 10; //allocated on the heap
*x = 11;
println!("The Heaps new value is {}, x");
}
//> Cargo run
//> The Heaps new value is 11
//
23. compiler protects you by owning de-allocation
fn main() {
let mut x: Box<int> = box::new(10); //allocated on the heap
*x = 11;
println!("The Heaps new value is {}, x");
//Scope for x ends here so the compiler adds the de-allocation
//free(x);
}
//> Cargo run
//> The Heaps new value is 11
//
24. There is no garbage
collection in Rust. The
compiler observes the
lifetime of a variable and
de-allocates it where it is
no longer used.
26. borrowing
fn main() {
// x is the owner of the integer, which is memory on the stack.
let x = 5;
// you may lend that resource to as many borrowers as you like
let y = &x;
let z = &x;
// functions can borrow too!
foo(&x);
// we can do this alllllll day!
let a = &x;
}
27. ownership is singular
fn main() {
let mut x = 5;
let y = &mut x; //mutability only allows one borrower
let z = &mut x; // ... no go
}
//> Cargo build
//> error: cannot borrow `x` as mutable more than once at a time
// let z = &mut x;
// ^~~~~~~~~~~~~~~
28. ownership can be transferred
fn main() {
let x: Box<i32> = Box::new(5);
let y = add_one(x);
println!("{}", y);
}
fn add_one(mut num: Box<i32>) -> Box<i32> {
*num += 1;
num
}
//> Cargo run
//> 6
//
29. ownership can be transferred back
fn main() {
let mut x: Box<i32> = Box::new(5);
x = add_one(x);
println!("{}", x);
}
fn add_one(mut num: Box<i32>) -> Box<i32> {
*num += 1;
num
}
//> Cargo run
//> 6
//
30. now THAT sums to to the
promised memory safety
and data race prevention
32. pattern matching
fn main() {
let x = 5;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
4 => println!("four"),
5 => println!("five"),
_ => println!("something else"),
}
}
33. pattern matching
fn main() {
let x = 5;
match x {
1 | 2 => println!("one or two"),
3 => println!("three"),
4 ... 7 => println!("4 through 7"),
_ => println!("anything"),
}
}
34. pattern matching
fn main(){
struct Point {
x: i32,
y: i32,
}
let origin = Point { x: 0, y: 0 };
match origin {
Point { x: x, .. } => println!("x is {}", x),
}
}
//> Cargo run
//> x is 0
//
35. iterators & adapters
fn main(){
for i in range(1i, 10i).filter(|&x| x % 2 == 0) {
println!("{}", i);
}
}
//> Cargo run
//> 2
//> 4
//> 6
//> 8
36. functions
//a function that takes and integer and returns an integer
fn add_one(x: i32) -> i32 {
x + 1
}
fn main(){
println!("1 plus 1 is {}", add_one(1));
}
//> Cargo run
//> 1 plus 1 is 2
//
37. closures
fn main() {
let add_one = |x| { 1 + x };
println!("The sum of 5 plus 1 is {}.", add_one(5));
}
//> Cargo run
//> The sum of 5 plus 1 is 6.
//
38. closures can be passed as params
//Generic function that takes a closure as an argument
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
f(x) + f(x)
}
fn main() {
let result = twice(5, |x: i32| { x * x });
println!("And we have .... {}", result);
}
//> Cargo run
//> And we have .... 50
//
39. traits
struct Circle {
x: f64,
y: f64,
radius: f64,
}
trait HasArea {
fn area(&self) -> f64;
}
impl HasArea for Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}
fn main() {
let c = Circle {x:0.0, y:1.0, radius: 2.0};
println!("The circles's radious is {}", c.area());
}
40. traits with generics
trait HasArea {
fn area(&self) -> f64;
}
fn print_area<T: HasArea>(shape: T) {
println!("This shape has an area of {}", shape.area());
}
fn main() {
let c = Circle {x:0.0, y:1.0, radius: 2.0};
print_area(c);
}
//> Cargo run
//> This shape has an area of 12.566371
//
43. concurrency and ownership
fn print_message(){
println!("Hello from within a thread!");
}
fn main() {
let x: int = 5;
spawn(move || print_message);
x = 10;
}
//> Cargo run
//> error: re-assignment of immutable variable `x`
// x = 10;
// ^~~~~~~
47. testing an expected failure
#[test]
#[should_fail]
fn adding_one(){
let expected: int = 5;
let actual: int = 4;
assert_eq!(expected,actual);
}
//> Cargo Test
//> running 1 tests
//> test adding_one ... OK
//
48. making it pass
#[test]
fn adding_one(){
let expected: int = 5;
let actual: int = 5;
assert_eq!(expected,actual);
}
//> Cargo Test
//> running 1 tests
//> test adding_one ... OK
//
49. benchmark tests
#[bench]
fn bench_add_two(b: &mut Bencher) {
let add_one = |x| { 1 + x };
b.iter(|| add_one(2));
}
//> Cargo Test
//> running 1 tests
//> test tests::bench_add_two ... bench: 1 ns/iter (+/- 0)
//> test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
//
50. As promised Rust
1. guarantees memory safety
2. threads without dataraces
3. zero-cost abstractions (done at compile time)
4. trait-based generics
5. pattern matching
6. type inference
7. & more