Share
Embed
Intro to Rust Programming Language
Rust is a systems programming language focused on three goals: safety, speed, and concurrency. In this talk, you will get a high-level overview of the language, its syntax and semantics, and some code examples.
Rida Al Barazi
February 25, 2016
Transcript
88 slides
-
Rust is a systems programming language focused on three goals:
safety, speed, and concurrency Source: rust-lang.org What is rust -
Why and when? • Embedding in other languages • Writing
low-level code • Small programs with specific space and time requirements -
Installation 1.6.0 is the latest major release Came out on
January 21, 2016 Install your system package from: https://www.rust-lang.org/downloads.html -
cargo ! cargo run Compiling hello_world v0.1.0 (file:///home/yourname/projects/ hello_world) Running
`target/debug/hello_world` Hello, world! -
Adding dependencies cargo.toml [package] name = "hello_world" version = "0.1.0"
authors = ["Your name <[email protected]>”] [dependencies] rand="0.3.0" -
dependencies versions [dependencies] rand="0.3.0" # This a shorthand for ^0.3.0
rand=“^0.3.0" # Use any release compatible with this specific version. Semantic Versioning rand=“=0.3.0" # Use only 0.3.0 exactly rand=“*" # Use latest version -
dependencies versions ! cargo build Downloading libc v0.2.7 Downloading rand
v0.3.14 Compiling libc v0.2.7 Compiling rand v0.3.14 Compiling hello_world v0.1.0 (file:/// home/yourname/projects/hello_world) -
variable binding let x = 5; // Type inferred as
i32 let x: i32 = 5; // Explicitly bind with the type i32 -
variable binding let x = 5; // Type inferred as
i32 let x: i32 = 5; // Explicitly bound with the type i32 let (x, y) = (1, 2); // Pattern matching -
variable binding let x = 5; // Type inferred as
i32 let x: i32 = 5; // Explicitly bound with the type i32 let (x, y) = (1, 2); // Pattern matching y = 3; // Raises an error. Immutable by default let mut y = 3; // y is now mutable and is bound to 3 -
scoping and shadowing let x: i32 = 8; { println!("{}",
x); // Prints "8" let x = 12; println!("{}", x); // Prints "12" } println!("{}", x); // Prints "8" let x = 42; println!("{}", x); // Prints "42" -
numeric types let x = 42; // x has type
i32 let y = 1.0; // y has type f64 -
numeric types i8 i16 i32 i64 isize u8 u16 u32
u64 usize f32 f64 -
arrays let a = [1, 2, 3]; // a: [i32;
3] let mut m = [1, 2, 3]; // m: [i32; 3] -
arrays let a = [1, 2, 3]; // a: [i32;
3] let mut m = [1, 2, 3]; // m: [i32; 3] // Arrays have type [T; N] let a = [0; 20]; // a: [i32; 20] -
arrays let a = [1, 2, 3]; // a: [i32;
3] let mut m = [1, 2, 3]; // m: [i32; 3] // Arrays have type [T; N] let a = [0; 20]; // a: [i32; 20] // Get the length println!("a has {} elements", a.len()); //> a has 20 elements -
arrays let a = [1, 2, 3]; // a: [i32;
3] let mut m = [1, 2, 3]; // m: [i32; 3] // Arrays have type [T; N] let a = [0; 20]; // a: [i32; 20] // The `len` method yields the size of the array println!("a has {} elements", a.len()); //> a has 20 elements let names = ["Graydon", "Brian", "Niko"]; // names: [&str; 3] println!("The second name is: {}", names[1]); //> The second name is: Brian -
tuples let tuple = (1, "hello", "world"); // x: (i32,
&str, &str) // Indexing let v = tuple.1; println!("v is {}", v); // v is hello -
tuples let tuple = (1, "hello", "world"); // x: (i32,
&str, &str) // Indexing let v = tuple.1; println!("v is {}", v); // v is hello // Deconstructing let (x, y, z) = (1, 2, 3); println!("x is {}", x); // x is 1 -
structs struct Point { x: i32, y: i32, } fn
main() { let mut point = Point { x: 0, y: 0 }; point.x = 5; println!("The point is at ({}, {})", point.x, point.y); let point = point; // this new binding can’t change now point.y = 6; // this causes an error } -
structs // Tuple Struct struct Inches(i32); let length = Inches(10);
let Inches(integer_length) = length; println!("length is {} inches", integer_length); //> length is 10 inches // Unit-like Struct struct Electron; let x = Electron; // Empty tuple: () -
enums enum Message { // An `enum` may either be
`unit-like`, Quit, // like tuple structs, ChangeColor(i32, i32, i32), // or like structures. Move { x: i32, y: i32 }, Write(String), } let m: Message = Message::Write("Hello, world".to_string()); -
functions fn foo(x: i32) -> i32 { x } let
x: fn(i32) -> i32 = foo; -
operators // Integer addition println!("1 + 2 = {}", 1
+ 2); // Integer subtraction println!("1 - 2 = {}", 1 - 2); -
operators // Integer addition println!("1 + 2 = {}", 1
+ 2); // Integer subtraction println!("1 - 2 = {}", 1 - 2); // Short-circuiting boolean logic println!("true AND false is {}", true && false); println!("true OR false is {}", true || false); println!("NOT true is {}", !true); -
operators // Integer addition println!("1 + 2 = {}", 1
+ 2); // Integer subtraction println!("1 - 2 = {}", 1 - 2); // Short-circuiting boolean logic println!("true AND false is {}", true && false); println!("true OR false is {}", true || false); println!("NOT true is {}", !true); // Use underscores to improve readability! println!("One million is written as {}", 1_000_000); -
GENERIC FUNCTIONS fn takes_anything<T>(x: T) { // do something with
x } fn takes_two_things<T, U>(x: T, y: U) { // ... } -
GENERIC STRUCTS struct Point<T> { x: T, y: T, }
let int_origin = Point { x: 0, y: 0 }; let float_origin = Point { x: 0.0, y: 0.0 }; -
vectors // The `vec!` macro can be used to initialize
a vector let mut v = vec![1, 2, 3, 4, 5]; // v: Vec<i32> -
vectors // The `vec!` macro can be used to initialize
a vector let mut v = vec![1, 2, 3, 4, 5]; // v: Vec<i32> v.push(4); // Insert new element at the end of the vector -
vectors // The `vec!` macro can be used to initialize
a vector let mut v = vec![1, 2, 3, 4, 5]; // v: Vec<i32> v.push(4); // Insert new element at the end of the vector // The `len` method yields the current size of the vector println!("Vector size: {}", v.len()); //> Vector size: 6 println!("Sixth element: {}", v[5]); //> Sixth element: 4 -
strings // &str let greeting = "Hello there."; // greeting:
&'static str = &str // String let mut s = "Hello".to_string(); // mut s: String println!("{}", s); //> "Hello" s.push_str(", world."); println!("{}", s); //> "Hello, World" -
strings • They are a sequence of UTF-8 bytes. •
&str is a string slice. • String is a growable string. • "Hello there" is statically allocated string literal, typed string slice. • str.to_string() creates a new String, which is expensive. • string.as_slice() returns a view of the string, which is cheap. -
if let x = 5; if x == 5 {
println!("x is five!"); } else if x == 6 { println!("x is six!"); } else { println!("x is not five or six :("); } -
if let x = 5; if x == 5 {
println!("x is five!"); } else if x == 6 { println!("x is six!"); } else { println!("x is not five or six :("); } let y = if x == 5 { 10 } else { 15 }; // y: i32 -
loops loop { println!("Loop forever!"); } let mut x =
5; loop { x += x - 3; println!("{}", x); if x % 5 == 0 { break; } } -
loops let mut x = 5; // mut x: i32
let mut done = false; // mut done: bool while !done { x += x - 3; println!("{}", x); if x % 5 == 0 { done = true; } } -
loops for x in 0..10 { println!("{}", x); // x:
i32 } for (idx,j) in (5..10).enumerate() { println!("idx = {} and j = {}", i, j); } // idx = 0 and j = 5 // idx = 1 and j = 6 // idx = 2 and j = 7 // idx = 3 and j = 8 // idx = 4 and j = 9 -
loops 'outer: for x in 0..10 { 'inner: for y
in 0..10 { if x % 2 == 0 { continue 'outer; } // continues the loop over x if y % 2 == 0 { continue 'inner; } // continues the loop over y println!("x: {}, y: {}", x, y); } } -
match let x = 5; match x { 1 =>
println!("one"), 2 => println!("two"), 3 => println!("three"), 4 => println!("four"), 5 => println!("five"), _ => println!("something else"), } -
match enum Message { Quit, ChangeColor(i32, i32, i32), Move {
x: i32, y: i32 }, Write(String), } fn quit() { /* ... */ } fn change_color(r: i32, g: i32, b: i32) { /* ... */ } fn move_cursor(x: i32, y: i32) { /* ... */ } fn process_message(msg: Message) { match msg { Message::Quit => quit(), Message::ChangeColor(r, g, b) => change_color(r, g, b), Message::Move { x: x, y: y } => move_cursor(x, y), Message::Write(s) => println!("{}", s), }; } -
functions fn main() { let x = 5; print_sum(add_one(x), 6);
// sum is: 12 } fn print_sum(x: i32, y: i32) { println!("sum is: {}", x + y); } fn add_one(x: i32) -> i32 { x + 1 // note that there's no semicolon = `return` } -
methods To call a method on an struct instance like:
`circle.area()`, you have to use `impl` and declare functions that accept a variant of `self`, `&self`, or `&mut self` as their first parameter. -
methods struct Circle { x: f64, y: f64, radius: f64,
} impl Circle { fn area(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) } } fn main() { let c = Circle { x: 0.0, y: 0.0, radius: 2.0 }; println!("{}", c.area()); } -
methods struct Circle { x: f64, y: f64, radius: f64,
} impl Circle { // new is an associated function fn new(x: f64, y: f64, radius: f64) -> Circle { Circle { x: x, y: y, radius: radius, } } } fn main() { let c = Circle::new(0.0, 0.0, 2.0); -
Methods Rust doesn’t have method overloading, named arguments, or variable
arguments. Instead you would use the Builder Pattern -
Methods struct Circle { x: f64, y: f64, radius: f64,
} impl Circle { fn area(&self) -> f64 { std::f64::consts::PI * (self.radius * self.radius) } } struct CircleBuilder { x: f64, y: f64, radius: f64, } -
Methods impl CircleBuilder { fn new() -> CircleBuilder { CircleBuilder
{ x: 0.0, y: 0.0, radius: 1.0, } } fn x(&mut self, coordinate: f64) -> &mut CircleBuilder { self.x = coordinate; self } fn y(&mut self, coordinate: f64) -> &mut CircleBuilder { self.y = coordinate; self } fn radius(&mut self, radius: f64) -> &mut CircleBuilder { self.radius = radius; self } fn finalize(&self) -> Circle { Circle { x: self.x, y: self.y, radius: self.radius } } } -
Methods fn main() { let c = CircleBuilder::new() .x(1.0) .y(2.0)
.radius(2.0) .finalize(); println!("area: {}", c.area()); println!("x: {}", c.x); println!("y: {}", c.y); } -
traits Similar to methods you can add functionality to structs
by specifying what Traits a struct implements. -
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) } } -
ownership let v = vec![1, 2, 3]; let v2 =
v; println!("v[0] is: {}", v[0]); // error: use of moved value: `v` -
ownership let v = 1; let v2 = v; println!("v
is: {}", v); // v is i32 which is a primitive. // All primitive types implement the `Copy` trait -
references and borrowing let v = vec![1, 2, 3]; let
v2 = &v; println!("v[0] is: {}", v[0]); // v[0] is: 1 println!("v2[1] is: {}", v2[1]); // v2[1] is: 2 -
references and borrowing let mut x = 5; { let
y = &mut x; *y += 1; } println!("{}", x); -
Syntax and style • Indentation is 4 spaces (no tabs)
• variable names are underscore lowercased • structs begin with a capital letter and are camel cased -
resources • The Rust Programming Language (online book) • https://doc.rust-lang.org/stable/book/
• Rust by Example • http://rustbyexample.com/index.html • Rust Cheat Sheet • http://clchiou.github.io/2015-01-09/rust- cheat-sheet/ • ConFreaks Rust Talks • http://confreaks.tv/tags/155