понедельник, 17 июня 2019 г.

Спецификация Go: назначения (assignments)

Assignment = ExpressionList assign_op ExpressionList .

assign_op = [ add_op | mul_op ] "=" .

Каждый левый операнд должен быть адресуемым, либо быть индексным выражением карты , либо (только для = назначений) пустым идентификатором. Операнды могут быть заключены в скобки.

x = 1
*p = f()
a[i] = 23
(k) = <-ch  // так же, как: k = <-ch

Операция назначения x op= y, где op - двоичный арифметический оператор, эквивалентна x = x op (y), но вычисляет x только один раз. Конструкция op= является одним токеном. В операциях назначения как левые, так и правые списки выражений должны содержать ровно одно однозначное выражение, а левое выражение не должно быть пустым идентификатором.

a[i] <<= 2
i &^= 1<<n

Назначения кортежа (tuple assignment) назначает отдельные элементы многозначной операции списку переменных. Есть две формы. В первом случае правый операнд - это однозначное выражение, такое как вызов функции, операция канала или карты или утверждение типа (type assertion). Количество операндов в левой части должно соответствовать количеству значений. Например, если f является функцией, возвращающей два значения,

x, y = f()

присваивает первое значение x, а второе - y. Во второй форме число операндов слева должно равняться количеству выражений справа, каждое из которых должно быть однозначным, а n-е выражение справа присваивается n-му операнду слева:

one, two, three = '一', '二', '三'

Пустой идентификатор позволяет игнорировать правые значения в назначении:

_ = x       // оценивает x, но игнорируем его
x, _ = f()  // вычисляет f(), но игнорирует второе значение результата

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

a, b = b, a  // обменивает a и b

x := []int{1, 2, 3}
i := 0
i, x[i] = 1, 2  // устанавливает i = 1, x[0] = 2

i = 0
x[i], i = 2, 1  // устанавливает x[0] = 2, i = 1

x[0], x[0] = 1, 2  // устанавливает x[0] = 1, затем x[0] = 2 (таким образом x[0] == 2 в итоге)

x[1], x[3] = 4, 5  // устанавливает x[1] = 4, затем panic устанавливает x[3] = 5.

type Point struct { x, y int }
var p *Point
x[2], p.x = 6, 7  // устанавливает x[2] = 6, затем panic устанавливает p.x = 7

i = 2
x = []int{3, 5, 7}
for i, x[i] = range x {  // устанавливает i, x[2] = 0, x[0]
  break
}
// после этого цикла, i == 0 и x == []int{3, 5, 3}

В назначениях каждое значение должно быть присваиваемым (assignable) типу операнда, которому оно присвоено, в следующих особых случаях:

  1. Любому типизированному значению может быть присвоен пустой идентификатор.
  2. Если нетипизированная константа назначена переменной типа интерфейса или пустому идентификатору, константа сначала неявно преобразуется в ее тип по умолчанию.
  3. Если нетипизированное логическое значение присваивается переменной типа интерфейса или пустому идентификатору, оно сначала неявно преобразуется в тип bool.

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


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

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