Cannot access mutable reference in a vector by indexing - vector

I need to iterate over a vector of mutable references; here is a simplified reproduction:
trait Ticking {
fn tick(&mut self);
}
trait Fish {}
struct World<'a> {
fish: Vec<&'a mut dyn Fish>,
}
impl<'a> Ticking for World<'a> {
fn tick(&mut self) {
let _fish: &mut dyn Fish = self.fish[0];
//let _fish: &mut dyn Fish = self.fish.get_mut(0).expect("expected value");
}
}
struct Guppy<'a> {
n_ref: &'a usize,
}
impl<'a> Fish for Guppy<'a> {}
fn main() {
let mut guppy: Guppy = Guppy { n_ref: &5 };
let _world: World = World {
fish: vec![&mut guppy],
};
}
I received the following error:
error[E0596]: cannot borrow data in an index of `std::vec::Vec<&mut dyn Fish>` as mutable
--> src/main.rs:15:36
|
15 | let _fish: &mut dyn Fish = self.fish[0];
| ^^^^^^^^^^^^ cannot borrow as mutable
|
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::vec::Vec<&mut dyn Fish>`
I attempted to call get_mut directly and received a lifetime bound error:
error[E0277]: the trait bound `&'a mut (dyn Fish + 'a): Fish` is not satisfied
--> src/main.rs:13:36
|
13 | let _fish: &mut dyn Fish = self.fish.get_mut(0).expect("expected value");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Fish` is not implemented for `&'a mut (dyn Fish + 'a)`
|
= note: required for the cast to the object type `dyn Fish`
The compiler explanations were unhelpful in determine the root cause here.

You are (1) using the wrong syntax for indexing and (2) your type mismatches:
let _fish: &mut &mut dyn Fish = &mut self.fish[0];
// ^^^^ 2 ^^^^ 1
There's no reason to have an explicit type here anyway:
let _fish = &mut self.fish[0];
See also:
How can I use `index_mut` to get a mutable reference?
What is the return type of the indexing operation?

The compiler incorrectly chooses the Index trait over the IndexMut trait here, and gives a factually wrong error message. I filed a bug for this behaviour, but it turns out that this is actually fixed in the beta and nightly versions of Rust. Beta will be released as stable next week, so in the future your code will just work.
In the meantime, there are several ways of making the code work on the current stable version and older versions of Rust. The most succinct way is to force the compiler to choose IndexMut by adding &mut only on the right-hand side of the assignment:
let _fish: &mut dyn Fish = &mut self.fish[0];
The right-hand side has type &mut &mut dyn Fish now, so a deref coercion will be applied by the compiler. Alternatively, you can explicitly dereference the right-hand side, *&mut self.fish[0].

Related

Add value to a HashSet in Rust and add a reference to it to another datastructure

I'm trying to return a Vector from a function. This happens in a loop and I need the values to exist outside of the loop. Since I perform the return multiple times and I only need the unique values, I thought I use a HashSet for this, in which I insert and then try to get a reference to the value in the next line.
I need a reference to the value in multiple other datastructures and don't want to duplicate the actual values. The values don't need to be mutable.
What I tried
use std::collections::HashSet;
fn main() {
let mut vec: Vec<&str> = Vec::new();
let mut books = HashSet::new();
for i in 0..5 {
// This could be a function call, which returns a vector of objects, which should all be
// stored centrally and uniquely in a HashSet
books.insert("A Dance With Dragons".to_string());
let mut reference: &str = books.get("A Dance With Dragons").unwrap();
// This would be done for multiple "refering" datastructures
vec.push(reference);
}
}
What I was expecting
Getting a pointer to the String in the HashSet for future use.
What actually happens
error[E0502]: cannot borrow `books` as mutable because it is also borrowed as immutable
--> src/main.rs:10:9
|
10 | books.insert("A Dance With Dragons".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
11 |
12 | let mut reference: &str = books.get("A Dance With Dragons").unwrap();
| --------------------------------- immutable borrow occurs here
13 | // This would be done for multiple "refering" datastructures
14 | vec.push(reference);
| ------------------- immutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
warning: `set_test` (bin "set_test") generated 2 warnings
error: could not compile `set_test` due to previous error; 2 warnings emitted
I think I'm missing a very obvious solution to this...
Thanks in advance for helping.
You can't do this
use std::collections::HashSet;
fn main() {
let mut v: Vec<&str> = Vec::new();
let mut books = HashSet::new();
for i in 0..5 {
// this needs to borrow mutably
books.insert("A Dance With Dragons".to_string());
// this reference has to live as long as v
// so on the second iteration books is still borrowed
// which means you can't borrow it mutably any more.
let reference: &str = books.get("A Dance With Dragons").unwrap();
v.push(reference);
}
// v only goes out of scope here
}
You might find success in separating mutation and referencing like this:
fn main() {
let mut books = HashSet::new();
for i in 0..5 {
books.insert("A Dance With Dragons".to_string());
}
let v: Vec<&str> = books.iter().collect();
}
Or by using a Rc like pigeonhgands suggests.
fn main() {
let mut v: Vec<Rc<str>> = Vec::new();
let mut books = HashSet::new();
for i in 0..5 {
books.insert(Rc::new("A Dance With Dragons".to_string()));
// note: this clone is cheap cause it only clones the `Rc` not the whole String.
let reference = books.get("A Dance With Dragons").unwrap().clone();
v.push(reference);
}
}
The issue is that's the value in "book" could be removed and you try to save reference in a vector. It is a risk of null pointer.
You need to build book in imutable way, like this
use std::collections::HashSet;
fn main() {
let mut vec: Vec<&str> = Vec::new();
let books: HashSet<String> = vec!(
"A Dance With Dragons".to_string(),
"A Dance With Dragons".to_string()).into_iter().collect();
let reference: &str = books.get("A Dance With Dragons").unwrap();
vec.push(reference);
}

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

How to pass a vector as a parameter in rust

I am trying to write a function that prints a vector. I am having some trouble in understanding how to pass a vector as a parameter. This is what I have so far:
fn vecprinter(v1: &mut Vec<u32>) -> Vec<u32> {
v1
}
fn main(){
let mut v1=vec![1,10,11,12,13];
println!("{:?}", vecprinter(v1));
}
However I am getting this error:
error[E0308]: mismatched types
--> main.rs:3:1
|
1 | fn vecprinter(v1: &mut Vec<u32>) -> Vec<u32> {
| -------- expected `std::vec::Vec<u32>` because of return type
2 |
3 | v1
| ^^
| |
| expected struct `std::vec::Vec`, found mutable reference
| help: try using a conversion method: `v1.to_vec()`
|
= note: expected struct `std::vec::Vec<u32>`
found mutable reference `&mut std::vec::Vec<u32>`
error[E0308]: mismatched types
--> main.rs:10:31
|
10 | println!("{:?}", vecprinter(v1));
| ^^
| |
| expected mutable reference, found struct `std::vec::Vec`
| help: consider mutably borrowing here: `&mut v1`
|
= note: expected mutable reference `&mut std::vec::Vec<u32>`
found struct `std::vec::Vec<{integer}>`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
compiler exit status 1
What am I doing wrong?
You have two issues here.
Firs your vecprinter method takes a &mut Vec<u32 as a parameter, but you are passing it a Vec<u32> in your call to println!. To resolve this pass a mutable reference t to the vec instead:
println!("{:?}", vecprinter(&mut v1));
The second issue is with the return types of the vecprinter method. You are taking in a &mut Vec<u32> and expecting to return a Vec<u32>; however, when you return the value of v1 you are returning a &mut Vec<u32> rather than the expected Vec<u32>. Depending on your requirements you have two options.
Change the return type of the vecprinter method and pass a mutable reference:
fn vecprinter(v1: &mut Vec<u32>) -> &mut Vec<u32> {
v1
}
fn main(){
let mut v1=vec![1,10,11,12,13];
println!("{:?}", vecprinter(&mut v1));
}
or change the parameter value to take the vector rather than a reference:
fn vecprinter(v1: Vec<u32>) -> Vec<u32> {
v1
}
fn main(){
let mut v1=vec![1,10,11,12,13];
println!("{:?}", vecprinter(v1));
}
You wrote in your question:
I am trying to write a function that prints a vector.
But the function you wrote (no matter if it works or not) is not writing anything: it returns the given vector.
A function which would print something would look like this:
fn print_something(to_print: /*Some type*/) /*No return type*/ {
println!(/*...*/);
}
As you want to print a vector of u32, the prototype could be:
fn print_something(to_print: Vec<u32>) { /*...*/ }
But if you do that, the argument will be moved into the function and will become unusable outside of it. In order to improve this, you can pass the argument as a reference:
fn print_something(to_print: &Vec<u32>) { /*...*/ }
To handle more general cases (&Vec<u32> + &[u32]), you can still improve it like this:
fn print_something(to_print: &[u32]) { /*...*/ }
Now when you call this function, you have to add an ampersamp & to the given argument (unless it's already a reference):
print_something(&my_vector);
Finally, by gluing everything together, you have this:
fn print_vec(v: &[u32]) {
println!("{:?}", v);
}
fn main() {
let v = vec![1, 10, 11, 12, 13];
print_vec(&v);
// Because we changed "&Vec<u32>" to "&[u32]", the following is also
// possible:
let arr = &[1, 10, 11, 12, 13];
print_vec(arr);
}

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