ZetCode

Golang close function

last modified May 8, 2025

This tutorial explains how to use the close built-in function in Go. We'll cover channel basics with practical examples of proper channel management.

The close function is used to close a channel in Go. Closing a channel indicates that no more values will be sent on it. This is important for proper channel cleanup and to prevent goroutine leaks.

In Go, close is used with channels to signal completion of sending operations. Closed channels can still be read from until they're empty, but sending to a closed channel causes a panic.

Basic channel closing example

The simplest use of close shuts down a channel after sending all values. This example demonstrates basic channel closing.
Note: Only the sender should close a channel, never the receiver.

basic_close.go
package main

import "fmt"

func main() {
    ch := make(chan int, 3)
    
    ch <- 1
    ch <- 2
    ch <- 3
    
    close(ch) // Close the channel after sending values
    
    for num := range ch {
        fmt.Println("Received:", num)
    }
    
    fmt.Println("Channel closed and drained")
}

The channel is closed after sending three values. The range loop reads all values until the channel is empty and closed. This ensures proper cleanup.

Detecting channel closure

We can detect when a channel is closed using the second return value from receive operations. This example shows explicit closed channel detection.

detect_close.go
package main

import "fmt"

func main() {
    ch := make(chan string, 2)
    
    ch <- "first"
    ch <- "second"
    close(ch)
    
    for {
        msg, ok := <-ch
        if !ok {
            fmt.Println("Channel closed")
            break
        }
        fmt.Println("Received:", msg)
    }
}

The ok boolean becomes false when the channel is closed and empty. This pattern is useful for explicit closed channel detection in complex flows.

Closing channels with goroutines

Closing channels properly with goroutines prevents goroutine leaks. This example shows coordinated channel closing between goroutines.

goroutine_close.go
package main

import (
    "fmt"
    "time"
)

func worker(tasks <-chan int, done chan<- bool) {
    for task := range tasks {
        fmt.Println("Processing task", task)
        time.Sleep(500 * time.Millisecond)
    }
    done <- true
}

func main() {
    tasks := make(chan int, 3)
    done := make(chan bool)
    
    go worker(tasks, done)
    
    for i := 1; i <= 3; i++ {
        tasks <- i
    }
    close(tasks) // Signal no more tasks
    
    <-done // Wait for worker to finish
    fmt.Println("All tasks processed")
}

The main goroutine closes the tasks channel when done sending. The worker goroutine exits when it detects the closed channel. This prevents leaks.

Closing multiple receivers

Closing a channel can notify multiple receiver goroutines simultaneously. This example demonstrates broadcasting with channel closing.

multiple_receivers.go
package main

import (
    "fmt"
    "sync"
)

func receiver(id int, ch <-chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for num := range ch {
        fmt.Printf("Receiver %d got %d\n", id, num)
    }
    fmt.Printf("Receiver %d exiting\n", id)
}

func main() {
    var wg sync.WaitGroup
    ch := make(chan int)
    
    for i := 1; i <= 3; i++ {
        wg.Add(1)
        go receiver(i, ch, &wg)
    }
    
    for i := 1; i <= 5; i++ {
        ch <- i
    }
    close(ch) // Signal all receivers to exit
    
    wg.Wait()
    fmt.Println("All receivers exited")
}

Closing the channel causes all three receiver goroutines to exit. The WaitGroup ensures proper synchronization between goroutines.

Preventing panics from closed channels

Sending to a closed channel causes a panic. This example shows how to safely handle channel operations to prevent panics.

safe_operations.go
package main

import (
    "fmt"
    "sync"
)

func safeSend(ch chan<- int, value int, wg *sync.WaitGroup) {
    defer wg.Done()
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered from panic:", r)
        }
    }()
    
    ch <- value
}

func main() {
    var wg sync.WaitGroup
    ch := make(chan int, 1)
    
    // First send works
    wg.Add(1)
    go safeSend(ch, 1, &wg)
    
    // Close the channel
    close(ch)
    
    // Second send would panic but we recover
    wg.Add(1)
    go safeSend(ch, 2, &wg)
    
    wg.Wait()
    fmt.Println("Program completed safely")
}

The safeSend function uses recover to handle potential panics. This pattern makes channel operations more robust in complex systems.

Source

Go language specification

This tutorial covered the close function in Go with practical examples of proper channel management and cleanup.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Golang tutorials.