The question
Often you need to know whether a slice holds some value. Is this name on the guest list? Is this item in the cart? Go has no in keyword for slices. Since Go 1.21 the slices package answers the question with slices.Contains, which the lesson's code already imports. Before that, people wrote a loop.
slices.Contains
slices.Contains(s, x) compares each item of s with x, from the first one on. It returns true as soon as one matches, and false if none does.
colors := []string{"red", "green", "blue"}
fmt.Println(slices.Contains(colors, "red")) // true
fmt.Println(slices.Contains(colors, "pink")) // false
An empty slice holds nothing, so slices.Contains([]string{}, "x") is false.
Use it as an if condition
The result is a bool, so it fits straight into an if. Put ! in front to ask the opposite: !slices.Contains(s, x) is true when x is missing.
if !slices.Contains(colors, "pink") {
fmt.Println("No pink yet")
}
This prints No pink yet.
What it replaces
Without the helper you would write a loop and a flag:
found := false
for _, item := range cart {
if item == "bread" {
found = true
break
}
}
That is five lines for one yes-or-no answer, and slices.Contains(cart, "bread") does the same in one. The break corresponds to returning at the first match: the search stops as soon as the value is found.
A typical use is a guest list. With guests := []string{"Ana", "Ben"}, checking "Ben" reports that he is on the list, while "Cara" is not.
It works for any element type that can be compared with ==, such as numbers and strings. For nums := []int{4, 8, 15}, slices.Contains(nums, 8) is true and slices.Contains(nums, 9) is false.
Because it looks at every item until a match, a long slice takes longer to search than a short one. For a handful of items that doesn't matter.
Checking several values
Because the call is a plain expression, you can use it inside a loop to check many values against one list:
guests := []string{"Ana", "Ben"}
for _, who := range []string{"Ben", "Cara"} {
if slices.Contains(guests, who) {
fmt.Println(who, "is on the list")
} else {
fmt.Println(who, "is not on the list")
}
}
This prints:
Ben is on the list
Cara is not on the list
Traps
- Text must match exactly.
slices.Contains(colors, "Red")isfalse, because the slice has"red", with a lowercase letter. A name with a trailing space, such as"Ben ", doesn't match"Ben"either. - The value must have the slice's element type. Check a
[]intwith a number, a[]stringwith text. - You get a yes or no, not a position. If you need the position,
slices.Index(colors, "blue")returns2, and-1when the value is missing.
The task: packing for a hike
bag holds map, water and snacks. The task has two checks.
- If
"water"is inbag, printWater is packed. The bag has water, so the condition is true and the line prints. - If
"tent"is not inbag, printPack a tent. This one needs the!: the bag has no tent, so!slices.Containsis true.
bag := []string{"map", "water", "snacks"}
if slices.Contains(bag, "water") {
fmt.Println("Water is packed")
}
if !slices.Contains(bag, "tent") {
fmt.Println("Pack a tent")
}
The output is:
Water is packed
Pack a tent
Reading the task
Each of the two checks is its own if, written one after the other, and each decides on its own whether to print. The first asks "is it in?", the second "is it missing?". Mixing them up, for example forgetting the ! in the second check, would print nothing at all, since the bag has no tent and the condition would then be false.
Key takeaways
slices.Contains(s, x)is true when the slice holdsx, and false otherwise.- Use it as the condition of an
if; add!to test for a missing value. - Matching is exact, including upper and lower case.
