| This error occurs because a borrow in a movable coroutine persists across a | |
| yield point. | |
| Erroneous code example: | |
| ```compile_fail,E0626 | |
| # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] | |
| # use std::ops::Coroutine; | |
| # use std::pin::Pin; | |
| let mut b = #[coroutine] || { | |
| let a = &String::new(); // <-- This borrow... | |
| yield (); // ...is still in scope here, when the yield occurs. | |
| println!("{}", a); | |
| }; | |
| Pin::new(&mut b).resume(()); | |
| ``` | |
| Coroutines may be either unmarked, or marked with `static`. If it is unmarked, | |
| then the coroutine is considered "movable". At present, it is not permitted to | |
| have a yield in a movable coroutine that occurs while a borrow is still in | |
| scope. To resolve this error, the coroutine may be marked `static`: | |
| ``` | |
| # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] | |
| # use std::ops::Coroutine; | |
| # use std::pin::Pin; | |
| let mut b = #[coroutine] static || { // <-- note the static keyword | |
| let a = &String::from("hello, world"); | |
| yield (); | |
| println!("{}", a); | |
| }; | |
| let mut b = std::pin::pin!(b); | |
| b.as_mut().resume(()); | |
| ``` | |
| If the coroutine must remain movable, for example to be used as `Unpin` | |
| without pinning it on the stack or in an allocation, we can alternatively | |
| resolve the previous example by removing the borrow and just storing the | |
| type by value: | |
| ``` | |
| # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] | |
| # use std::ops::Coroutine; | |
| # use std::pin::Pin; | |
| let mut b = #[coroutine] || { | |
| let a = String::from("hello, world"); | |
| yield (); | |
| println!("{}", a); | |
| }; | |
| Pin::new(&mut b).resume(()); | |
| ``` | |
| This is a very simple case, of course. In more complex cases, we may | |
| wish to have more than one reference to the value that was borrowed -- | |
| in those cases, something like the `Rc` or `Arc` types may be useful. | |
| This error also frequently arises with iteration: | |
| ```compile_fail,E0626 | |
| # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] | |
| # use std::ops::Coroutine; | |
| # use std::pin::Pin; | |
| let mut b = #[coroutine] || { | |
| let v = vec![1,2,3]; | |
| for &x in &v { // <-- borrow of `v` is still in scope... | |
| yield x; // ...when this yield occurs. | |
| } | |
| }; | |
| Pin::new(&mut b).resume(()); | |
| ``` | |
| Such cases can sometimes be resolved by iterating "by value" (or using | |
| `into_iter()`) to avoid borrowing: | |
| ``` | |
| # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] | |
| # use std::ops::Coroutine; | |
| # use std::pin::Pin; | |
| let mut b = #[coroutine] || { | |
| let v = vec![1,2,3]; | |
| for x in v { // <-- Take ownership of the values instead! | |
| yield x; // <-- Now yield is OK. | |
| } | |
| }; | |
| Pin::new(&mut b).resume(()); | |
| ``` | |
| If taking ownership is not an option, using indices can work too: | |
| ``` | |
| # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] | |
| # use std::ops::Coroutine; | |
| # use std::pin::Pin; | |
| let mut b = #[coroutine] || { | |
| let v = vec![1,2,3]; | |
| let len = v.len(); // (*) | |
| for i in 0..len { | |
| let x = v[i]; // (*) | |
| yield x; // <-- Now yield is OK. | |
| } | |
| }; | |
| Pin::new(&mut b).resume(()); | |
| // (*) -- Unfortunately, these temporaries are currently required. | |
| // See <https://github.com/rust-lang/rust/issues/43122>. | |
| ``` |