Sobes.tech
Middle

Quais as consequências de ler de um canal fechado em Go?

sobes.tech IA

Resposta da IA

A leitura de um canal fechado devolve imediatamente o valor nulo do tipo de elementos do canal sem bloqueio. Se estiver presente um segundo parâmetro booleano devolvido, este será false.

package main

import (
	"fmt"
)

func main() {
	ch := make(chan int, 1) // Canal com buffer
	ch <- 1
	close(ch)

	val, ok := <-ch // Leitura de um canal fechado
	fmt.Printf("Valor: %d, Aberto: %t\n", val, ok) // Será exibido "Valor: 1, Aberto: true"

	val, ok = <-ch // Leitura repetida do mesmo canal fechado
	fmt.Printf("Valor: %d, Aberto: %t\n", val, ok) // Será exibido "Valor: 0, Aberto: false"

	// Leituras adicionais do canal fechado
	val, ok = <-ch
	fmt.Printf("Valor: %d, Aberto: %t\n", val, ok) // Será exibido "Valor: 0, Aberto: false"
}

Consequências principais:

  • Obtenção de valor nulo: O programa não irá falhar, mas obterá o valor nulo padrão para o tipo de dados do canal.
  • Indicador de encerramento: O segundo parâmetro booleano, se utilizado, torna-se false, sinalizando que o canal está fechado e o valor obtido é nulo.
  • Leitura não bloqueante: A operação de leitura não bloqueará a goroutine.
  • Sem pânico: Ao contrário de escrever em um canal fechado, ler de um canal fechado não provoca pânico.

Comparação da leitura de canais abertos e fechados:

Estado do canal Operação Comportamento Valor retornado (se houver o segundo parâmetro)
Aberto <-ch Bloqueio até receber valor ou fechar Valor, true
Aberto val, ok := <-ch Bloqueio até receber valor ou fechar Valor, true
Fechado <-ch Obtenção imediata Valor nulo
Fechado val, ok := <-ch Obtenção imediata Valor nulo, false

O uso do segundo parâmetro booleano é a forma recomendada de determinar se um elemento real foi recebido do canal ou se o canal está fechado.

package main

import (
	"fmt"
)

func main() {
	ch := make(chan int, 1)
	ch <- 1
	close(ch)

	for {
		val, ok := <-ch
		if !ok {
			fmt.Println("Canal fechado, saindo do ciclo.")
			break
		}
		fmt.Printf("Valor recebido: %d\n", val)
	}
}

Este comportamento permite encerrar elegantemente as goroutines que leem do canal após seu fechamento.