Here the Speak
trait has the blanket implementation for the references of any type that implement the Speak
trait (Human
type in the current example). That allows to pass Human
, &Human
, and &mut Human
to the introduce
method that expects a trait that has Speak
trait implemented. The blanket implementation is necessary as Rust doesn't dereference types in traits.
trait Speak {
fn speak(&self);
}
// Blanket implementation for &T
impl<T: Speak> Speak for &T {
fn speak(&self) {
(*self).speak();
}
}
// Blanket implementation for &mut T
impl<T: Speak> Speak for &mut T {
fn speak(&self) {
(**self).speak();
}
}
struct Human {
name: String,
}
impl Speak for Human {
fn speak(&self) {
println!("Hello, my name is {}.", self.name);
}
}
struct Introduction;
impl Introduction {
fn introduce(&self, speaker: impl Speak) {
println!("Let me introduce our speaker:");
speaker.speak();
}
}
fn main() {
let person = Human {
name: String::from("Jhon"),
};
let introduction = Introduction;
introduction.introduce(&person);
}
By default the let
keyword defines immutable variable.
let immutable_u8_val: u8 = 200u8;
let _borrow_immutable_u8_val: &u8 = &immutable_u8_val; // shared reference
// cannot borrow `immutable_u8_val` as mutable, as it is not declared as mutable
// let _borrow_mutable_u8_val: &mut u8 = &mut immutable_u8_val; // exclusive reference
The mut
keyword allows to define mutable variable.
let mut mutable_u8_val: u8 = 200u8;
let _borrow_immutable_u8_val: &u8 = &mutable_u8_val; // shared reference
let borrow_mutable_u8_val: &mut u8 = &mut mutable_u8_val; // exclusive reference
*borrow_mutable_u8_val += 1; // dereference and mutate
// 0xE000_E010 is a memory address
// *const means raw pointer of immutable value
let const_raw_ref: *const u32 = 0xE000_E010 as *const u32;
// dereference the raw pointer to u32
// it's unsafe because Rust compiler doesn't know anything about 0xE000_E010 memory address
let immutable_val: u32 = unsafe { *const_raw_ref };
let _borrow_immutable_val: &u32 = &immutable_val;
// cannot borrow `*const_raw_ref` as mutable, as it is behind a `*const` pointer
// that means we must use `*mut` to define the raw pointer (see below)
// let borrow_mutable_val: &mut u32 = unsafe { &mut *const_raw_ref };
// not sure that this is correct, but Rust compiler seems ok with that
// note how we moved the `&mut` ahead of `unsafe` block
let borrow_mutable_val_from_const_pointer: &mut u32 = &mut unsafe { *const_raw_ref };
*borrow_mutable_val_from_const_pointer += 1; // dereference and mutate
// with `mut` keyword we can turn the `*const` pointer into mutable variable
let mut mutable_val: u32 = unsafe { *const_raw_ref };
let borrow_mutable_val: &mut u32 = &mut mutable_val;
*borrow_mutable_val += 1; // dereference and mutate
// *mut means raw pointer for muttable value
let mut_raw_ref: *mut u32 = 0xE000_E010 as *mut u32;
// dereference the raw pointer to u32
let borrow_mutable_val: &mut u32 = unsafe { &mut *mut_raw_ref };
*borrow_mutable_val += 1;
// all in one
// `0xE000_E010 as *mut u32` - raw reference
// `*(0xE000_E010 as *mut u32)` - dereference to u32
// `&mut *(0xE000_E010 as *mut u32)` - borrow u32 to mutate
let val: &mut u32 = unsafe { &mut *(0xE000_E010 as *mut u32) };
*val += 1;
The function pointer that is not used anywhere doesn't require any memory.
fn main() {
let a = foo::<u32>;
println!("{}", core::mem::size_of_val(&a)); // 0
}
fn foo<T>() {}
foo<T>
is a generic function typea
holds a function pointer to the generic functionfoo
with a specified type parameter ofu32
The function pointer that is going to be used must have some memory occupation.
fn main() {
let a = foo::<u32>;
println!("{}", core::mem::size_of_val(&a)); // 0
bar(foo::<u32>);
}
fn foo<T>() {}
fn bar(f: fn()) {
println!("{}", core::mem::size_of_val(&f)); // 8
}
bar
expects function pointer
The function type implements the Fn(), FnMut(), and FnOnce() traits by default. The function pointer could be used in place of any of the function traits implementation required. That's because the function type doesn't hold any external references.
fn main() {
baz(foo::<u32>);
}
fn foo<T>() {}
fn baz<F>(f: F)
where
F: Fn(),
{
(f)()
}
baz
expects anything that implement the Fn() trait
The relationship between the function traits is this:
Fn()
could be used in place ofFnMut()
orFnOnce()
FnMut()
could be used in place ofFnOnce()
It means if something implements the Fn()
trait it could be called multiple times simultaneously as it doesn't hold any ownership or exclusive reference from the external scope, otherwise it will violent the borrowing rules. That what the function type actually is.
If something implements the FnMut()
trait it also could be called multiple times, but not simultaneously as it holds some exclusive reference that couldn't be shared.
If something implements the FnOnce()
trait it could be called only once as it takes an ownership from the external scope and will drop the owned value after the first execution which makes impossible the subsequent execution.
The main consumer of the function traits Fn()
, FnMut()
, and FnOnce()
are closures.
In its simplest form the closure doesn't take ownership or hold any external reference (non-capturing closure). That makes it seem to the compiler as something that implements the Fn()
trait.
fn main() {
let f = || (); // non-capturing closure
baz(f);
}
fn baz<F>(f: F)
where
F: Fn(),
{
(f)()
}
The non-capturing closure could be coerced to the function pointer. (only non-capturing!)
fn main() {
let f = || (); // non-capturing closure
baz(f);
}
fn baz(f: fn()) {
println!("{}", core::mem::size_of_val(&f)); // 8
}
The closure that behaves like Fn()
still could take the shared references to use internally as the borrowing rules do not prohibit it.
fn main() {
let a = String::from("foo");
let f = || {
println!("{}", a); // captures the `a` value
};
baz(f);
}
fn baz<F>(f: F)
where
F: Fn(),
{
(f)()
}
The Fn()
closure could be used in place of FnMut()
or FnOnce()
fn main() {
let a = String::from("foo");
let f = || {
println!("{}", a);
};
bar(f);
baz(f);
bax(f);
}
fn bar<F>(f: F)
where
F: Fn(),
{
(f)()
}
fn baz<F>(mut f: F)
where
F: FnMut(),
{
(f)()
}
fn bax<F>(f: F)
where
F: FnOnce(),
{
(f)()
}
The FnMut()
closure holds exclusive reference and mutate external value catched by closure.
fn main() {
let mut a = String::from("foo");
let f = || {
a.clear();
};
baz(f);
}
fn baz<F>(mut f: F)
where
F: FnMut(),
{
(f)()
}
The closure with the FnMut()
trait cannot be used in place of Fn()
as the Fn()
trait means multiple executions from the different threads simultaneously which is not allowed by the borrowin rules in case of FnMut()
trait.
fn main() {
let mut a = String::from("foo");
let f = || {
a.clear();
};
bar(f);
}
fn bar<F>(f: F)
where
F: Fn(),
{
(f)()
}
Output
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
--> src/main.rs:3:11
|
3 | let f = || {
| ^^ this closure implements `FnMut`, not `Fn`
4 | a.clear();
| - closure is `FnMut` because it mutates the variable `a` here
5 | };
6 | bar(f);
| --- the requirement to implement `Fn` derives from here
But it's allowed to use the FnMut()
closure in place of FnOnce()
.
fn main() {
let mut a = String::from("foo");
let f = || {
a.clear();
};
bar(f);
}
fn bar<F>(f: F)
where
F: FnOnce(), // changed from `Fn()`
{
(f)()
}
The most strict of the function traits FnOnce()
allows to be called only once as it takes the ownership of the external value and drop it after execution.
fn main() {
let a = String::from("foo");
let f = || {
drop(a); // `a` dropped here
};
bar(f);
}
fn bar<F>(f: F)
where
F: FnOnce(),
{
(f)()
}
The FnOnce()
trait cannot be substitude by any other function traits.
fn main() {
let mut a = String::from("foo");
let f = || {
drop(a);
};
bar(f);
}
fn bar<F>(mut f: F)
where
F: FnMut(),
{
(f)()
}
Output
error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
--> src/main.rs:3:11
|
3 | let f = || {
| ^^ this closure implements `FnOnce`, not `FnMut`
4 | drop(a);
| - closure is `FnOnce` because it moves the variable `a` out of its environment
5 | };
6 | bar(f);
| --- the requirement to implement `FnMut` derives from here