Reputation: 571
The tutorial shows some very basic examples of pattern matching, such as matching over an integer to emulate a c-style switch statement. The tutorial also shows how to do basic destructuring over a tuple type, and destructuring structures.
It seems like it should be possible to pattern match over a vector but I cannot figure out the right syntax for it and I haven't found any examples of it.
For example, in Haskell you can easily destructure a list:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr func initValue [] = initValue
foldr func initValue (x:xs) = func initValue $ foldr initValue func xs
So, looking at a rough translation, it would be nice to be able to do:
fn foldr<A, B>(func: fn(A, B) -> B,
initValue: B,
vals: [A]) -> B {
alt vals {
[] { ret initValue; }
_ {
let h = vec::head(vals),
t = vec::tail(vals);
ret foldr(func, func(initValue, h), t);
}
}
}
Note: I know you could use an if statement here, I am just using this as an example of pattern matching over a vector.
This currently returns:
patterns.rs:10:4: 10:5 error: constant contains unimplemented expression type
patterns.rs:10 [] { ret initValue; }
^
error: aborting due to previous errors
There is an example in the tutorial for destructuring structures (defined with { .. }
) and tuples (defined with ( .. )
), so it seems like there should be built-in support for vectors as well considering they also contain a special syntax (defined with [ .. ]
).
Feel free to correct me if I am using vectors in the wrong way as well.
Upvotes: 41
Views: 40139
Reputation: 3718
match
the vector in complete and guard the match arms:
fn vec_alt<T>(vals: Vec<T>) -> &'static str {
match vals {
v if v.len() == 2 => "two elements",
v if v.len() == 3 => "three elements",
_ => "otherwise",
}
}
The slice pattern solution becomes a bit bulky from vector lengths above 10 and for dynamic lengths it doesn't work at all, e.g. for a query like if v.len() > 7
.
Upvotes: 2
Reputation: 1008
You need slice patterns:
fn vec_alt<T>(vals: Vec<T>) -> &'static str {
match vals[..] {
[a, b] => "two elements",
[a, b, c] => "three elements",
_ => "otherwise",
}
}
Upvotes: 60
Reputation: 1114
I wish I could give more general advice on how to best use pattern matching on vectors, but here's how you can use them to test for empty vectors (at least I think that's what that Haskell code is doing...):
use std;
import std::io::println;
fn main() {
let empty: [int] = [];
println(vec_alt(empty));
println(vec_alt([1,2,3]));
}
fn vec_alt<A>(vals: [A]) -> str {
alt vals {
x if x == [] { "empty" }
_ { "otherwise" }
}
}
Note that trying to simply pass []
as an argument fails because the compiler can't infer a type for the vector. It seems to be possible to pass [()]
(a vector with a nil
inside) without first declaring it, but the alt
statement seems incapable of testing to see if the head expression matches [()]
(it simply falls through to the default).
All in all, vectors seem a little rough at the moment. If there's some specific use you have in mind that Rust doesn't seem to support, the developers are quite open to suggestions and critcism: https://mail.mozilla.org/listinfo/rust-dev
Also see the reference manual for a more formal definition, and a few more examples to help clarify things: http://doc.rust-lang.org/doc/rust.html#alternative-expressions
Upvotes: 8