On Github bkircher / rust-pottcpp
Created by Kai / @_cibo_ and Ben / @predatorhat
fn main() { println!("Hello, there!"); }
Quite similar to C++. So why do we need another language?
Rust's type system!
void logError(const char* msg, int* ints) { fprintf(stderr, "%s: %i\n", msg, ints[0]); } int main() { int* ptr = (int*)malloc (SIZE); // ... if (err) { abrt = 1; free(ptr); } // ... if (abrt) { logError("operation aborted before commit", ptr); } }
To catch this in C or C++ you need
In Rust, lifetime is part of an object's type
fn main() { let x; { let y = 5; x = &y; } println!("x's value is {}", x); }
And thus, checked at compile time
Move by default: variables are moved to new locations, preventing previous locations from using it.
There is only one owner of data!
rustc hello_world.rs ./hello_world Hello, World!
foo.rs:
mod foo { fn hello_world() { println!("Hello, World!"); } mod bar { fn goodbye_world() { println!("Goodbye!"); } } }
foo::bar::goodbye_world();
main.rs:
mod foo; fn main() { foo::hello_world(); }
rustc main.rs
Compiles main.rs and foo.rs into main executable.
rustc --crate-type dylib foo.rs
main.rs:
extern crate foo; fn main() { foo::hello_world(); }
rustc main.rs
Compiles main.rs and links foo at run time.
cargo new --bin program_name
[package] name = "program_name" version = "0.0.1" authors = ["Kai Michaelis <kai.michaelis@rub.de>"] [dependencies] num = "~0.0.4" slow_primes = "~0.1.4"
Downloads all dependencies and builds everything
cargo build
Calling C from Rust and vice versa
Call Rust code directly from C or C++
#[no_mangle] pub extern fn hello_rust() -> *const u8 { "Hello, world!\0".as_ptr() }
Call C code from Rust also pretty easy
int sqlite3_open( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb /* OUT: SQLite db handle */ );
translates basically to
extern crate libc; use libc::c_int,c_char; #[link(name = "sqlite3")] extern { pub fn sqlite3_open(filename: *const c_char, ppDb: *mut *mut sqlite3) -> c_int; }
You wouldn't do this yourself all the way: there is bindgen
And of course, you wouldn't do this with sqlite3 because there is already crates.io/crates/rusqlite
struct Employee { name: String, age: u8, department: String }
let e1 = Employee { name: "Kai Michaelis".to_string(), age: 29, department: "Engineering".to_string() }; let Employee{ name: n, ..} = e1; // Prints "Hello, I'm Kai Michaelis" println!("Hello, I'm {}",n);
let e1 = Employee { name: "Kai Michaelis".to_string(), age: 29, department: "Engineering".to_string() }; if let Employee{ age: 67, ..} = e1 { println!("Time to retire!"); } else { println!("You still got {} years to go",67 - e1.age); }
#[derive(PartialEq)] enum Fruit { Apple = 1, Banana = 2, Kiwi, Pineapple }
fn say_it(fruit: Fruit) { match fruit { Fruit::Apple => println!("Apple"), Fruit::Kiwi => println!("Kiwi"), Fruit::Pineapple => println!("Pineapple"), } }
enum NumberOrText { Number(i32), Text(String) }
fn print_number_or_text(nt: NumberOrText) { match nt { NumberOrText::Number(i) => println!("Number: {}",i), NumberOrText::Text(t) => println!("Text: {}",t) } }
let a: NumberOrText = Number(42); let b: NumberOrText = Text("Hello, World".to_string()); // Prints "Number: 42" print_number_or_text(a); // Prints "Text: Hello, World" print_number_or_text(b);
use std::boxed::Box; use std::ops::Deref; enum Tree { Leaf(char), Node(Box<Tree>,Box<Tree>) } fn depth_first_search(root: &Tree) { match root { &Tree::Leaf(s) => println!("{}",s), &Tree::Node(ref left,ref right) => { depth_first_search(left.deref()); depth_first_search(right.deref()) } } }
fn main() { let tree = Box::new(Tree::Node( Box::new(Tree::Node( Box::new(Tree::Leaf('H')), Box::new(Tree::Node( Box::new(Tree::Leaf('e')), Box::new(Tree::Leaf('l')))))), Box::new(Tree::Node( Box::new(Tree::Node( Box::new(Tree::Leaf('l')), Box::new(Tree::Leaf('o')))), Box::new(Tree::Leaf('!')))))); // Prints "Hello!" depth_first_search(&tree); }
panic! unwinds the thread
fn guess(n: i32) -> bool { if n < 1 || n > 10 { panic!("Invalid number: {}", n); } n == 5 } fn main() { guess(11); }
enum Option<T> { None, Some(T), }
Option<T>
fn find(haystack: &str, needle: char) -> Option<usize> { for (offset, c) in haystack.char_indices() { if c == needle { return Some(offset); } } None } fn main() { let filename = "foobar.txt"; match find(filename, '.') { Some(i) => println!("Filename extension: {}", &filename[i+1..]), None => println!("No extension found!"), } }
Somewhat mixed...
Way better than arbitrary return values Seems harder to use than exceptions Anyone?