Интерфейс io.Closer
Интерфейс io.Closer определяет базовый метод
Close, который используется для освобождения
ресурсов, связанных с объектом. В первом параметре
метод не принимает аргументов, а возвращает ошибку
типа error, которая указывает на успешность
закрытия ресурса.
Метод Close обычно вызывается после завершения
работы с ресурсом, чтобы избежать утечек памяти и
освободить системные дескрипторы. Многие типы в
стандартной библиотеке Go, такие как os.File,
net.Conn и http.Response, реализуют
этот интерфейс.
Важно отметить, что вызов Close должен быть
безопасным для многократного использования: повторный
вызов не должен приводить к панике, а возвращать
ошибку os.ErrClosed или подобную. Также
рекомендуется использовать конструкцию defer
для гарантированного закрытия ресурса.
Синтаксис
type Closer interface {
Close() error
}
Пример с файлом
Рассмотрим пример использования io.Closer
с открытым файлом. Функция os.Open возвращает
файл, который реализует интерфейс io.Closer:
package main
import (
"fmt"
"io"
"os"
)
func main() {
file, err := os.Open("example.txt")
if err != nil {
fmt.Println("Error opening file:", err)
return
}
defer file.Close()
data := make([]byte, 100)
n, err := file.Read(data)
if err != nil && err != io.EOF {
fmt.Println("Error reading file:", err)
return
}
fmt.Printf("Read %d bytes: %s", n, string(data[:n]))
}
Результат выполнения кода (при наличии файла example.txt):
"Read 13 bytes: Hello, World!"
Пример с HTTP-ответом
В этом примере показано, как закрыть тело HTTP-ответа,
которое реализует io.Closer:
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
resp, err := http.Get("https://example.com")
if err != nil {
fmt.Println("Error making request:", err)
return
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading body:", err)
return
}
fmt.Printf("Response status: %s\n", resp.Status)
fmt.Printf("Body length: %d bytes", len(body))
}
Результат выполнения кода:
"Response status: 200 OK"
"Body length: 1256 bytes"
Пример с функцией NopCloser
В стандартной библиотеке есть функция io.NopCloser,
которая оборачивает io.Reader и возвращает
io.ReadCloser с пустой реализацией Close.
Это полезно, когда требуется интерфейс io.Closer,
но закрывать ничего не нужно:
package main
import (
"fmt"
"io"
"strings"
)
func main() {
r := strings.NewReader("example data")
rc := io.NopCloser(r)
defer rc.Close()
data, err := io.ReadAll(rc)
if err != nil {
fmt.Println("Error reading:", err)
return
}
fmt.Printf("Data: %s", string(data))
}
Результат выполнения кода:
"Data: example data"
Смотрите также
-
интерфейс
io.ReadCloser,
который объединяетio.Readerиio.Closer -
интерфейс
io.WriteCloser,
который объединяетio.Writerиio.Closer -
функцию
io.NopCloser,
которая создаетReadCloserбез операции закрытия -
интерфейс
os.File,
который реализуетio.Closerдля работы с файлами