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.
Further Reading