The Go Idioms

Posted May 13, 2023 by Rohith ‐ 3 min read

Following are the 9 most important idioms used in go programming. defer, `comma, ok` idiom, `range` idiom, Goroutines, Channels, Select statement, Interfaces, Zero value, Error handling

  1. defer: The defer keyword schedules a function call to be executed when the current function returns.
func foo() {
    defer fmt.Println("deferred function called")
    fmt.Println("function called")
}

  1. “comma, ok” idiom: A technique for checking if a value is present in a map or if a channel is closed. It involves using a two-value assignment in combination with the ok boolean to determine if the value exists or the channel is open.
value, ok := myMap[key]
if ok {
    // handle value
} else {
    // key does not exist
}

  1. “range” idiom: A technique for iterating over a collection, such as an array, slice, map, or channel. It involves using the range keyword and a loop to iterate over the collection.
for index, element := range myList {
    // handle element at index
}

  1. Goroutines: A lightweight thread of execution that can be created with the go keyword. Goroutines are a key feature of Go and allow for concurrent programming.
func worker(done chan bool) {
    fmt.Println("working")
    time.Sleep(time.Second)
    fmt.Println("done")

    done <- true
}

func main() {
    done := make(chan bool, 1)
    go worker(done)
    <-done
}

  1. Channels: A fundamental primitive for concurrent communication and synchronization between goroutines.
func producer(ch chan<- int) {
    for i := 0; i < 5; i++ {
        ch <- i
    }
    close(ch)
}

func consumer(ch <-chan int) {
    for val := range ch {
        fmt.Println(val)
    }
}

func main() {
    ch := make(chan int)
    go producer(ch)
    consumer(ch)
}

  1. Select statement: A control structure that allows for waiting on multiple channel operations simultaneously. It is commonly used in conjunction with channels to coordinate concurrent operations.
func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)

    go func() {
        time.Sleep(1 * time.Second)
        ch1 <- 1
    }()

    go func() {
        time.Sleep(2 * time.Second)
        ch2 <- 2
    }()

    for i := 0; i < 2; i++ {
        select {
        case val := <-ch1:
            fmt.Println("ch1:", val)
        case val := <-ch2:
            fmt.Println("ch2:", val)
        }
    }
}

  1. Interfaces: A set of methods that define a contract between different types. Interfaces are a powerful feature of Go and enable polymorphism and modular programming.
type Shape interface {
    Area() float64
}

type Rectangle struct {
    Width  float64
    Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

func main() {
    var s Shape = Rectangle{Width: 5, Height: 10}
    fmt.Println(s.Area())

    s = Circle{Radius: 2}
    fmt.Println(s.Area())
}

  1. Zero value: In Go, every variable has a zero value, which is the value that the variable has by default before it is assigned a value.
var num int      // zero value is 0
var str string   // zero value is ""
var b bool       // zero value is false
var ptr *int     // zero value is nil
var slice []int  // zero value is nil
var m map[string]int  // zero value is nil

  1. Error handling: Go has a built-in error type and idioms for handling errors that encourage explicit error checking and reporting.
func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("division by zero")
    }
    return a / b, nil
}

func main() {
    result, err := divide(10, 2)
    if err != nil {
        fmt.Println("error:", err)
    } else {
        fmt.Println("result:", result)
    }
}

These are just a few of the common idioms in Go programming. By using these idioms and following the Go programming conventions, you can write efficient and effective code that is easy to read and maintain.

quick-references blog go

Subscribe For More Content