Шаг 67.
Язык программирования Go.
Примеры использования инструкции select
На этом шаге рассмотрим примеры использования инструкции select.
Задание 1. Подсчитать сумму значений граний при четных и нечетных бросаниях игрового кубика (рис.1):
Рис.1. Пример работы приложения
Раскрыть/скрыть решение и комментарии.
channels := make([]chan bool, 6)/*создаются шесть двунаправленных каналов для
обмена логическими значениями*/
for i := range channels {
channels[i] = make(chan bool)
}
/*создается go-подпрограмма, выполняющая бесконечный цикл,
в каждой итерации которого случайно выбирается один из каналов,
и в него отправляется значение true */
go func() {
for {
channels[rand.Intn(6)] <- true
}
}()
s1, s2 := 0, 0
/*шесть каналов используются для имитации бросания игрового кубика
(та или иная грань которого, строго говоря, выпадает псевдослучайно).
Инструкция select ожидает, пока по одному из каналов не будет что-нибудь отправлено
(инструкция select блокируется, потому что в ней отсутствует раздел default),
и как только один или более каналов будет готов к передаче, псевдослучайно будет
выбран один из разделов case. Так как инструкция select находится внутри простого
цикла for, она будет выполнена фиксированное число раз*/
for i := 1; i <= 20; i++ {
var x int
select {
case <-channels[0]:
x = 1
case <-channels[1]:
x = 2
case <-channels[2]:
x = 3
case <-channels[3]:
x = 4
case <-channels[4]:
x = 5
case <-channels[5]:
x = 6
}
if i%2 == 1 {
s1 += x
} else {
s2 += x
}
fmt.Printf("%d ", x)
}
fmt.Printf("\nСумма четных бросков равна %d", s2)
fmt.Printf("\nСумма нечетных бросков равна %d", s1)
fmt.Println()
Архив примера можно взять здесь.
Задание 2. Написать программу, которая выполняет обратный отчет (рис.2):
Рис.2. Пример работы приложения
Раскрыть/скрыть решение и комментарии.
/*программа осуществляет обратный отсчет для запуска ракеты.
Функция time.Tick возвращает канал, по которому она
периодически отправляет события, действуя как метроном.
Каждое событие представляет собой значение момента времени*/
прервать := make(chan struct{})
/*добавим возможность прервать последовательность запуска,
нажав клавишу Enter во время обратного отсчета.
Сначала запустим go-подпрограмму, которая пытается прочитать
один байт из стандартного ввода и, если это удастся, отправляет значение
в канал, который называется прервать*/
go func() {
os.Stdin.Read(make([]byte, 1))
прервать <- struct{}{}
}()
fmt.Println("Начинаю отсчет. Нажмите Enter для отмены.")
/*функция time.Tick ведет себя так, как будто создает go-подпрограмму,
которая вызывает time.Sleep в цикле, отправляя событие всякий раз,
когда она "просыпается"*/
время := time.Tick(1 * time.Second)
/*каждая итерация цикла обратного отсчета должна ожидать
события от одного из двух каналов: канала время, если все в порядке,
или канала прервать, если следует отменить запуск.
Нельзя просто получать значения от каждого канала, потому что первая же
операция будет блокирована до ее завершения. Нужно мультиплексировать
эти операции, для этого нужна инструкция select*/
for обратныйОтсчет := 5; обратныйОтсчет >= 0; обратныйОтсчет-- {
fmt.Println(обратныйОтсчет)
/*инструкция select приводит к тому, что на каждой итерации цикла выполняется
ожидание сигнала прерывания в течение секунды*/
select {
case <-время:
case <-прервать:
fmt.Println("Отсчет отменен!")
return
}
}
пуск()
}
func пуск() {
fmt.Println("Пуск!")
}
Архив примера можно взять здесь.
На следующем шаге рассмотрим инструкцию defer.
Предыдущий шаг
Содержание
Следующий шаг