пятница, 21 июня 2019 г.

Спецификация Go: select утверждения (select statements)

Утверждение "select" выбирает, какой из набора возможных операций отправки или получения будет продолжен. Это похоже на утверждние "switch", но со всеми случаями (cases), относящимися к операциям связи.

SelectStmt = "select" "{" { CommClause } "}" .
CommClause = CommCase ":" StatementList .
CommCase   = "case" ( SendStmt | RecvStmt ) | "default" .
RecvStmt   = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr .
RecvExpr   = Expression .

Случай (case) с RecvStmt может присвоить результат RecvExpr одной или двум переменным, которые могут быть объявлены с помощью краткого объявления переменных. RecvExpr должен быть (возможно заключенной в скобки) операцией приема. Может быть не более одного случая по умолчанию, и он может появиться в любом месте списка случаев (cases).

Исполнение утверждения "select" происходит в несколько этапов:

  1. Для всех случаев в утверждении операнды канала операций приема и выражения канала и правой части выражений утверждений отправки оцениваются ровно один раз в порядке исходного кода при входе в "select" утверждение. Результатом является набор каналов для приема или отправки и соответствующие значения для отправки. Любые побочные эффекты в этой оценке будут иметь место независимо от того, какая (если таковая имеется) операция связи выбрана для продолжения. Выражения в левой части RecvStmt с кратким объявлением или присваиванием переменной еще не оценены.
  2. Если одно или несколько сообщений может быть продолжено, выбирается одно, которое может продолжаться, посредством равномерного псевдослучайного выбора. В противном случае, если есть случай по умолчанию, этот случай выбирается. Если случай по умолчанию отсутствует, утверждение "select" блокируется до тех пор, пока не будет продолжено хотя бы одно из сообщений.
  3. Если выбранный случай не является случаем по умолчанию, выполняется соответствующая операция связи.
  4. Если выбранный случай представляет собой RecvStmt с коротким объявлением переменной или присваиванием, левые выражения оцениваются и присваивается полученное значение (или значения).
  5. Список выписок выбранного случая выполнен.

Поскольку обмен данными по нулевым каналам никогда не может быть продолжен, select только с нулевыми каналами и без случая по умолчанию блокируется навсегда.

var a []int
var c, c1, c2, c3, c4 chan int
var i1, i2 int
select {
case i1 = <-c1:
  print("received ", i1, " from c1\n")
case c2 <- i2:
  print("sent ", i2, " to c2\n")
case i3, ok := (<-c3):  // то же самое что и: i3, ok := <-c3
  if ok {
    print("received ", i3, " from c3\n")
  } else {
    print("c3 is closed\n")
  }
case a[f()] = <-c4:
  // то же самое что и:
  // case t := <-c4
  //  a[f()] = t
default:
  print("no communication\n")
}

for {  // отправляет случайную последовательность битов в c
  select {
  case c <- 0:  // примечание: нет утверждения, нет fallthrough ("провала" в следующий случай), нет сворачивания случаев
  case c <- 1:
  }
}

select {}  // блокируется навсегда


Читайте также:


Комментариев нет:

Отправить комментарий