Slice with the ability to access the root array


#1

I’m creating a recursive function. Each call to the function modifies a single element in the array, then calls itself to modify the subsequent elements in the array. Once it gets to the end of the array, the entire array is processed not just the small segment that is in the current context.

I was thinking of going with something like:

use std::ops::{Index, IndexMut};

struct ShrinkWrap<'a, T : 'a>
{
	offset : usize,
	data : &'a mut Vec<T>
}

impl<'a, T> ShrinkWrap<'a, T>
{
	pub fn new(
		data : &'a mut Vec<T>
		) -> ShrinkWrap<T>
	{
		ShrinkWrap {
			offset : 0,
			data : data
		}
	}
	
	pub fn len(&self) -> usize
	{
		self.data.len() - self.offset
	}
	
	pub fn remaining(
		&'a self
		) -> ShrinkWrap<T>
	{
		ShrinkWrap {
			offset : self.offset + 1,
			data   : self.data
		}
	}
	
	pub fn full(&self) -> &Vec<T>
	{
		&self.data
	}
}

impl<'a, T> Index<usize> for ShrinkWrap<'a, T>
{
	type Output = T;
	
	fn index<'b>(&'b self, index : usize) -> &'b T
	{
		&self.data[self.offset + index]
	}
}

impl<'a, T> IndexMut<usize> for ShrinkWrap<'a, T>
{
	fn index_mut<'b>(&'b mut self, index : usize) -> &'b mut T
	{
		&mut self.data[self.offset + index]
	}
}

fn main() {
    let mut vec = vec!(1, 2, 3, 4, 5);
    let shrink  = ShrinkWrap::new(&mut vec);
    let shrunk  = shrink.remaining();
    
    println!("{}", shrunk[0]);
}

So that my function looks clean, just modifying index 0, and calling itself with remaining() until len() is 1.

However the remaining() function is wrong. First I’m getting an error E0389 which I can’t actually find defined anywhere. Second I feel like I should be specifying a lifetime on the object that is returned so the compiler knows that this element cannot outlive the parent.

Anyone see a way to make the above class actually work?

Maybe I just need to stuff this in a class with the vectors as member variables and pass slices from those variables into the methods.


#2

One simple solution:

fn process(data: &mut [u32], i: usize) {
    if i < data.len() {
        data[i] *= 10;
        process(data, i + 1)
    } else {
        for j in 0 .. data.len() {
            data[j] += 1;
        }
    }
}

fn main() {
    let mut data = vec![10, 20, 30, 40];
    process(&mut data, 0);
    println!("{:?}", data);
}

#3

The code is basically right. The error is cannot borrow data mutably in a `&` reference. This is because ShrinkWrap wants to allow the vector to be mutated, but the remaining method takes an immutable reference. Changing the argument of remaining to &'a mut self fixes that. (The variable in main also needs to be mutable for the example to compile.)

A lifetime is required on the returned ShrinkWrap object, but since there’s only one thing it could be ('a) the compiler can figure it out. The ability to leave out lifetimes sometimes is known as elision. If you prefer to be explicit, you can give the return value as ShrinkWrap<'a, T>.


#4

Ouch, so close, yes that works, thanks.