Asking whether a value is there
Often you need to know whether a Vec holds some value: is this name on the guest list, is this item in the cart? The method contains answers that with a bool. It compares the items with the value from the first one on, returns true as soon as one matches, and returns false if none does.
let colors = vec!["red", "green", "blue"];
println!("{}", colors.contains(&"red")); // true
println!("{}", colors.contains(&"pink")); // false
A run prints true and then false.
Why the &
contains takes a reference to the value, not the value itself, so you write & in front of it. Without it the code doesn't compile. For a vector of &str, colors.contains("red") is rejected with "expected &&str, found &str"; the vector's items are &str, so the argument must be a reference to one.
The same goes for other item types. With a Vec<i32> you write nums.contains(&8). With a Vec<String> and a String variable called name, you write names.contains(&name).
Using it in an if
The answer is a bool, so it goes right into an if. Put ! in front for the opposite: !colors.contains(&x) is true when x is missing.
let cart = vec!["milk", "bread"];
if cart.contains(&"milk") {
println!("Milk is in the cart");
}
Text must match exactly, upper and lower case included. colors.contains(&"Red") is false, because the vector has "red".
Details worth knowing
An empty vector never contains anything, so contains is false for it. A vector with repeated values is fine: vec![4, 4, 4].contains(&4) is true, and the search stops at the first match.
A common use is to add an item only when it is new. If seen is a Vec<&str> and w is "b", then if !seen.contains(&w) { seen.push(w); } adds "b" the first time and does nothing the second time, so seen ends as ["a", "b"]. When you need the position of a value rather than a yes or no, a different method is needed; contains only answers the question "is it there?".
The task, step by step
The bag is ["map", "water", "snacks"]. The first check asks whether it holds "water", and the print runs when it does. The second check asks whether it does not hold "tent", using !, and prints Pack a tent when that is true.
let bag = vec!["map", "water", "snacks"];
if bag.contains(&"water") {
println!("Water is packed");
}
if !bag.contains(&"tent") {
println!("Pack a tent");
}
It prints:
Water is packed
Pack a tent
Why two separate ifs
The two checks in the task are independent questions, so they are two separate if blocks, not an if with an else. The bag does hold water, so the first message prints. The bag does not hold a tent, so the second condition, !bag.contains(&"tent"), is true and its message prints as well. An else would only run when the first check failed, which is not what the task asks for. Reading the condition aloud helps: "if the bag does not contain a tent".
Common mistakes
- Leaving out the
&, which is a compile error. - Putting the
!in the wrong place. It goes before the whole call:!bag.contains(&"tent"). - Expecting a match on different capitalisation, such as
"Water"for"water".
Key takeaways
v.contains(&x)istruewhen the vector holdsx.- Write
!v.contains(&x)for "x is missing". - The match is exact, and the argument is always a reference.
