🦀 Rust - Functions
Functions always have a fixed number of parameters. Macros can take a variable number of parameters if you really need that e.g. format!().
Not ending your code block with ; will return the result of that block.
fn number() -> i32 {
8
}
fn number() -> i32 {
return 8;
}
It is common to use control structures that implicitly return the response.
fn main() {
assert_eq!(dice_roll_conditional(true), 6);
assert_eq!(dice_roll_conditional(false), 4);
assert_eq!(dice_roll_match(true), 6);
assert_eq!(dice_roll_match(false), 4);
}
fn dice_roll_conditional(feeling_lucky: bool) -> i32 {
if feeling_lucky {
6
} else {
4
}
}
fn dice_roll_match(feeling_lucky: bool) -> i32 {
match feeling_lucky {
true => 6,
false => 4,
}
}
Closures
Vertical pipes || start a closure.
let sleepy = |num| {
thread::sleep(Duration::from_secs(num));
num
};
You can take ownership of used context variables with the move prefix.
They don't need curly braces unless you want to have multiple statements.
let x = String::from("hello");
let equal_to_x = move |z| z == x;
// x is moved into the closure and not owned by the context anymore
Closures implement closure traits Fn, FnMut or FnOnce with some captured context.
Fn: can be called repeatedly and doesn't modify the captured contextFnMut: can be called repeatedly and can modify the captured contextFnOnce: can only be called once and consumes the captured context
fn for_each_planet<F: Fn(&'static str)>(f: F) {
f("Earth");
f("Mars");
f("Jupiter");
}
fn main() {
// here the `|planet| ...` is a closure of type `Fn`
for_each_planet(|planet| println!("Hello, {}", planet));
}
As closures are traits, you must use trait object to return then.
// does not compile
fn returns_closure() -> Fn(i32) -> i32 { |x| x + 1 }
// boxed closure
fn returns_closure() -> Box<Fn(i32) -> i32> { |x| x + 1 }
// a more modern way
fn returns_closure() -> impl Fn(i32) -> i32 { |x| x + 1 }
Function Pointers
Function pointers fn are not closures, but implement all the closure traits.
Here the
do_twicefunction parameter is a function pointer type. Normally you'd use a closure trait for this to allow using either a function pointer or a closure.
fn add_one(x: i32) -> i32 { x + 1 }
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { f(arg) + f(arg) }
fn main() {
let answer = do_twice(add_one, 5);
println!("The answer is: {}", answer);
}