Однонаправленный канал

Однонаправленный канал — это канал, у которого ограничено направление передачи данных. В Go мы можем объявить канал, который будет использоваться только для отправки значений (chan<-) или только для получения значений (<-chan). Это позволяет явно указать намерения разработчика и предотвратить случайные операции, которые могут привести к ошибкам. Обычно такие каналы используются в сигнатурах функций, чтобы показать, как именно функция взаимодействует с каналом.

Синтаксис

govar sendOnly chan<- int // только для отправки
var recvOnly <-chan int // только для получения

Пример

Давайте создадим функцию, которая принимает однонаправленный канал для отправки данных. Внутри функции будем отправлять значения в канал, а в главной функции — считывать их. Это поможет понять, как ограничение направления работает на практике.

gopackage main

import "fmt"

// Функция принимает канал только для отправки
func sendData(ch chan<- int) {
  for i := 1; i <= 3; i++ {
    ch <- i * 10
  }
  close(ch)
}

func main() {
  ch := make(chan int)

  go sendData(ch)

  // Читаем данные из канала
  for val := range ch {
    fmt.Println(val)
  }
}

Результат выполнения кода:

go10
20
30

Пример

Теперь рассмотрим функцию, которая принимает канал только для получения данных и обрабатывает их. Это полезно, когда функция должна только читать значения из канала, не изменяя его состояние.

gopackage main

import "fmt"

// Функция принимает канал только для получения
func processData(ch <-chan int) {
  for val := range ch {
    fmt.Printf("Received: %d\n", val)
  }
}

func main() {
  ch := make(chan int)

  go func() {
    for i := 1; i <= 3; i++ {
      ch <- i * 5
    }
    close(ch)
  }()

  processData(ch)
}

Результат выполнения кода:

go"Received: 5"
"Received: 10"
"Received: 15"

Пример

Однонаправленные каналы также можно создавать с буферизацией. Это работает точно так же, как и с обычными каналами: мы указываем размер буфера при создании, а направление ограничиваем при передаче.

gopackage main

import "fmt"

func main() {
  ch := make(chan string, 2)

  // Отправляем данные в буферизированный канал
  ch <- "a"
  ch <- "b"

  // Передаём канал в функцию только для получения
  readChan := func(ch <-chan string) {
    for val := range ch {
      fmt.Println(val)
    }
  }

  close(ch)
  readChan(ch)
}

Результат выполнения кода:

go"a"
"b"

Смотрите также