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

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);
}

Related

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);
}

Trying to modify a Vec of futures inside a Rc<RefCell<...>>

I try to wait and remove one-by-one future from a Vec of futures. It does not work. I understand why it does not work: Pin is not copyable. But how to correct this error?
extern crate futures;
use std::cell::{RefCell};
use std::rc::Rc;
use std::pin::Pin;
use std::future::Future;
use futures::channel::oneshot::Canceled;
use futures::executor::block_on;
use futures::future::select_all;
fn run_queries_body() {
let _futures: Vec<Pin<Box<dyn Future<Output=Result<(), Canceled>>>>> = Vec::new();
let futuresRc = Rc::new(RefCell::new(_futures)); // TODO: Cell instead
// This in actual could be called inside another future, so we need Rc<RefCell<...>>
let mut futures = futuresRc.borrow_mut();
let f3 = futures.iter().map(|x| *x);
let (_res, _idx, remaining_futures) = block_on(select_all(f3));
*futures = remaining_futures;
}
error[E0507]: cannot move out of `*x` which is behind a shared reference
--> src/lib.rs:16:37
|
16 | let f3 = futures.iter().map(|x| *x);
| ^^ move occurs because `*x` has type `std::pin::Pin<std::boxed::Box<dyn futures::Future<Output = std::result::Result<(), futures::channel::oneshot::Canceled>>>>`, which does not implement the `Copy` trait
The problem is not in the pin - a boxed future is safe to move along with its pin because box means the future is heap-allocated, so moving the box doesn't move the future. The pin serves to forbid moving the future out of its box, but you don't attempt that. Your code fails to compile because Vec::iter() iterates over references to elements, and you can't move an object out of a reference because it would leave the original value in an undefined state. This kind of move is only allowed for types that can be trivially copied such as numbers or bools, which is marked by the Copy trait. The compiler's message is confusing because it mentions Pin<...>, but it only does so because that's the literal type behind the reference, and the compiler reports that the type in question isn't Copy, without implying anything about Pin semantics.
A straightforward fix is to make futures a vector of options. That allows you to extract an element out of the vector just by possessing a mutable iterator to the element by calling Option::take on the &mut Option<T>. This is well-defined because it extracts the value, but also leaves None in the old place in the vector.
In your case you would iterate over the vector using iter_mut() (playground):
pub fn run_queries_body() {
let futures: Vec<Option<Pin<Box<dyn Future<Output = Result<(), Canceled>>>>>> = vec![];
let futures_rc = Rc::new(RefCell::new(futures));
let mut futures = futures_rc.borrow_mut();
let f3 = futures.iter_mut().map(|f| f.take().unwrap());
let (_res, _idx, remaining_futures) = block_on(select_all(f3));
*futures = remaining_futures.into_iter().map(Some).collect();
}
As pointed out by #Jmb, an even simpler approach is to use Vec::drain, which removes the elements from the vector and gives you an iterator over the removed elements (playground):
pub fn run_queries_body() {
let futures: Vec<Pin<Box<dyn Future<Output = Result<(), Canceled>>>>> = vec![];
let futures_rc = Rc::new(RefCell::new(futures));
let mut futures = futures_rc.borrow_mut();
let f3 = futures.drain(..);
let (_res, _idx, remaining_futures) = block_on(select_all(f3));
*futures = remaining_futures;
}

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 write a function that adds an element to a vector, allowing the element to be changed before insertion?

I'm trying to make a simple example involving a vector of structs to learn Rust. All examples of vectors in the Rust literature I've found only use vectors of integers.
I want to write a function aimed at filling a vector, allowing the possibility of the element to be inserted to be changed, I can't figure out what to do. I always got a compiler error[E0308]: mismatched types on
the push method, because elem is a reference to a Point. So
push() needs a Point structure because v is a vector of Point
but if I want to modify elem, I need to pass a (mutable?) reference
What is the right thing to do?
// structure used everywhere in Rust examples
#[derive(Debug)]
struct Point {
x: i16,
y: i16
}
fn add_element(v: &mut Vec<Point>, elem: &Point) {
// modify element
elem.x = 0;
// add element
v.push(elem);
}
// this example is meant to study a vector of structs
fn main() {
// declare 2 points. By default, live on the stack
let origin = Point {x:0, y:0};
println!("origin address\t: {:p}", &origin);
let mut p1 = Point {x:1, y:1};
println!("p1 address\t: {:p}", &p1);
// declare a new vector of structs. Allocation is made in the heap
// declare mutable because we'll add elements to vector
let mut v: Vec<Point> = Vec::new();
// add points
add_element(&mut v, &origin);
add_element(&mut v, &p1);
// change p1
p1.x = 2;
p1.y = 2;
}
Let's read the error messages together:
error[E0308]: mismatched types
--> src/main.rs:10:12
|
10 | v.push(elem);
| ^^^^ expected struct `Point`, found &Point
|
= note: expected type `Point`
= note: found type `&Point`
The code is attempting to store a reference to a Point in a Vec that is declared to hold entire Points. Since Rust is a statically- and strongly- typed language, the compiler tells you that you cannot do that. The fix is to accept a Point by value:
fn add_element(v: &mut Vec<Point>, elem: Point)
This leads to the next error:
error: cannot assign to immutable field `elem.x`
--> src/main.rs:9:5
|
9 | elem.x = 0;
| ^^^^^^^^^^
You cannot change members of elem because it is not marked as mutable. Mutability of a value is a property of the binding, so let's do that:
fn add_element(v: &mut Vec<Point>, mut elem: Point)
Then change the calling of that function to adapt:
fn main() {
let origin = Point { x: 0, y: 0 };
let p1 = Point { x: 1, y: 1 };
let mut v = Vec::new();
add_element(&mut v, origin);
add_element(&mut v, p1);
}
Note that neither origin nor p1 need to be mutable because this function doesn't modify either while it owns it. It transfers ownership to add_element, which chooses to make it mutable.
but if I want to modify elem, I need to pass a (mutable?) reference
As you can see, you can simply make the elem parameter mutable when transferring the entire value to the function. Since the function owns that value, it has full control over it, including choosing to make it mutable.

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