Anup
Anup

Reputation: 1011

Returning an array/slice of `u32` from a function

I have a reasonably simple function (let's call it intersection) that takes two parameters of type &[u32] and I'd like the return type to be &[u32]. This function takes in two slices(arrays?), and returns a new slice(array?) containing elements that are in both slices.

pub fn intersection<'a>(left: &'a [u32], right: &'a [u32]) -> &'a [u32] {
    let left_set: HashSet<u32> = left.iter().cloned().collect();
    let right_set: HashSet<u32> = right.iter().cloned().collect();
    
    // I can't figure out how to get a
    // `&[u32]` output idiomatically  
    let result: &[u32] = left_set
        .intersection(&right_set)
        .into_iter()
        .....
        .....

    
    result //<- this is a slice
}

I suppose I could do something like create a Vec<u32> but then borrow checker doesn't like me returning that Vec<u32>.

pub fn intersection<'a>(left: &'a [u32], right: &'a [u32]) -> &'a [u32] {
   .....
   .....
   let mut result: Vec<u32> = left_set
        .intersection(&right_set)
        .into_iter()
        .cloned()
        .collect();
    result.sort();

    result.as_slice()  //<-- ERROR cannot return reference to local variable 
      // `result` returns a reference to data owned by the current function
}

I'm probably missing a trick here. Any advice on how to do this idiomatically in Rust?

Upvotes: 3

Views: 2726

Answers (1)

Masklinn
Masklinn

Reputation: 42492

This function takes in two arrays

No, it takes two slices.

I'm probably missing a trick here. Any advice on how to do this idiomatically in Rust?

There is no trick and you can't. A slice is a form of borrow, by definition a slice refers to memory owned by some other collection (static memory, a vector, an array, ...).

This means like every other borrow it can't be returned if it borrows data from the local scope, that would result in a dangling pointer (as the actual owner will get destroyed when the scope ends).

The correct thing to do is to just return a Vec:

pub fn intersection<'a>(left: &'a [u32], right: &'a [u32]) -> Vec<u32> {
   left.iter().collect::<HashSet<_>>().intersection(
       &right.iter().collect()
   ).map(|&&v| v).collect()
}

Or if it's very common for one of the slices to be a subset of the other and you're happy paying for the check (possibly because you can use something like a bitmap) you could return a Cow and in the subset case return the subset slice:

pub fn intersection<'a>(left: &'a [u32], right: &'a [u32]) -> Cow<'a, [u32]> {
    if issubset(left, right) {
        Cow::Borrowed(left)
    } else if issubset(right, left) {
        Cow::Borrowed(right)
    } else {
        Cow::Owned(
            left.iter().collect::<HashSet<_>>().intersection(
                &right.iter().collect()
            ).map(|&&v| v).collect()
        )
    }
}

Upvotes: 5

Related Questions