Introduction to GO comma ok idiom
Go is a very good language when it comes to testing different features or data in Go programs. Unlike other languages like Python that have the try catch error handling pattern, Go uses the famous comma ok pattern. The comma ok pattern is used to test certain statements in our code so that we can minimize developing programs that do things they are not intended to do.
In this article we are going to dive into situations that are ideal for using the comma ok pattern. To make the best out of this article, you should have the basics of the Go language. If not please read the Introduction to Go from the official website. The Go comma ok idiom is mostly used to :
- Test for error on a function return
- Testing if a key-value item exist in a Go map
- Testing if an interface variable is of certain type
- Testing if a channel is closed
Testing for errors on a function return
The comma ok idiom is most of the time used with functions that return more than one value, and one of the values is an error. Since there is no try catch pattern in Go, Go errors are treated as normal variables after being returned from a function. Consider a function that takes an integer as an argument and returns an error if a number is odd.
Example
package main
import (
"errors"
"fmt"
)
func main() {
num := 4
if ok, err := isEven(num); ok {
fmt.Printf("%d is divisible by 2 : %v \n", num, ok)
} else {
fmt.Println(err)
}
}
func isEven(num int) (bool, error) {
if num%2 != 0 {
return false, errors.New("Number not divisible by 2")
}
return true, nil
}
Explanation
In the above example, we define the isEven() function that takes an
integer as an argument and returns boolean and an error. This function
body checks if a number is divisible by 2 . This function will return a
false boolean and an error if the test fails, otherwise it will
return a true boolean and a nil for the error.
In the main function, we use the if statement to create the
comma ok pattern. The used syntax is ,
if ok, err := isEven(num); ok
Since the isEven() function returns two values, the values in the left
side of the assignment are the ok and err. The ok variable stores
the boolean value returned from the function. The err variable stores
the error in case err is not nil. Immediately after the function call ,
we have a semicolon and the ok variable. At this point, we are
checking if ok is true and execute the code in the block.
Output
$ go run main.go
4 is divisible by 2 : true
Testing if a key-value item exist in a Go map
The comma ok idiom can also be used to check if a key exists in a Go map. A Go map is made up of key value pair and the comma ok idiom will return true value if a key exists, else false.
Example
package main
import (
"fmt"
)
func main() {
httpConnection := map[string]string{
"url": "https://www.golinuxcloud.com/",
"method": "POST",
}
if v, ok := httpConnection["method"]; ok {
fmt.Printf("Value is : %s \n", v)
} else {
fmt.Println("Key not found")
}
}
Explanation
In the above example, we initialize a map httpConnection with key
value pairs of type string. The comma ok idiom has been used to check if
the “method” key exists in the map. The v variable stores the value
found in the httpConnection map if the key exists in the map.
Otherwise the v variable will store nil while the ok variable stores
false.
Output
$ go run main.go
Value is : post
Testing if an interface variable is of certain type
While writing code , it is important to always understand the type of data you are working with. Go offers type assertion which provides access to an interface value underlying a concrete value. The comma ok idiom can be used with type assertion to check if a value is of a certain type or not.
Example
package main
import (
"fmt"
)
func main() {
var v interface{} = 23
if s, ok := v.(string); ok {
fmt.Println(s, " is a string")
} else {
fmt.Printf("Variable type is %T\n", v)
}
}
Explanation
In the above example, we define a variable v of any type. This means
it can be assigned to any type in Go such as a string, bool, int
and so on. The comma ok idiom has been used here to check if variable
v is a string i.e if s, ok := v.(string); ok .In this example,
variable s will store the value being checked if the returned value for
the ok variable is true.
Output
$ go run main.go
Variable type is int
Testing if a channel is closed
The comma ok idiom is useful when working with Go channels. Channels in Go are like pipelines that allow data to pass through them from a sender to a receiver. The sender is always responsible for closing the channel and we can test this using the comma ok idiom.
Example
package main
import (
"fmt"
"time"
)
func main() {
companyChannel := make(chan string)
companies := []string{"Golinuxcloud", "Facebook", "Google"}
go func() {
for _, c := range companies {
companyChannel <- c
}
close(companyChannel)
}()
go func() {
for i := 0; i < 5; i++ {
if name, ok := <-companyChannel; ok {
fmt.Println(name)
} else {
fmt.Println("Channel closed!")
}
}
}()
time.Sleep(time.Second * 3)
}
Explanation
In the above example, we define a channel(companyChannel) of type
string and an array of string values(companies). We then spin a
goroutine
that loops through the company name and sends the names into the
companyChannel. We close the companyChannel after we are done
looping.
We then spin another
goroutine
that loops through integer values.Please note that the number of loops
here exceeds the number of names in the companies slice. For each loop ,
we check if the companyChannel is closed using the comma ok idiom. If
the channel is closed, we print “Channel closed” in the terminal.
Output
$ go run main.go
Golinuxcloud
Facebook
Google
Channel closed!
Channel closed!
Summary
In this article we learn about Go comma ok idiom and how it has been used in different situations in our code. The comma ok idiom is commonly used to test if a function returns an error, test if a key exists in a map, test if a variable is of a certain type using type assertion and lastly testing if a channel is closed.


