io.Closer în Go

Interfața pentru orice resursă care trebuie închisă după folosire (fișiere, conexiuni, corpuri HTTP).

Sintaxă
type Closer interface {
    Close() error
}

Ce face io.Closer

io.Closer are o singură metodă, Close() error. O implementează fișierele, conexiunile de rețea, corpul unui răspuns HTTP (resp.Body) și compresoarele (gzip.Writer).

Apare mai ales în combinații: io.ReadCloser (Reader + Closer), io.WriteCloser, io.ReadWriteCloser. Dacă primești un io.ReadCloser, ești responsabil să-l închizi. io.NopCloser(r) transformă un Reader obișnuit într-un ReadCloser al cărui Close nu face nimic.

Ce returnează

Close returnează nil sau eroarea de la închidere.

Exemple

Exemplul 1: Închiderea mai multor resurse

package main

import (
    "fmt"
    "io"
    "os"
)

func inchideToate(resurse ...io.Closer) {
    for _, r := range resurse {
        if err := r.Close(); err != nil {
            fmt.Println("eroare la închidere:", err)
        }
    }
}

func main() {
    a, _ := os.Create("a.txt")
    b, _ := os.Create("b.txt")
    inchideToate(a, b)
    inchideToate(a) // a doua oară: eroare
}

Rezultat

eroare la închidere: close a.txt: file already closed

Exemplul 2: Un tip propriu care se închide

package main

import (
    "fmt"
    "io"
)

type conexiune struct {
    nume string
}

func (c *conexiune) Close() error {
    fmt.Println("închid conexiunea", c.nume)
    return nil
}

func foloseste(c io.Closer) {
    defer c.Close()
    fmt.Println("lucrez...")
}

func main() {
    foloseste(&conexiune{nume: "baza-de-date"})
}

Rezultat

lucrez...
închid conexiunea baza-de-date

Exemplul 3: io.NopCloser

O funcție cere io.ReadCloser, dar noi avem doar un text. NopCloser adaugă un Close care nu face nimic.

package main

import (
    "fmt"
    "io"
    "strings"
)

func citesteCorp(corp io.ReadCloser) string {
    defer corp.Close()
    date, _ := io.ReadAll(corp)
    return string(date)
}

func main() {
    corp := io.NopCloser(strings.NewReader(`{"status":"ok"}`))
    fmt.Println(citesteCorp(corp))
}

Rezultat

{"status":"ok"}

Greșeli frecvente

  • Uiți resp.Body.Close() după o cerere HTTP. Conexiunea nu poate fi refolosită și resursele se adună.

Comenzi înrudite

  • os.File.Close: Închide fișierul și eliberează resursele sistemului; după Close fișierul nu mai poate fi folosit.
  • io.Reader: Interfața pentru orice sursă de date din care se poate citi: fișiere, text, conexiuni, răspunsuri HTTP.
  • io.Writer: Interfața pentru orice destinație în care se pot scrie octeți: fișiere, ecran, buffer-e, răspunsuri HTTP.
  • io.ReadWriter: Interfața pentru tipurile din care se poate și citi, și în care se poate scrie (Reader + Writer).
  • io.NopCloser: Transformă un Reader obișnuit într-un io.ReadCloser al cărui Close nu face nimic.