"owned" slice patterns

I have some code that uses the "slice pattern" like this:

struct Foo {
    a: i32,
    b: i32,
    c: i32,
}

fn bar(v: Vec<i32>) -> Vec<i32> {
    todo!()
}

fn main() {
    let apple = 1;
    let banana = 2;
    let cat = 3;

    let result = bar(vec![apple, banana, cat]);
    let [a, b, c] = result[..] else {panic!("not match")};
    let foo = Foo {
        a,
        b,
        c,
    };
}

It works fine, but only if i32 is copy-able and clone-able. Now I have some types that do not support copy or clone, for example:

struct NonCopyNonClone(i32);

struct Foo {
    a: NonCopyNonClone,
    b: NonCopyNonClone,
    c: NonCopyNonClone,
}

fn bar(v: Vec<i32>) -> Vec<NonCopyNonClone> {
    todo!()
}

fn main() {
    let apple = 1;
    let banana = 2;
    let cat = 3;

    let result = bar(vec![apple, banana, cat]);
    let [a, b, c] = result[..] else { panic!("not match") }; // won't compile
    let foo = Foo {
        a,
        b,
        c,
    };
}

Any way I can do this?

Vec implements TryInto<[T; N]> so you can use that to convert to owned arrays.

struct NonCopyNonClone(i32);

struct Foo {
    a: NonCopyNonClone,
    b: NonCopyNonClone,
    c: NonCopyNonClone,
}

fn bar(v: Vec<i32>) -> Vec<NonCopyNonClone> {
    todo!()
}

fn main() {
    let apple = 1;
    let banana = 2;
    let cat = 3;

    let result = bar(vec![apple, banana, cat]);
    let Ok([a, b, c]): Result<[_; 3], _> = result.try_into() else { panic!("not match") };
    let foo = Foo {
        a,
        b,
        c,
    };
}

The type annotations could be improved though.

3 Likes

It works, but most annoying part is that I need to clarify the length of the array, even tough I wrote [a,b,c] before, in this case the code is even more complicated than using pop :rofl:

#![feature(iter_next_chunk)]
let Ok([a, b, c]) = result.drain(..3).next_chunk() else { panic!("not match") };

can be replaced with result.into_iter() or any iterator that yields the owned elements.

Update:

for stable Rust, some crates can help

2 Likes

That's awesome, I don't even need to clarify the length, just using drain(..).

If you don't need the part of vec, it's better to consume the vec via .into_iter(), because drain seems to do more work.

And I've updated the answer in case someone are looking for stable solutions.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.