pub fn main() {
println!("Hello World!");
}mainis a functionprintln!is a macropubdeclares its scopemainis called by default in an executable|var| { func(var) }is a closure, and borrows its encolsed variables (eg.var)move |var| { func(var) }is a closure which takes ownership of its enclosed variables- Loops: Rust has the usual
forandwhileloops. But also you can justloopfor an infinite loop:
for i in 0..10 {
foo(i)
}
while do_thing {
foo(i)
}
loop {
foo(i)
}u8,i8- unsigned and signed 8 bit integers (also 16, 32, 64 and size)f32,f64- single / double precision floating point numberbool-trueorfalsechar- a Unicode Scalar Valuestr- A string slice, usually seen as &str, a reference to some UTF-8 data stored somewhere else. eg. &'static is stored in the binary output of the programString- 'Owned' string, which is often heap allocated(u8, u8),[u8]- Tuples and arrays- Structs and ADTs -
Option<T>,Result<T, E>
let a = 1, the current scope then 'owns'afunc(a)passes ownership ofato the scope offuncfunc(&a), in this case the scope offuncis 'borrowing'a, the current scope gets it back after the function completes- The type of ownership a funciton wants should be specified in the type signature too:
fn foo(val: Option<bool>)versusfn foo(val: &Option<bool>) func(&mut a)passes a 'mutable reference'. This allows modification of the valueaby the function. (Don't forget the type signature:fn foo(val: &mut Option<bool>))
let a = 1; a += 1;is invalid, asais immutable by defaultlet mut a = 1; a += 1;specifiesais mutablefunc(&mut a)passes a mutable reference tofunc
T(eg.let val = 1) is an 'Owned' value on the stack (possibly containing a heap object, eg.Vec)&T(eg&val) is a 'reference' to the value. Similar (but not the same) as a pointer in other languagesBox<T>,Rc<T>, are examples of Smart Pointers.Box<T>can be used for allocating on the Heap.RC<T>implementes reference counting
fn print_forever(a: &T) {
thread::spawn(move || loop { println!("a: {}", a) });
}This function will not work, as it is borrowing a for the 'lifetime' of the function scope.
However, this function scope creates a thread that may live forever, so the function scope may not "let go" of a.
This is a problem, because a could be some heap allocated memory which immediately gets freed.
(not real Rust!)
let value = heap_allocate("Print me forever");
print_forever(&value);
heap_free(value);What gets printed after the call to heap_free?
This is why Rust doesn't allow this.
To work around this, you can specify a lifetime requirement to the parameter with the 'lifetime syntax.
Ie. foo(a: &'l T).
In this case the 'static lifetime can be used, which requires that any a passed to this function lives as long as the execution of the program itself.
- Many functions will return
Result<T, E>, which has variants ofOk(T)andErr(E) - The result can be extracted with
.unwrap()orif let Ok(val)
Traits are how Rust allows generic code. Any struct can implement a trait, and a function can take a parameter of type 'Trait'.
Eg. The ToString trait defines the to_string() method, which must return a String.
For further reading, read The Rust Programming Language, and for advanced reading The Rustonomicon.