Is it possible to pattern match Box<[T]>?

Seeing how slice pattern matching work, I feel like the following snippet should just work.

use std::vec::Vec;
use std::boxed::Box;

enum S {
    L,
    R(Box<[i32]>),
}

fn main() {
    let s: Vec<i32> = vec![1, 2, 3];
    let v: S = S::R(s[..].into());

    match v {
        S::R([1, 2, ..]) => println!("yep"),
        S::R([2, ..]) => println!("bof"),
        _ => println!("nope"),
    }
}

As a noob I think of Box<T> as an owned &T so that it is strictly more powerful, thus I feel like the necessary cast should be possible, but I don't see how.

Am I doing something wrong ?

It's not currently possible to pattern match a box directly. If you need a reference to the inner value, convert it to a reference (however you like, eg. deref-then-reference, the as_ref method, etc.).

If you need the inner value itself (not possible with unsized types like slices, but it works with sized types), then simply dereference the box, which will move out of it.

impl S {
    fn as_slice(&self) -> Option<&[i32]> {
        match self {
            S::R(slice) => Some(slice),
            S::L => None,
        }
    }
}

fn main() {
    let s: Vec<i32> = vec![1, 2, 3];
    let v: S = S::R(s[..].into());
    match v.as_slice() {
        Some([1, 2, ..]) => println!("yep"),
        Some([2, ..]) => println!("bof"),
        _ => println!("nope"),
    }
}

playground

No. While for &T, there’s a & pattern, Box<T> does not have a “box” pattern (at least on stable Rust). It’s generally often-ish the case, that deeper pattern matching in Rust needs to happen in multiple steps… in this concrete example where you’re not trying to extract any values, you can still get away with putting the second step into a guard:

match &v {
    S::R(x) if matches!(**x, [1, 2, ..]) => println!("yep"),
    S::R(x) if matches!(**x, [2, ..]) => println!("bof"),
    _ => println!("nope"),
}
3 Likes

I did. Here:

Oh, sorry. I always scold people for not reading previous replies, but now did this myself :cold_sweat:

2 Likes

While this may be a solution, it seems a bit tedious for any non trivial tree. My use case pattern matching on AST so I would need the as_slice to traverse recursively the tree to be able to consider deeper nodes in the matching, but then I could no longer use bindings in the pattern.

It definitely works for simpler cases like Result<Box<str>, _> though !

I see, it is a bit of a shame in my opinion, because I don't see why this should be treated differently from &T in this case, but it is what it is. Hopefully the experimentation in the nighly lead to a nice new feature.

My problem is that it is not possible to use the &* trick when I am looking at a tree of boxed nodes. So I need to decompose layer by layer and the pattern matching become basically useless.

For the Box case there are box_patterns. For more general case (Rc or Arc instead of Box) there is no compiler support yet but I found a crate which attempts it.