slices & maps packages
PHP has around eighty array_* functions, plus sort, usort, in_array and friends. Go keeps its equivalents in two small packages, slices and maps. You've already used a few: slices.Sort in 0.4, slices.Clone in 2.3, slices.Sorted and maps.Keys in 2.5. Here's the rest of the toolkit.
The quick tour
| PHP | Go |
|---|---|
in_array($x, $xs, true) |
slices.Contains(xs, x) |
array_search($x, $xs, true) |
slices.Index(xs, x) |
sort($xs) |
slices.Sort(xs) |
usort($xs, $fn) |
slices.SortFunc(xs, fn) |
array_reverse($xs) |
slices.Reverse(xs) |
max($xs) |
slices.Max(xs) |
$a == $b |
slices.Equal(a, b) |
array_keys($m) |
maps.Keys(m) |
$copy = $m |
maps.Clone(m) |
Everything compares strictly, so there's no loose in_array to remember a true for. slices.Reverse works in place rather than returning a copy, and maps.Keys returns an iterator (2.5), so wrap it in slices.Collect when you want a slice. For PHP's array_unique, sort first and then call slices.Compact, which removes duplicates that sit next to each other. Functions that answer "where is it?" return -1 for "not found", because a Go function can't return false instead of an int. And max(a, b) and min(a, b), for two or more separate values, are built into the language.
Functions as values (just enough)
usort takes a closure, and so does slices.SortFunc. A Go function without a name, written inline, looks like this:
func(a, b Entry) int { return cmp.Compare(a.Taps, b.Taps) }
It's PHP's fn($a, $b) => $a['taps'] <=> $b['taps'], with types and braces. Like PHP's fn, it can use variables from around it without a use (...) clause. You'll see these anonymous functions everywhere the standard library wants "a bit of your logic": sorting, searching with slices.IndexFunc, and later HTTP handlers.
Sorting with a comparison
slices.Sort only works on things Go already knows how to order: numbers and strings. Try it on a slice of structs and you get a long compile error that starts Entry does not satisfy cmp.Ordered. For anything else, slices.SortFunc takes a comparison function. It returns a negative number if a comes first, a positive one if b does, and 0 if they tie, which is exactly what PHP's spaceship operator does.
cmp.Compare(x, y)is<=>. It returns -1, 0 or +1.- Swap the arguments to reverse the order.
cmp.Compare(b.Taps, a.Taps)puts the busiest first, like$b <=> $a. cmp.Or(...)returns the first of its arguments that isn't zero. It's PHP's?:chain, and it's how you write a tie-break:
slices.SortFunc(board, func(a, b Entry) int { return cmp.Or( cmp.Compare(b.Taps, a.Taps), cmp.Compare(a.Station, b.Station), ) })
flowchart TB accTitle: How cmp.Or breaks a tie accDescr: To compare two leaderboard entries, cmp.Or first compares their tap counts, busiest first. If the counts differ, that result decides the order. If they are equal, the comparison is zero, so cmp.Or moves on and compares the station names alphabetically, and that result decides instead. a["Compare taps<br/>busiest first"] --> q["A tie?"] q -->|no| d1["Taps decide"] q -->|yes| b["Compare names<br/>A to Z"] b --> d2["Names decide"]
SortFunc isn't stable: items that compare as equal can come out in any order. So either give it a tie-break, as above, or use slices.SortStableFunc, which keeps equal items in their original order.
Laravel corner
$stations->sortBy([['taps', 'desc'], ['station', 'asc']]) is the Collection version of this sort. In Go the same rule is a comparison function: one cmp.Compare per column, wrapped in cmp.Or, with the arguments swapped for desc.
The array_map that isn't there
The slices package has no Map, no Filter and no Reduce. That's deliberate: a for loop does the job, and it can filter and map in a single pass:
var busy []string for _, e := range board { if e.Taps > 100 { busy = append(busy, e.Station) } }
If you really want Map and Filter helpers, lesson 3.9 shows how to write them with generics in a few lines. Most Go code just writes the loop.
Mind the gap
Some functions change the slice, others return a new one. slices.Sort, slices.SortFunc, slices.Reverse and slices.Compact work in place on the slice you pass in, which, after 2.3, you know means anyone sharing that backing array sees the change too. slices.Sorted, slices.Clone and slices.Collect return a new slice. In PHP, sort changes its argument but array_reverse returns a copy, so you've had to know this before. Go's docs say "in place" when it matters.
Recap
slicesandmapshold Go'sarray_*functions. Searching is strict, and "not found" is -1.- An anonymous function is
func(a, b T) int { … }, Go's version of PHP'sfn. slices.SortFunctakes a comparison.cmp.Compareis<=>, swapping its arguments reverses the order, andcmp.Orchains tie-breaks.- There's no
MaporFilter. Aforloop does both. Sort,ReverseandCompactwork in place.Sorted,CloneandCollectreturn new slices.