#20.2 golang Однонаправленные каналы, объявление типа и инициализация - когда используются
Primary tabs
Forums:
Ранее мы начали говорить про каналы в golang и в тех примерах все они были двухнапраправленными - то есть мы могли писать в них и тут же читать, минималистичный пример кода работы с таким каналом будет выглядеть так:
package main
import (
"fmt"
)
func main() {
// объявление двунаправленного канала
// сразу с инициализацией
var intChannel chan int = make(chan int)
go func() {
intChannel <- 5 // пишем значение в канал
}()
val := <-intChannel // читаем значение
fmt.Println("Значение из канала:", val)
}
Но мы можем определять каналы и только для чтения или только для отправки
Определение каналов только чтения (отправки) или только для записи (для получения)
- Определение канала только для записи данных:
var inputChannel chan <- int
-- стрелка направлен "в канал" (смотрит на слово chan)
- Определение канала только для чтения данных:
var outputChannel <- chan int
-- стрелка направлен "из канала" (выходит из слова chan)
Также канал можно сразу иницилизировать только для чтения или только записи через make:
- Создание канала только для записи данных:
ch := make(chan <- int)
- Создание канала только для чтения данных:
ch := make(<- chan int)
-- но тут есть важный момент: сфера использования действительно однонаправленных каналов крайне узка.
Поэтому если объяление типа однонаправленного канала действительно используется часто, то вот реальное создание однонапраленного канала на уровене инициализации - довольно редкая ситуация.
Чаще мы всё-таки создаем канал как двунаправленный, а потом передаем его куда-то, где ожидается однонаправленный, рассмотрим пример:
package main
import (
"fmt"
)
/*
Здесь ожидаем на вход канал "только для записи"
Это значит, что внутри функции
мы можем только писать в канал,
но не читать из него
*/
func send(channel chan<- int) {
channel <- 22 // отправляем данные
}
func main() {
// обычный двунаправленный канал
channel := make(chan int)
go send(channel) // запускаем горутину для записи
fmt.Println(<-channel) // читаем значение
}
-- фактически тут разработчики golang разрешают неявное приведение типа для каналов.
По аналогии можно объявить в функции и канал только для чтения данных (с синхронизацией через sync.WaitGroup):
package main
import (
"fmt"
"sync"
)
// Ожидаем канал, доступный только для чтения
func read(channel <-chan int, wg *sync.WaitGroup) {
fmt.Println(<-channel)
wg.Done() // сигнализируем, что горутина завершилась
}
func main() {
var wg sync.WaitGroup
channel := make(chan int)
wg.Add(1) // будем ждать выполнения еще 1 горутины
go read(channel, &wg) // запускаем горутину
channel <- 5 // пишем в канал
wg.Wait() // ждем завершения горутины
}
-- обратите внимание, что здесь мы:
- сначала вызваем дополнительную горутину,
- и только потом пишем в канал, т.к. заполненный канал, блокирует текущую горутину в том числе и после записи, пока кто-нибудь не считает значение (чтобы этот кто-нибудь был - мы заранее и запускаем фоновую горутину).
Источники
- Двухнаправленные и однонаправленные каналы https://metanit.com/go/tutorial/7.8.php
- Log in to post comments
- 89 reads