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?