четверг, 20 июня 2019 г.

Спецификация Go: for утверждения с range условием

for утверждение с range условием перебирает все записи массива, среза, строки, карты, или значений, полученных по каналу. Для каждой записи он присваивает значения итерации соответствующим переменным итерации, если они присутствуют, и затем выполняет блок.

RangeClause = [ ExpressionList "=" | IdentifierList ":=" ] "range" Expression .

Выражение справа в условии "range" называется выражением диапазона (range expression), которое может быть массивом, указателем на массив, срезом, строкой, картой или каналом, разрешающим операции приема. Как и в случае присваивания, операнды слева, если они присутствуют, должны быть адресуемыми или выражениями индекса карты; они обозначают итерационные переменные. Если выражение диапазона является каналом, допускается не более одной итерационной переменной, в противном случае их может быть до двух. Если последняя переменная итерации является пустым идентификатором, условие "range" эквивалентно тому же условию без этого идентификатора.

Выражение диапазона x вычисляется один раз перед началом цикла, за одним исключением: если присутствует не более одной переменной итерации, а len(x) является константой, выражение диапазона не оценивается.

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

Выражение диапазона                        1-е значение       2-е значение

массив или срез  a  [n]E, *[n]E, или []E   index    i  int    a[i]       E
строка           s  string type            index    i  int    см. ниже  rune
карта (map)      m  map[K]V                key      k  K      m[k]       V
канал            c  chan E, <-chan E       element  e  E

  1. Для массива, указателя на массив или значения среза a значения итерации индекса создаются в порядке возрастания, начиная с индекса элемента 0. Если присутствует не более одной переменной итерации, цикл диапазона создает значения итерации от 0 до len(а)-1 и не индексирует в массиве или самом срезе. Для нулевого среза число итераций равно 0.
  2. Для строкового значения условие "range" выполняет итерации по кодовым точкам Unicode в строке, начиная с байтового индекса 0. В последовательных итерациях значение индекса будет индексом первого байта последовательных кодированных точек UTF-8 в строке, а второе значение типа rune будет значением соответствующей кодовой точки. Если итерация встречает недопустимую последовательность UTF-8, второе значение будет 0xFFFD, символ замены Unicode, и следующая итерация будет продвигать один байт в строке.
  3. Порядок итераций для карт не указан и не гарантируется, что он будет одинаковым для каждой итерации. Если запись карты, которая еще не была достигнута, удаляется во время итерации, соответствующее значение итерации не будет создано. Если запись карты создается во время итерации, эта запись может быть создана во время итерации или может быть пропущена. Выбор может варьироваться для каждой созданной записи и от одной итерации к следующей. Если карта равна нулю, количество итераций равно 0.
  4. Для каналов получаемые значения итерации являются последовательными значениями, отправляемыми по каналу, пока канал не будет закрыт. Если канал нулевой, выражение диапазона блокируется навсегда.

Значения итерации присваиваются соответствующим итерационным переменным, как в операторе присваивания.

Переменные итерации могут быть объявлены условием "range", используя форму краткого объявления переменных (:=). В этом случае их типам присваиваются типы соответствующих значений итерации, а их область действия является блоком for утверждения; они повторно используются в каждой итерации. Если переменные итерации объявлены вне for утверждения, после выполнения их значения будут такими же, как в последней итерации.

var testdata *struct {
  a *[7]int
}
for i, _ := range testdata.a {
  // testdata.a никогда не оценивается; len(testdata.a) это константа
  // i в диапазоне от 0 до 6
  f(i)
}

var a [10]string
for i, s := range a {
  // тип i это int
  // тип s это string
  // s == a[i]
  g(i, s)
}

var key string
var val interface {}  // тип элемента в m присваеваемый к val
m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6}
for key, val = range m {
  h(key, val)
}
// key == last map key (последний ключ карты) встреченный в итерации
// val == map[key]

var ch chan Work = producer()
for w := range ch {
  doWork(w)
}

// пустой канал
for range ch {}

Выполнить пример в песочнице

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


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

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