How do I empty a slice in a RefMut<&mut [u8]>? - rust

If I wanted to "empty" a slice normally, I could do something like this:
let mut data: &[u8] = &[1, 2, 3];
data = &[];
But I'm using a library that returns a RefMut<&mut [u8]>, and if I try to reset it the same way:
let mut data: RefMut<&mut [u8]> = account.data.borrow_mut();
data = &[];
I get told I need:
expected struct `RefMut`, found `&[_; 0]`
I try something like this:
let mut data: RefMut<&mut [u8]> = account.data.borrow_mut();
let cleared: &mut [u8] = &mut [];
let c = RefCell::new(cleared);
data = c.borrow_mut();
But then c is dropped while still borrowed. Am I going about this the wrong way?

You can use the dereference operator to write back to the RefCell.
let refcell: RefCell<&[u8]> = RefCell::new(&[1, 2, 3]);
{
let mut data = refcell.borrow_mut();
*data = &[];
// or equivalently, *refcell.borrow_mut() = &[];
}
println!("{:?}", refcell); // RefCell { value: [] }

Related

Problems trying to get intersection of a Vector

I am having a problem whilst trying to get the intersection of two Vectors.
impl Solution {
pub fn intersection(nums: Vec<Vec<i32>>) -> Vec<i32> {
// Intended strategy:
// Store the first element into an intersect_result
// Iterate over the remaining elements for each element:
// Determine the intersection of the current element and the intersect result
// set intersect result to this.
// Sort the intersect result
// Return the intersect result back to the caller.
let len:i32 = nums.len() as i32;
let intersect_result:Vec<i32> = nums[0].clone();
for i in 1..len{
println!("i is: {}", i);
let temp_vec:Vec<i32> = nums[i as usize].clone();
// find the intersection of the current element with the intersect result
let unique_a:HashSet<i32> = temp_vec.into_iter().collect();
let unique_b:HashSet<i32> = intersect_result.clone().into_iter().collect();
intersect_result = unique_a.intersection(&unique_b).collect::<Vec<_>>();
}
vec![]
}
}
The error message I get is:
= note: expected struct `Vec<i32>`
found struct `Vec<&i32>`
This happens in the call unique_a.intersection().
Any thoughts guys?
You can add a map(|i| *i) in the iterator chain that causes the error:
intersect_result = unique_a.intersection(&unique_b).map(|i| *i).collect::<Vec<_>>();
When fixing this, the code also seems to work as intended. I think there are a few improvements possible (probably more, but these immediately tracked my attention):
use hashbrown::HashSet;
pub fn intersection(nums: Vec<Vec<i32>>) -> Vec<i32> {
let mut intersect_result: Vec<i32> = nums[0].clone();
for temp_vec in nums {
let unique_a: HashSet<i32> = temp_vec.into_iter().collect();
intersect_result = unique_a
.intersection(&intersect_result.into_iter().collect())
.map(|i| *i)
.collect::<Vec<_>>();
}
intersect_result
}
fn main() {
let a = vec![1, 2, 3];
let b = vec![2, 3, 4];
let c = vec![3, 4, 5];
let v = vec![a, b, c];
let res = intersection(v);
println!("res: {:?}", res);
}

Rust: Map two Vecs into a third Vec of composite structs

I have three structs:
struct A;
struct B;
struct C {
a: Option<A>,
b: Option<B>
}
Given inputs Vec<A> and Vec<B> and some predicate function, I want to create an output Vec<C>, which is a combination of the elements of the inputs, something like the following:
let aVec: Vec<A> = vec![];
let bVec: Vec<B> = vec![];
let mut cVec: Vec<C> = vec![];
for a in aVec {
if let Some(b) = bVec.into_iter().find(predicate) {
cVec.push(C{a: Some(a), b: Some(b)});
}
}
Is there a way to do this without needing B to be copyable? Both input vectors aren't required after the operation. Also, is this possible without the loop?
You can:
Find the index of the element satisfying predicate. (I would use Iterator::position.)
remove or swap_remove the element at the position obtained by the previous step.
push the previously removed element into result.
In code:
use itertools; // 0.8.2
use itertools::Itertools;
struct A {}
struct B {
n: usize,
}
struct C {
a: Option<A>,
b: Option<B>
}
fn main() {
let aVec: Vec<A> = vec![];
let mut bVec: Vec<B> = vec![];
let mut cVec: Vec<C> = vec![];
for a in aVec {
if let Some(idx) = bVec.iter()
.position(|b| b.n==42)
{
let b = bVec.remove(idx); // or swap_remove if ordering does not need to be preserved
cVec.push(C{a: Some(a), b: Some(b)});
}
}
}

Why do I get "no method named `join` found for type `[usize]` in the current scope"?

fn example(books: Vec<usize>, n_books: usize) {
let fbooks = books[0..n_books].join(" ");
}
error[E0599]: no method named `join` found for type `[usize]` in the current scope
--> src/lib.rs:2:36
|
2 | let fbooks = books[0..n_books].join(" ");
| ^^^^ method not found in `[usize]`
I tried mapping usize to String, collecting into Vec and some more random stuff. I don't understand what's going on.
TLDR:
Since map() transforms one iterator into another iterator, you should provide an iterator first.
Try this:
fn example(books: Vec<usize>, n_books: usize) -> String {
books[0..n_books]
.iter()
.map(|u| u.to_string())
.collect::<Vec<_>>()
.join(" ")
}
fn main() {
let books: Vec<usize> = vec![1, 2, 3];
let n_books: usize = 2;
let result = example(books, n_books);
println!("{}", result); //"1 2"
}
Notes:
You should not join the usize vector items with &str type. You need to convert usize to string first then join it:
map(|u| u.to_string())
The standard library's join is defined only for slices, so the following code works:
let books: &[_] = &["1", "2", "3"];
let n_books: usize = 2;
let result = books[0..n_books].join(" ");
println!("{}", result); // "1 2"
Edit:
From your comment:
What's the difference using take(n) or a subscript operator (re-slicing books[0..n_books])
A slice is a type composed of a length and a pointer to a memory.
You may use .take(n_books) instead of re-slicing, which is an iterator that only iterates over the first n iterations of iter, try this:
let books: Vec<usize> = vec![1, 2, 3];
let n_books: usize = 2;
let result = books
.iter()
.take(n_books)
.map(|u| u.to_string())
.collect::<Vec<_>>()
.join(" ");
println!("{}", result); //"1 2"

Lifetimes of references in mutable Vector

I have an algorithm like:
let seed: Foo = ...
let mut stack: Vec<&Foo> = Vec::new();
stack.push(&seed);
while let Some(next) = stack.pop {
let more_foos: Vec<Foo> = some_function_of(next) // 0 to many Foos returned
for foo in more_foos {
stack.push(&foo);
}
}
I receive the error that foo does not live long enough. I assume this is because stack has a greater lifetime. How can I fix this?
more_foos and its contents are dropped at the end of each iteration of the while let loop. However, you're trying to store a reference to items from more_foos in stack, and that's not valid, as that would lead to dangling pointers.
Instead, you should make stack own Foo objects instead.
fn main() {
let seed: Foo = unimplemented!();
let mut stack: Vec<Foo> = Vec::new();
stack.push(seed);
while let Some(next) = stack.pop() {
let more_foos: Vec<Foo> = unimplemented!();
for foo in more_foos {
stack.push(foo);
}
}
}
Note: the for loop can be replaced with:
stack.extend(more_foos);
which might be slightly more efficient.

Why can't I make a reference to memory inside "if"?

I could make a copy of this vector, but that will take time and memory.
I could write another println, but this is just an example — instead of println there may be several loops — and it will take space and complicate the code. I could perform the conversion in main and write two versions of the function call, but changing the reference is much easier.
fn foo(mut a: &Vec<i32>) {
let mut c: Vec<i32>;
if a[0] == 0 {
c = vec![1; 3];
a = &c;
}
println!("{:?}", a);
}
fn main() {
let a: Vec<i32> = vec![0; 3];
foo(&a);
}
Error:
main.rs:9:14: 9:15 error: `c` does not live long enough
main.rs:9 a = &c;
^
The rules of lifetime in rust are quite (very) strict: if you have a reference to an object, this object must live longer than the reference, in both direction.
This means the reference must be created after the object.
In your case, a exists before c, so the assignment a = &c is invalid. A simple fix can be to create a copy of the reference after c is created and work on this copy:
fn foo(vec_ref: &Vec<i32>){
let mut c: Vec<i32>;
let mut a = vec_ref
if a[0] == 0 {
c = vec![1; 3];
a = &c;
}
println!("{:?}",a);
}
or in a more rusty way:
fn foo(vec_ref: &Vec<i32>){
let mut c: Vec<i32>;
let a = if vec_ref[0] == 0 {
c = vec![1; 3];
&c
} else {
vec_ref
};
println!("{:?}",a);
}

Resources