How to use an async closure both capturing and accepting references - asynchronous

I am trying to pass a closure returning Future<Output=bool> to an async function and call this closure as an async predicate (something like an async .filter or other higher-order function).
This predicate receives its input as a reference. I found how to implement it for pure predicates that do not capture their environment:
type BoxFuture<'a, Out> = Pin<Box<dyn Future<Output=Out> + 'a + Send>>;
////////////////////////////////////////////////////////////////////////////////
// 1 -> Closure only uses the inner argument //
////////////////////////////////////////////////////////////////////////////////
/// Run the computation and check that its output is not empty
fn run1<'a>(expected: &'a [u8]) -> impl Future<Output=()> + 'a {
async move {
let is_ok = compute_and_check1(|b: &[u8]| Box::pin(async move {
b.len() > 0 // Only uses the inner argument
}));
let is_ok1 = is_ok.await;
dbg!(is_ok1);
}
}
/// Compute some bytes (may be complex / use async), then check their validity
/// with a user-supplied function, finally do some clean-up and return.
async fn compute_and_check1<F>(check: F) -> bool
where
F: for<'r> FnOnce(&'r [u8]) -> BoxFuture<'r, bool>
{
let bytes = [0u8; 128];
let is_ok = check(&bytes).await;
drop(bytes);
is_ok
}
Playground link
Supporting only non-capturing closures is quite limiting. I would like to use a closure that captures its environment. By changing the bounds of my compute_and_check function, I am able to pass a closure that uses its environment - but not its input:
type BoxFuture<'a, Out> = Pin<Box<dyn Future<Output=Out> + 'a + Send>>;
////////////////////////////////////////////////////////////////////////////////
// 2 -> Closure only uses the outer argument //
////////////////////////////////////////////////////////////////////////////////
/// Run the computation and assume that its output is not empty if `expected` is not empty
fn run2<'a>(expected: &'a [u8]) -> impl Future<Output=()> + 'a {
async move {
let is_ok = compute_and_check2(|b: &[u8]| Box::pin(async move {
expected.len() > 0 // Only uses the environment
}));
let is_ok2 = is_ok.await;
dbg!(is_ok2);
}
}
/// Compute some bytes (may be complex / use async), then check their validity
/// with a user-supplied function, finally do some clean-up and return.
async fn compute_and_check2<'a, F>(check: F) -> bool
where
F: for<'r> FnOnce(&'r [u8]) -> BoxFuture<'a, bool>
{
let bytes = [0u8; 128];
let is_ok = check(&bytes).await;
drop(bytes);
is_ok
}
Playground link
I can write an implementation where the closure uses its input, and one where the closure uses its environment. But not both at the same time.
How can I accept a Future-producing closure that uses references for both its input and environment?
What I would like to write is something like this:
type BoxFuture<'a, Out> = Pin<Box<dyn Future<Output=Out> + 'a + Send>>;
////////////////////////////////////////////////////////////////////////////////
// 3 -> Closure uses both the inner and outer arguments //
////////////////////////////////////////////////////////////////////////////////
/// Run the computation and check its output is the provided expected value
fn run3<'a>(expected: &'a [u8]) -> impl Future<Output=()> + 'a {
async move {
let is_ok = compute_and_check3(|b: &[u8]| Box::pin(async move {
b == expected // Uses both the input and environment
}));
let is_ok2 = is_ok.await;
dbg!(is_ok2);
}
}
/// Compute some bytes (may be complex / use async), then check their validity
/// with a user-supplied function, finally do some clean-up and return.
async fn compute_and_check3<'a, F>(check: F) -> bool
where
F: for<'r> FnOnce(&'r [u8]) -> BoxFuture<'r + 'a, bool>
{
let bytes = [0u8; 128];
let is_ok = check(&bytes).await;
drop(bytes);
is_ok
}
Playground link
This code does not compile because I am asking the closure to return BoxFuture<'r + 'a, bool> but this is not legal syntax:
error[E0226]: only a single explicit lifetime bound is permitted
--> src/main.rs:89:51
|
89 | F: for<'r> FnOnce(&'r [u8]) -> BoxFuture<'r + 'a, bool>
| ^^
From what I understand, the core of my issue is that I need to restrict my Higher-Ranked Trait Bound. Instead of "for any 'r", I want to say "for any 'r that does not outlive 'a" but I don't see how to write it down.
I tried to use two lifetimes and restrictions to my BoxFuture type alias, or define an auxilliary trait but I did not manage to solve this issue because I fail to apply restrictions on the HRTB lifetime.
For completness, here are the errors I get when passing my final closure to compute_and_check1 (only input) and compute_and_check2 (only environment):
Using compute_and_check1 (only input) playground link
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:17:67
|
17 | let is_ok = compute_and_check1(|b: &[u8]| Box::pin(async move {
| ___________________________________________________________________^
18 | | b == expected
19 | | }));
| |_____^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 15:9...
--> src/main.rs:15:9
|
15 | fn run3<'a>(expected: &'a [u8]) -> impl Future<Output=()> + 'a {
| ^^
note: ...so that the types are compatible
--> src/main.rs:17:67
|
17 | let is_ok = compute_and_check1(|b: &[u8]| Box::pin(async move {
| ___________________________________________________________________^
18 | | b == expected
19 | | }));
| |_____^
= note: expected `(&[u8], &[u8])`
found `(&[u8], &'a [u8])`
note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the body at 17:36...
--> src/main.rs:17:36
|
17 | let is_ok = compute_and_check1(|b: &[u8]| Box::pin(async move {
| ____________________________________^
18 | | b == expected
19 | | }));
| |______^
note: ...so that the expression is assignable
--> src/main.rs:17:47
|
17 | let is_ok = compute_and_check1(|b: &[u8]| Box::pin(async move {
| _______________________________________________^
18 | | b == expected
19 | | }));
| |______^
= note: expected `Pin<Box<dyn Future<Output = bool> + Send>>`
found `Pin<Box<dyn Future<Output = bool> + Send>>`
Using compute_and_check2 (only environment) playground link
error: lifetime may not live long enough
--> src/main.rs:17:47
|
17 | let is_ok = compute_and_check2(|b: &[u8]| Box::pin(async move {
| ________________________________________-____-_^
| | | |
| | | return type of closure is Pin<Box<(dyn Future<Output = bool> + Send + '2)>>
| | let's call the lifetime of this reference `'1`
18 | | b == expected
19 | | }));
| |______^ returning this value requires that `'1` must outlive `'2`
I have also looked into the unboxed_closure nightly feature but did not manage to solve my issue. I would prefer my code to work on stable Rust but it is acceptable for my code to require nightly if it is the only solution.

Related

Rust lifetimes in async wrapper for sync code

I am trying to create a Stream using a camera with a blocking capture method. The blocking call is wrapped with blocking::unblock.
use futures::stream;
use rscam::{Camera, Config};
fn frame_stream() -> impl stream::Stream {
let mut camera = Camera::new("/dev/video0").unwrap();
camera.start(&Config {
interval: (1, 30),
resolution: (1280, 720),
format: b"H264",
..Default::default()
}).unwrap();
stream::unfold(camera, |c| async move {
let frame = blocking::unblock(|| c.capture().unwrap()).await;
Some((frame, c))
})
}
Compiling gives this error message:
error[E0373]: closure may outlive the current function, but it borrows `c`, which is owned by the current function
--> src/lib.rs:15:39
|
15 | let frame = blocking::unblock(|| c.capture().unwrap()).await;
| ^^ - `c` is borrowed here
| |
| may outlive borrowed value `c`
|
note: function requires argument type to outlive `'static`
--> src/lib.rs:15:21
|
15 | let frame = blocking::unblock(|| c.capture().unwrap()).await;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `c` (and any other referenced variables), use the `move` keyword
|
15 | let frame = blocking::unblock(move || c.capture().unwrap()).await;
| ++++
error[E0505]: cannot move out of `c` because it is borrowed
--> src/lib.rs:17:22
|
15 | let frame = blocking::unblock(|| c.capture().unwrap()).await;
| ------------------------------------------
| | | |
| | | borrow occurs due to use in closure
| | borrow of `c` occurs here
| argument requires that `c` is borrowed for `'static`
16 |
17 | Some((frame, c))
| ^ move out of `c` occurs here
How can I guarantee to the compiler that the reference to c taken in the closure will still be valid? I assume it will be, since execution of the closure is awaited before c is returned.
Solution
stream::unfold(camera, |c| async move {
Some(
blocking::unblock(|| {
(c.capture().unwrap(), c)
}).await
)
})
You could move the camera into the inner closure, then return it once the frame capture is complete:
stream::unfold(camera, |c| async move {
Some(blocking::unblock(|| move {
let frame = c.capture().unwrap()).await;
(frame,c)
})
})
.await does not guarantee liveness. This is the general problem of scoped async tasks. Futures can be canceled at any time. Consider:
let future = async {
let local = 123;
blocking::unblock(|| local).await;
};
// Poll `future`, but only once.
futures::block_on(async move { futures::poll!(future) });
We started a task using local data, then dropped the future. The task continues executing but the local data is gone. For this reason, there is currently no sound way to expose an async API allowing using local data similar to scoped threads. You have to use 'static data, for example by wrapping in Arc.
See also blocking issue #4.

How to store a pointer to an async method in a container?

I have a struct that defines multiple async methods, and I'd like to store a pointer of each of them in a HashMap, so that I can call any method in one single line, knowing only a key that is given in parameter.
The aim here is to avoid as much as possible to have a huge match clause that would inflate more and more as I add new methods to my struct.
Methods all have the same signature:
async fn handle_xxx(&self, c: Command) -> Result<String, ()>
And I'd really like to call them the following way:
pub async fn execute_command(&mut self, command: Command) -> Result<String, ()> {
let handler = self.command_callbacks.get(&command);
let return_message: String = match handler {
Some(f) => f(self, command).await.unwrap(), // The call is made here.
None => return Err(()),
};
Ok(return_message)
}
However, obviously, in order to store something in a HashMap, you have to specify its type when declaring the HashMap, and that's when the trouble starts.
I tried the most obvious, which is declaring the wrapping function type:
type CommandExecutionNotWorking = fn(&CommandExecutor, Command) -> Future<Output = Result<String, ()>>;
Which does not work since Future is a trait, and not a type.
I tried to declare a generic type and specify it somewhere below:
type CommandExecutionNotWorkingEither<Fut> = fn(&CommandExecutor, Command) -> Fut;
But I encounter the same kind of issue since I need to specify the Future type, and have a HashMap declaration like following:
let mut command_callbacks: HashMap<
Command,
CommandExecutionFn<dyn Future<Output = Result<String, ()>>>,
> = HashMap::new();
impl Future obviously does not work since we're not in a function signature, Future either since it's not a type, and dyn Future creates a legitimate type mismatch.
Thus I tried to use Pin so that I can manipulate dyn Futures, and I ended up with the following signature:
type CommandExecutionStillNotWorking = fn(
&CommandExecutor,
Command,
) -> Pin<Box<dyn Future<Output = Result<String, ()>>>>;
But I need to manipulate functions that return Pin<Box<dyn Future<...>>> and not just Futures. So I tried to define a lambda that take an async function in parameter and returns a function that wraps the return value of my async method in a Pin<Box<...>>:
let wrap = |f| {
|executor, command| Box::pin(f(&executor, command))
};
But the compiler is not happy since it expects me to define the type of f, which is what I tried to avoid here, so I'm back to square one.
Thus my question: Do you know if it's actually possible to write the type of an async function so that pointers on them can be easily manipulated like any variable or any other function pointer?
Or should I go for another solution that may be less elegant, with a bit of duplication code or a huge match structure?
TL;DR: Yes, it is possible, but probably more complicated than you imagined.
First, closures cannot be generic, and thus you'd need a function:
fn wrap<Fut>(f: fn(&CommandExecutor, Command) -> Fut) -> CommandExecution
where
Fut: Future<Output = Result<String, ()>>
{
move |executor, command| Box::pin(f(executor, command))
}
But then you cannot turn the returned closure into a function pointer because it captures f.
Now technically it should be possible since we only want to work with function items (that are non-capturing), and their type (unless converted into a function pointer) is zero-sized. So by the type alone we should be able to construct an instance. But doing that requires unsafe code:
fn wrap<Fut, F>(_f: F) -> CommandExecution
where
Fut: Future<Output = Result<String, ()>>,
F: Fn(&CommandExecutor, Command) -> Fut,
{
assert_eq!(std::mem::size_of::<F>(), 0, "expected a fn item");
move |executor, command| {
// SAFETY: `F` is a ZST (checked above), any (aligned!) pointer, even crafted
// out of the thin air, is valid for it.
let f: &F = unsafe { std::ptr::NonNull::dangling().as_ref() };
Box::pin(f(executor, command))
}
}
(We need _f as a parameter because we cannot specify the function type; let inference find it out itself.)
However, are troubles don't end here. They just start.
Now we get the following error:
error[E0310]: the parameter type `Fut` may not live long enough
--> src/lib.rs:28:9
|
18 | fn wrap<Fut, F>(_f: F) -> CommandExecution
| --- help: consider adding an explicit lifetime bound...: `Fut: 'static`
...
28 | Box::pin(f(executor, command))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `Fut` will meet its required lifetime bounds
Well, it suggests a solution. Let's try...
It compiles! Successfully!!
...until we actually try to make use of it:
let mut _command_callbacks: Vec<CommandExecution> = vec![
wrap(CommandExecutor::handle_xxx),
wrap(CommandExecutor::handle_xxx2),
];
(a HashMap will have the same effect).
error[E0308]: mismatched types
--> src/lib.rs:34:9
|
34 | wrap(CommandExecutor::handle_xxx),
| ^^^^ lifetime mismatch
|
= note: expected associated type `<for<'_> fn(&CommandExecutor, Command) -> impl Future<Output = Result<String, ()>> {CommandExecutor::handle_xxx} as FnOnce<(&CommandExecutor, Command)>>::Output`
found associated type `<for<'_> fn(&CommandExecutor, Command) -> impl Future<Output = Result<String, ()>> {CommandExecutor::handle_xxx} as FnOnce<(&CommandExecutor, Command)>>::Output`
= note: the required lifetime does not necessarily outlive the static lifetime
note: the lifetime requirement is introduced here
--> src/lib.rs:21:41
|
21 | F: Fn(&CommandExecutor, Command) -> Fut,
| ^^^
error[E0308]: mismatched types
--> src/lib.rs:35:9
|
35 | wrap(CommandExecutor::handle_xxx2),
| ^^^^ lifetime mismatch
|
= note: expected associated type `<for<'_> fn(&CommandExecutor, Command) -> impl Future<Output = Result<String, ()>> {CommandExecutor::handle_xxx2} as FnOnce<(&CommandExecutor, Command)>>::Output`
found associated type `<for<'_> fn(&CommandExecutor, Command) -> impl Future<Output = Result<String, ()>> {CommandExecutor::handle_xxx2} as FnOnce<(&CommandExecutor, Command)>>::Output`
= note: the required lifetime does not necessarily outlive the static lifetime
note: the lifetime requirement is introduced here
--> src/lib.rs:21:41
|
21 | F: Fn(&CommandExecutor, Command) -> Fut,
| ^^^
The problem is described in Lifetime of a reference passed to async callback. The solution is to use a trait to workaround the problem:
type CommandExecution = for<'a> fn(
&'a CommandExecutor,
Command,
) -> Pin<Box<dyn Future<Output = Result<String, ()>> + 'a>>;
trait CommandExecutionAsyncFn<CommandExecutor>:
Fn(CommandExecutor, Command) -> <Self as CommandExecutionAsyncFn<CommandExecutor>>::Fut
{
type Fut: Future<Output = Result<String, ()>>;
}
impl<CommandExecutor, F, Fut> CommandExecutionAsyncFn<CommandExecutor> for F
where
F: Fn(CommandExecutor, Command) -> Fut,
Fut: Future<Output = Result<String, ()>>,
{
type Fut = Fut;
}
fn wrap<F>(_f: F) -> CommandExecution
where
F: 'static + for<'a> CommandExecutionAsyncFn<&'a CommandExecutor>,
{
assert_eq!(std::mem::size_of::<F>(), 0, "expected a fn item");
move |executor, command| {
// SAFETY: `F` is a ZST (checked above), any (aligned!) pointer, even crafted
// out of the thin air, is valid for it.
let f: &F = unsafe { std::ptr::NonNull::dangling().as_ref() };
Box::pin(f(executor, command))
}
}
I will not expand on why this thing is needed or how it solves the problem. You can find an explanation in the linked question and the questions linked in it.
And now our code works. Like, truly so.
However, think carefully if you really want all of this stuff: it may be easier to just change the functions to return a boxed future.

Rust Async Borrow Lifetimes

I'm trying to make a helper that allows asynchronously chaining side effects, but I'm unable to get the generic bounds correct so that the compiler understands the output of the future outlives a reference used to build it.
Playground Link
The gist of it comes down to:
struct Chain<T> {
data: T
}
impl<T> Chain<T> {
pub async fn chain<E, Fut, F>(self, effect: F) -> Result<T, E>
where
Fut: Future<Output=Result<(), E>>,
F: FnOnce(&T) -> Fut
{
todo!()
}
}
gives a compiler error of
error: lifetime may not live long enough
--> src/main.rs:39:32
|
39 | let r = chain.chain(|this| this.good("bar")).await;
| ----- ^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure `impl Future` contains a lifetime `'2`
| has type `&'1 MyData`
If we fix up chain so that it can infer that the reference is available for the same lifetime as the future:
impl<T> Chain<T> {
pub async fn chain<'a, E, Fut, F>(self, effect: F) -> Result<T, E>
where
T: 'a,
Fut: 'a + Future<Output=Result<(), E>>,
F: FnOnce(&'a T) -> Fut
{
effect(&self.data).await?;
Ok(self.data)
}
}
We get a new compiler error about moving self.data while it's still borrowed.
error[E0505]: cannot move out of `self.data` because it is borrowed
--> src/main.rs:30:12
|
23 | pub async fn chain<'a, E, Fut, F>(self, effect: F) -> Result<T, E>
| -- lifetime `'a` defined here
...
29 | effect(&self.data).await?;
| ------------------
| | |
| | borrow of `self.data` occurs here
| argument requires that `self.data` is borrowed for `'a`
30 | Ok(self.data)
| ^^^^^^^^^ move out of `self.data` occurs here
I guess there's a pathological closure along the lines of |this| futures::future::ready(Err(this)) that would cause an early return with the borrow still "alive".
Question
How can we get chain to work? My normal lifetime trick of block-scoping doesn't seem to help. Is there a set of where constraints that can be added to prove that the borrow and then eventual move are on disjoint lifetimes?
This particular situation is one where the current constraint syntax and lack of higher-kinded types does not let you express what you want.
You can use a higher-rank trait bound, the for<'a> syntax, to introduce an intermediate generic lifetime parameter 'a within a where clause to dictate that the constraint must be valid for any lifetime. This is necessary here and the reason your first fix didn't work was because 'a as a generic on chain meant that the lifetime was determined by the caller, however, lifetime of self is by construction less than any lifetime that could be picked by the caller. So the slightly more correct syntax (and identical to the de-sugared original code) would be:
pub async fn chain<E, Fut, F>(self, effect: F) -> Result<T, E>
where
Fut: Future<Output = Result<(), E>>,
F: for<'a> FnOnce(&'a T) -> Fut
{
...
But this doesn't help at all, since there is still no association between Fut and 'a. There's unfortunately no way to use the same for<'a> across multiple constraints. You could try using impl Trait to define it all at once, but that isn't supported:
pub async fn chain<E, F>(self, effect: F) -> Result<T, E>
where F: for<'a> FnOnce(&'a T) -> (impl Future<Output = Result<(), E>> + 'a)
{
...
error[E0562]: `impl Trait` not allowed outside of function and method return types
--> src/lib.rs:35:44
|
35 | where F: for<'a> FnOnce(&'a T) -> (impl Future<Output = Result<(), E>> + 'a)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There will hopefully be better support for higher-kinded types in the future. This particular case might have a solution on nightly by using the almost-complete generic associated types feature, but I haven't yet found it.
So the only real fix then is to use a named type as the return value, which really only leaves us with trait objects:
use std::pin::Pin;
use futures::future::FutureExt;
pub async fn chain<E, F>(self, effect: F) -> Result<T, E>
where F: for<'a> FnOnce(&'a T) -> Pin<Box<dyn Future<Output = Result<(), E>> + 'a>>
{
...
let r = chain.chain(|this| this.good("bar").boxed()).await;
As a side note, your bad case still does not compile and indeed cannot work, since you'd be returning a reference to a local value.
It looks like you are trying to implement future.then()
If you are aware of that and you are doing it as an exercise, you probably should design it in a way that the effect method returns values, and use these values to return from chain method. That way you enforce proper order of operations. As far as I understand your design, you do not benefit from awaiting on effect inside the chain method, since as your skip function is also async and will return future (the actual return type of chain method is Future<Output=Result<T, E>>, since async works that way: it wraps your explicit return type in future).
So there is no point in awaiting on the effect inside the chain, you still have to await it whenever you use it - and nothing will happen until you actually await for it outside of the chain - futures are lazy that way.
TL;DR I would arange your effect methods to return values and arrange chain to just return these values

Need vector slices to live longer

Is there any way to get the slices of this vector to last long enough so that I can use them in this kind of circular structure?
fn populate_chain(file_path: &str) -> HashMap<String, HashSet<&String>> {
println!("loading...");
let time = util::StopWatch::new();
let mut words = HashMap::new();
{
let f = |mut x: Vec<String>| {
let word = x.pop().unwrap();
words.insert(word, HashSet::new());
};
Csv::process_rows(f, file_path, "\t");
}
let col: Vec<(String, HashSet<&String>)> = words.clone().into_iter().collect();
let m: usize = col.len() - 1;
for i in 0..m {
let ref k: String = col[i].0;
for j in i..m {
let ref nk: String = col[j].0;
if check_link(k, nk) {
words.get_mut(k).unwrap().insert(nk);
words.get_mut(nk).unwrap().insert(k);
}
}
}
time.print_time();
words
}
I'm using the double for loops to chain words together which are related so that they can be quickly looked up later.
Here are the compiler errors...
error: `col` does not live long enough
--> src/main.rs:28:29
|
28 | let ref k: String = col[i].0;
| ^^^ does not live long enough
...
40 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the block at 13:72...
--> src/main.rs:13:73
|
13 | fn populate_chain(file_path: &str) -> HashMap<String, HashSet<& String>>{
| ^
error: `col` does not live long enough
--> src/main.rs:30:34
|
30 | let ref nk: String = col[j].0;
| ^^^ does not live long enough
...
40 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the block at 13:72...
--> src/main.rs:13:73
|
13 | fn populate_chain(file_path: &str) -> HashMap<String, HashSet<& String>>{
|
I can tell you from your function signature that you're going to have big problems trying to write this function, at least if you want it to contain non-empty HashSets in the result.
fn populate_chain(file_path: &str) -> HashMap<String, HashSet<&String>>
This function signature has references in it; they have elided lifetimes. If you make the inferred lifetimes explicit, it would look like this:
fn populate_chain<'a>(file_path: &'a str) -> HashMap<String, HashSet<&'a String>>
In other words: This function claims that, given some string slice with lifetime 'a, it will give back a collection that holds String objects with lifetime 'a.
But you have no means for allocating such String objects within your code. :(
So, you're stuck; no matter what you put into that function body, you're not going to be able to supply an implementation that returns a non-trivial result with respect to the HashSets.
However, all is not lost. You could, for example, revise your function so that it also takes as an additional parameter a reference to a TypedArena with an appropriate lifetime, and then allocate the strings there. Another (simpler) option would be to use HashSet<String> instead of HashSet<&String>...

How do I push a value into a 2D Vec in Rust?

Here is a really simple attempt at a 2D Vec. I'm trying to add an element to the last entry in the top-level Vec:
fn main() {
let mut vec_2d = vec![vec![]];
if let Some(v) = vec_2d.last() {
v.push(1);
}
println!("{:?}", vec_2d);
}
I get this error:
error[E0596]: cannot borrow `*v` as mutable, as it is behind a `&` reference
--> src/main.rs:4:9
|
3 | if let Some(v) = vec_2d.last() {
| - help: consider changing this to be a mutable reference: `&mut std::vec::Vec<i32>`
4 | v.push(1);
| ^ `v` is a `&` reference, so the data it refers to cannot be borrowed as mutable
I've also tried Some(ref v) and Some(ref mut v) with the same results. I can't find any documentation that describes this error specifically. What is the right approach here?
An answer to a similar question recommends something more like Some(&mut v). Then I get these errors:
error[E0308]: mismatched types
--> src/main.rs:3:17
|
3 | if let Some(&mut v) = vec_2d.last() {
| ^^^^^^ types differ in mutability
|
= note: expected type `&std::vec::Vec<_>`
found type `&mut _`
= help: did you mean `mut v: &&std::vec::Vec<_>`?
If I try Some(&ref mut v) I get:
error[E0596]: cannot borrow data in a `&` reference as mutable
--> src/main.rs:3:18
|
3 | if let Some(&ref mut v) = vec_2d.last() {
| ^^^^^^^^^ cannot borrow as mutable
Grab a mutable reference to the last element with last_mut; no need to change patterns.
fn main() {
let mut vec_2d = vec![vec![]];
if let Some(v) = vec_2d.last_mut() {
v.push(1);
}
println!("{:?}", vec_2d);
}
A (much) more elegant solution for this particular case would be:
fn main() {
let vec_2d = vec![vec![1i32]];
println!("{:?}", vec_2d);
}

Resources