Am trying to print unique contiguous sub-arrays of a Vec using a recursive function like so:
use std::collections::HashSet;
fn recurse<'a>(nums: &'a [i32], already_printed: &'a mut HashSet<&'a [i32]>) {
if !already_printed.contains(nums) {
println!("{:#?}", nums);
}
already_printed.insert(nums);
if nums.len() >= 2 {
recurse(&nums[0..nums.len() - 1], already_printed);
recurse(&nums[1..nums.len()], already_printed);
}
}
pub fn main() {
let k = vec![1, 2, 3, 4, 5];
let mut already_printed: HashSet<&[i32]> = HashSet::new();
recurse(&k[0..], &mut already_printed);
}
This of course, as experienced Rustaceans may have guessed already, fails to compile with the following error:
error[E0499]: cannot borrow `*already_printed` as mutable more than once at a time
--> src/main.rs:12:39
|
3 | fn recurse<'a>(nums: &'a [i32], already_printed: &'a mut HashSet<&'a [i32]>) {
| -- lifetime `'a` defined here
...
11 | recurse(&nums[0..nums.len() - 1], already_printed);
| --------------------------------------------------
| | |
| | first mutable borrow occurs here
| argument requires that `*already_printed` is borrowed for `'a`
12 | recurse(&nums[1..nums.len()], already_printed);
| ^^^^^^^^^^^^^^^ second mutable borrow occurs here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0499`.
I understand from the very helpful error why the compiler refuses to compile this. However, what would be a workaround, generally speaking, to implement recursive functions that take mutable references as shown in the above code?
A possible workaround method I could think of was using the interior mutability pattern à la RefCell:
use std::cell::RefCell;
use std::collections::HashSet;
fn recurse<'a>(nums: &'a [i32], already_printed: &'a RefCell<HashSet<&'a [i32]>>) {
if !already_printed.borrow().contains(nums) {
println!("{:#?}", nums);
}
already_printed.borrow_mut().insert(nums);
if nums.len() >= 2 {
recurse(&nums[0..nums.len() - 1], already_printed);
recurse(&nums[1..nums.len()], already_printed);
}
}
pub fn main() {
let k = vec![1, 2, 3, 4, 5];
let already_printed: HashSet<&[i32]> = HashSet::new();
let ref_cell: RefCell<HashSet<&[i32]>> = RefCell::new(already_printed);
recurse(&k[0..], &ref_cell);
}
While this works, this seems to be discarding the safety rails that the compile time borrow checker provides. Is there a different canonical way to make recursive function calls like the above while still having compile time borrow checker pass?