personal website.
Table of contents
Fn FnMut and FnOnce under closureborrow and borrow_mut not working?self.x because it is borrowedFn FnMut and FnOnce under closureFn is the most flexible one, it can be called multiple times without any restrictions since they don't have any changes to their environment.
#[derive(Debug)]
struct SomeStruct {
param: i32,
}
fn check() {
let s = SomeStruct { param: 1 };
let func = || {
println!("{:?}", s);
};
func() // func is recognized as `impl Fn()`
}
FnMut means there's environment changes in the function:
#[derive(Debug)]
struct SomeStruct {
param: i32,
}
fn use_change() {
let mut s = SomeStruct { param: 1 };
let mut func = || { // for why `FmMut` variable must have `mut`, check: https://users.rust-lang.org/t/why-must-closure-variable-be-mut/53583/3
s.param = 0;
};
func() // function is recognized as `impl FnMut()` since it changes `s` in it's environment
}
it can also run multiple times, but since in rust mut for one variable can only exist once in the same scope, this is not allowed:
// WILL NOT COMPILE
fn use_change() {
let mut s = SomeStruct { param: 1 };
let mut func1 = || {
s.param = 0;
};
let mut func2 = || {
s.param = 1; // can not borrow the same variable twice which we did here to `s.param`, but you can still change other params under `s`
};
func1();
func2();
}
FnOnce means the function will only be executed once, this is special because you have to specify this in some circumstances:// WILL NOT COMPILE
fn use_change1() {
fn setup(s: SomeStruct) -> impl Fn() -> Box<dyn Fn()> { //here we use `Fn` not `FnOnce`
move || {
Box::new(move || {
println!("{:?}", s);
})
}
}
let func = setup(SomeStruct { param: 1 });
// you might want to just call it once, but without specifically saying it's a `FnOnce`, compiler will assume:
let b1 = func(); // box of print function
let b2 = func(); // box of print function
// `s` is passed to `b1` in the first call of `func`, there's nothing left for `b2` unless `SomeStruct` implemented `Copy` trait
}
Warning
> #[derive] won't work
trait Test1 {}
trait Test2 {
fn t(&self) {}
}
impl Test2 for dyn Test1 {
fn t(&self) {
// ...
}
}
This is usually a good idea to directly use self in side a closure that that lives longer than current function.
Unless it implements Copy or Clone, you can self.clone() from outside and move that cloned variable inside closure.
But this is only for FnOnce since that cloned variable will be dropped after closure returned.
If you wish to run it multiple times, then you have to specify the lifetime, for example:
// WILL NOT COMPILE
struct S {
d: usize,
}
impl S {
fn caller_(&mut self) -> Box<dyn FnMut()> {
Box::new(|| self.d += 1) // here, it will raise:
// lifetime may not live long enough returning this value requires that `'1` must outlive `'static`
}
}
But not only errors are shown, it gives us help: to declare that the trait object captures data from argument self, you can add an explicit '_lifetime bound: + '_
As for why is this needed here, maybe this means that it wants you to make sure that closure is actually try to borrow self? idk for now.
But whatever, this works:
fn caller_(&mut self) -> Box<dyn FnMut() + '_> {
Box::new(|| self.d += 1)
}
As to what The Rust Reference/Lifetime elision said: If the receiver has type &Self or &mut Self, then the lifetime of that reference to Self is assigned to all elided output lifetime parameters.
And so what we do up there ca be translated to:
fn caller<'a>(&'a mut self) -> Box<dyn FnMut() + 'a> {
Box::new(|| self.d += 1)
}
If you're using FnOnce then just add move in front.
But if the closure will be called multiple times, implementing Fn / FnMut / FnOnce for your own struct could work, but this feature in only available under nightly currently(see #29625).
Or you can specify a trait and add fn call(&self)/fn call_mut(&mut self) yourself and combine with the struct that holds all of the variable inside that scope, pass in the struct and call call/call_mut.
borrow and borrow_mut not working?Simply removes use std::borrow::{Borrow, BorrowMut} from your code.
self.x because it is borrowedAlways stay alert dealing with references.
impl SomeStruct {
fn a(&self) -> Result<u32, &str> {
self.p1.ok_or("no p1")
}
fn operate(&mut self) -> Result<(), &str> {
let p1 = self.a()?; // IDE gives lint: first borrow here
self.p2 = p1; // error here: cannot assign to `self.p2` because it is borrowed
Ok(())
}
}
But function a is done and &self borrow should be dropped, why it doesn't?
This is because the lifetime compiler inferred is incorrect:
fn a<'a>(&'a self) -> Result<(), &'a str> {
self.p1.ok_or("no p1")
}
The borrow of self is the same lifetime of returned "no p1", so &self isn't dropped at the end of function a, instead, it goes along wherever &str returned goes.
To fix it, you have to separate lifetime between borrow of self and ref str:
impl<'b> SomeStruct {
fn a(&self) -> Result<u32, &'b str> {
self.p1.ok_or("no p1")
}
fn operate(&mut self) -> Result<(), &'b str> {
let p1 = self.a()?;
self.p2 = p1;
Ok(())
}
}
Or in this particular case, use 'static since "str" itself is 'static anyway
fn a(&self) -> Result<(), &'static str> {
self.p1.ok_or("no p1")
}
https://www.reddit.com/r/learnrust/comments/ln28un/why_does_impl_require_lifetime_annotations/
https://users.rust-lang.org/t/need-help-with-mutable-and-immutable-borrow-of-self/68811/2?u=ogios
https://manishearth.github.io/blog/2015/05/17/the-problem-with-shared-mutability/
https://github.com/rust-lang/rust/issues/46774
Note
updating...