The Comma Ok Idiom
A common idiom in Go
Introduction
I've recently been working a lot more in Go and decided to read through effective go, a large document containing tips on how to write clear, idiomatic Go code.
I love that Go is very opinionated on how things should be done, and as part of my study of this document I hope to write a number of reference articles describing some aspects of it.
Multiple return values
If you are not familiar with Go, one unique aspect of this language is that functions and methods can return multiple values.
In A Tour of Go, they use the following example to demonstrate this:
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
// Output: world hello
Here we see the swap
function, which takes in two strings,
and returns two strings.
func swap(x, y string) (string, string)
This ability to return multiple values is very powerful, and sets up many idiomatic patterns in Go. This includes error handling, comma ok, and more.
Comma ok
Let's imagine a requirement: we have a map that holds a list of employees,
and we need to get a specific employee's ID number (stored as an int
).
We might start by creating a function with the following signature:
func SearchEmployee(name string) int
Then to use it, we can call it like so:
func NotifyEmployee(name string) {
employeeID := SearchEmployee(name)
// business logic with employee id
}
However this poses a problem, what if the name doesn't exist in our map?
In that case, employeeID
would default to the zero value,
which for int
is 0
. In other languages, you might return a -1
to signal
that the user was not found, but since Go supports multiple return values,
we can follow the "comma, ok" idiom.
We would change the signature to:
func SearchEmployee(name string) (id int, ok bool)
Then call it like so:
func NotifyEmployee(name string) {
employeeID, ok := SearchEmployee(name)
if !ok {
// logic to handle if employee id
// can't be found or doesn't exist
}
// business logic with employee id
}
This is used in many places in the standard library and very common when working with maps.
Basic implementation of SearchEmployee
Since Go uses the "comma, ok" idiom for maps,
a basic implementation of SearchEmployee
could look like this:
var employees = map[string]int{
"Alice S": 0,
"Bob C": 1,
"Doug F": 2,
// ... other employees
}
func SearchEmployee(name string) (id int, ok bool) {
if employee, ok := employees[name]; ok {
return employee, true
}
return 0, false
}
Other uses
This same pattern is followed for type assertions, another topic I'd love to write about it's power in the future! Here is a sneak peek:
truck, ok := vehicle.(Truck)
if ok {
fmt.Println("🚛")
} else {
fmt.Println("not a 🚛")
}
There are many places where the "comma, ok" pattern is useful in Go and I've found it to be a clean idiom that is very nice to use.
What do you think? Let me know @bstncartwright