-
-
Save rust-play/a601efc7482b38d1196eb4a3eddbf3d7 to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::sync::Arc; | |
| struct T {} | |
| impl T { | |
| async fn foo(&self) { | |
| println!("foo") | |
| } | |
| #[tokio::main] | |
| async fn outer(self) { | |
| // The requirement: | |
| // library_fn( | |
| // /* how to call self.foo() here in closure? */ | |
| // ); | |
| // -------------------------------------------------------- | |
| let _self = Arc::new(self); | |
| // Variant 1. | |
| // Err: "`_self` does not live long enough" | |
| // | |
| // IIUC, the async closure might (and probably will) be called AFTER | |
| // the [library_fn] call is over, thus `_self` is dropped to that moment. | |
| // library_fn(async || { | |
| // _self.foo().await | |
| // }); | |
| // -------------------------------------------------------- | |
| // Variant 2. | |
| // Err: "async closure does not implement FnMut because it captures state from its environment (rustc)" | |
| // | |
| // I am not sure I get it. | |
| // FnMut is supposed to represent the closure that might be called many times. | |
| // And if [Arc] is "ref counter that owns the data" why it just cannot | |
| // be used/copied while holding the ref to the data that is moved to heap (I hope?). | |
| // What's the matter? | |
| // library_fn(async move || { | |
| // // _self.foo().await; // Neither this nor next works | |
| // _self.clone().foo().await | |
| // }); | |
| // -------------------------------------------------------- | |
| // Variant 3. | |
| // Err (w/o move): "closure may outlive the current function, | |
| // but it borrows `_self`, which is owned by the current function" | |
| // With move: compilable. | |
| // library_fn(move || { | |
| // let _self = _self.clone(); | |
| // async { | |
| // } | |
| // }); | |
| // -------------------------------------------------------- | |
| // Variant 3.1. | |
| // The closures are lazy. So, before it's called inside [library_fn], | |
| // where is that [_self]? It's associated with the closure context | |
| // and will not be GCed earlier? | |
| // | |
| // And it doesn't even have the hint like | |
| // "function requires argument type to outlive `'static`" | |
| // I assume because [_self] now belongs to the closure. | |
| // So, since the closure owns it there's no borrowing, thus no 'static requirement. | |
| // | |
| // Although IDK then what 'static for FnMut and for returned Future mean. | |
| // Does it prevent to pass closure by reference? Capturing the non-'static references? | |
| // | |
| // But I do need to call [foo], that is async, so I need async context, | |
| // so async block (???) it's just a future constructor with the block/scope | |
| // becoming the body of it, right? Not the inner closure? | |
| // | |
| // And this thing also required to be 'static. | |
| // library_fn(move || { | |
| // let _self = _self.clone(); | |
| // async { | |
| // _self.foo().await | |
| // } | |
| // // Err: | |
| // // async block may outlive the current function, | |
| // // but it borrows `_self`, which is owned by the current function | |
| // // | |
| // // Hint: | |
| // // to force the async block to take ownership of `_self` | |
| // // (and any other referenced variables), use the `move` keyword | |
| // }); | |
| // -------------------------------------------------------- | |
| // Variant 4 | |
| library_fn(move || { | |
| let _self = _self.clone(); | |
| async move { | |
| _self.foo().await | |
| } | |
| }); | |
| // This finally works. | |
| // Why? How? | |
| // | |
| // What's happened with 'static requirement? | |
| // Is it gone because it covers only references and here we are owning | |
| // the values of smart pointers? | |
| // | |
| // Am I correct, that here: | |
| // _self: Transfer ownership to closure | |
| // _self: Transfer ownership to Future's body? | |
| // | |
| // Why then it wasn't working with var2? | |
| // If the ownership could be transferred in 2 steps to closure | |
| // and then to the Future's body, why it cannot be transferred in 1 step? | |
| // Or what? | |
| } | |
| } | |
| fn library_fn<F, T>(_: F) -> () | |
| where | |
| F: 'static + FnMut() -> T + Send, | |
| T: 'static + Future<Output = ()> + Send, | |
| { | |
| /* Some library code */ | |
| } | |
| fn main() { | |
| T{}.outer(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment