В представленном коде показана идея асинхронного копирования данных из io.Reader в io.Writer с использованием канала для передачи статуса операции.
func Copy(src io.Reader, dst io.Writer) error {
В представленном коде показана идея асинхронного копирования данных из io.Reader в io.Writer с использованием канала для передачи статуса операции.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
func Copy(src io.Reader, dst io.Writer) error { //... }
import gocopy
s := file.Open() err := gocopy.Copy(s, d)
func Copy(src io.Reader, dst io.Writer) (statusCh, error) { //... go func() { statusCh }() }
func Read() { select { case status := <-statusCh: } }
type Stat struct { status string err error }
func Copy(src io.Reader, dst io.Writer) chan Stat { //... statusCh := make(chan Stat{})
go func() {
statusCh{
}
}
return statusCh
}
func Read() { select { case status := <-statusCh: } }
import gocopy
s := file.Open() err := gocopy.Copy(s, d)
func Copy(src io.Reader, dst io.Writer) chan Stat { //... statusCh := make(chan Stat{}) buf := make([]byte, 1024) var total int64
go func() {
for {
n, err := src.Read(buf)
if n > 0 {
writen, err := dst.Write(buf[:n])
total += int64(writen)
if err != nil {
statusCh <- Stat{
status: "done with err",
err: err,
}
return
}
}
if err == io.EOF {
statusCh <- Stat{
bCopy: total,
status: "done",
err: nil,
}
return
}
if err != nil {
statusCh <- Stat{
status: "done with err",
err: err,
}
return
}
}
}
return statusCh
}
func Read() { select { case status := <-statusCh: if status.err != nil { return } } }
func Copy(src io.Reader, dst io.Writer) chan Stat { //... statusCh := make(chan Stat{}) buf := make([]byte, 1024) var total int64
go func() {
for {
select {
case :
n, err := src.Read(buf)
if n > 0 {
writen, err := dst.Write(buf[:n])
total += int64(writen)
if err != nil {
statusCh <- Stat{
status: "done with err",
err: err,
}
return
}
}
if err == io.EOF {
statusCh <- Stat{
bCopy: total,
status: "done",
err: nil,
}
return
}
if err != nil {
statusCh <- Stat{
status: "done with err",
err: err,
}
return
}
default:
statusCh <- Stat{
bCopy: total,
status: "pending",
err: nil,
}
}
}
}
return statusCh
}
func Read() { select { case status := <-statusCh: if status.err != nil { return } } }
Ответ
В представленном коде показана идея асинхронного копирования данных из io.Reader в io.Writer с использованием канала для передачи статуса операции.
Основные моменты:
- Функция
Copyзапускает горутину, которая читает изsrcи пишет вdstв цикле. - В процессе копирования она отправляет в канал
statusChструктуруStat, которая содержит статус операции и возможную ошибку. - Канал позволяет вызывающему коду получать обновления о прогрессе копирования или ошибках.
Пример упрощённой реализации:
package gocopy
import (
"io"
)
type Stat struct {
bCopy int64
status string
err error
}
func Copy(src io.Reader, dst io.Writer) chan Stat {
statusCh := make(chan Stat)
buf := make([]byte, 1024)
var total int64
go func() {
defer close(statusCh)
for {
n, err := src.Read(buf)
if n > 0 {
written, werr := dst.Write(buf[:n])
total += int64(written)
if werr != nil {
statusCh <- Stat{status: "done with err", err: werr}
return
}
}
if err == io.EOF {
statusCh <- Stat{bCopy: total, status: "done", err: nil}
return
}
if err != nil {
statusCh <- Stat{status: "done with err", err: err}
return
}
// Можно отправлять промежуточный статус, если нужно
statusCh <- Stat{bCopy: total, status: "pending", err: nil}
}
}()
return statusCh
}
В вызывающем коде можно читать из канала, чтобы отслеживать прогресс или ошибки:
func Read(statusCh chan Stat) {
for status := range statusCh {
if status.err != nil {
// обработать ошибку
return
}
// обработать прогресс, например, вывести количество скопированных байт
}
}
Таким образом, использование канала и горутины позволяет делать копирование асинхронным и информировать вызывающий код о состоянии операции в реальном времени.