Оператор select в языке Go
select — это управляющая структура в Go, похожая на оператор switch.
Оператор select можно использовать только для операций с каналами; каждый case должен быть операцией с каналом — отправкой или получением.
Оператор select отслеживает операции по всем указанным каналам; как только один из каналов готов, выполняется соответствующий блок кода.
Если готовы несколько каналов, оператор select случайным образом выбирает один для выполнения. Если ни один из каналов не готов, выполняется код в блоке default.
Синтаксис
Синтаксис оператора select в языке программирования Go выглядит следующим образом:
select {
case <- channel1:
// Код для выполнения
case value := <- channel2:
// Код для выполнения
case channel3 <- value:
// Код для выполнения
// Можно определить любое количество case
default:
// Код, выполняемый, когда ни один из каналов не готов
}
Ниже описывается синтаксис оператора select:
- Каждый case должен быть каналом.
- Все выражения каналов вычисляются.
- Все отправляемые выражения будут вычислены
- Если любой из каналов может продолжить работу, он выполняется; остальные игнорируются.
- Если несколько case могут выполниться, select случайно и справедливо выберет один для выполнения, а остальные не будут выполнены.
В противном случае:- Если есть ветвь default, она выполняется.
- Если ветви default нет, select будет блокироваться до тех пор, пока какой-либо канал не сможет выполниться; Go не будет повторно вычислять каналы или значения.
Пример
Демонстрация применения оператора select:
Пример
import (
"fmt"
"time"
)
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
c1 <- "one"
}()
go func() {
time.Sleep(2 * time.Second)
c2 <- "two"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
}
Результат выполнения приведённого выше кода:
received one received two
В приведённом выше примере мы создали два канала, c1 и c2.
Оператор select ожидает данные из двух каналов. Если данные получены из c1, он выводит "received one"; если данные получены из c2, он выводит "received two".
В следующем примере мы определяем два канала и запускаем две горутины для получения данных из этих каналов. В функции main мы используем оператор select, чтобы сделать неблокирующий выбор между двумя каналами. Если ни в одном из каналов нет доступных данных, выполняется инструкция в ветке default.
После выполнения следующего примера он будет непрерывно получать данные из двух каналов. Когда ни в одном из каналов нет доступных данных, он выведет "no message received".
Пример
import "fmt"
func main() {
// Определяем два канала
ch1 := make(chan string)
ch2 := make(chan string)
// Запустите две горутины, каждая получает данные из одного из каналов
go func() {
for {
ch1 <- "from 1"
}
}()
go func() {
for {
ch2 <- "from 2"
}
}()
// Используйте оператор select для получения данных из двух каналов неблокирующим способом
for {
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
default:
// Если ни в одном из каналов нет доступных данных, выполните операторы здесь
fmt.Println("no message received")
}
}
}