Показаны сообщения с ярлыком операторы в Go. Показать все сообщения
Показаны сообщения с ярлыком операторы в Go. Показать все сообщения

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

Спецификация Go: оператор получения (receive operator)

Для операнда ch типа канала значение операции получения <-ch является значением, полученным из канала ch. Направление канала должно разрешать операции получения, а типом операции получения является тип элемента канала. Выражение блокируется до тех пор, пока значение не станет доступным. Получение от нулевого канала блокирует навсегда. Операция получения на закрытом канале всегда может продолжаться немедленно, давая нулевое значение типа элемента после получения любых ранее отправленных значений.

v1 := <-ch
v2 = <-ch
f(<-ch)
// ожидание тактового импульса 
// и сброс полученного значения
<-strobe  

Выражение получения, используемое в присваивании или инициализации специальной формы

x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch
var x, ok T = <-ch

дает дополнительный нетипизированный логический результат, сообщающий, успешно ли установлено соединение. Значение ok равно true, если полученное значение было доставлено в результате успешной операции отправки в канал, или false, если это нулевое значение, сгенерированное из-за того, что канал закрыт и пуст.


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


воскресенье, 9 июня 2019 г.

Спецификация Go: логические операторы, адресные операторы

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

&&    conditional AND    p && q  означает  "если p тогда q иначе false"
||    conditional OR     p || q  означает  "если p тогда true иначе q"
!     NOT                !p      означает  "не p"

Адресные операторы

Для операнда x типа T операция адреса &x генерирует указатель типа *T на x. Операнд должен быть адресуемым, т.е. либо переменной, либо косвенным указателем, либо операцией индексации среза; или селектор поля адресуемого структурного операнда; или операция индексации массива адресуемого массива. В качестве исключения из требования адресуемости, x также может быть составным литералом (возможно, заключенным в скобки). Если оценка x вызовет панику во время выполнения, то оценка &x тоже.

Для операнда x типа указателя *T косвенность указателя *x обозначает переменную типа T, на которую указывает x. Если x равен nil, попытка оценить *x вызовет панику во время выполнения.

&x
&a[f(2)]
&Point{2, 3}
*p
*pf(x)

var x *int = nil
*x   // вызывает панику во время выполнения (run-time panic)
&*x  // вызывает панику во время выполнения (run-time panic)


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


Спецификация Go: операторы сравнения

Операторы сравнения сравнивают два операнда и выдают нетипизированное логическое значение.

==    равно
!=    не равно
<     меньше
<=    меньше или равно
>     больше
>=    больше или равно

В любом сравнении первый операнд должен быть присваиваемым (assignable) типу второго операнда или наоборот.

Операторы равенства == и != применяются к операндам, которые сравнимы. Операторы упорядочения <, <=, > и >= применяются к упорядоченным операндам. Эти термины и результат сравнений определяются следующим образом:

  • Булевы значения сопоставимы. Два логических значения равны, если они оба либо true, либо оба false.
  • Целочисленные значения сравнимы и упорядочены обычным способом.
  • Значения с плавающей точкой сопоставимы и упорядочены, как определено стандартом IEEE-754. Комплексные значения сопоставимы. Два комплексных значения u и v равны, если оба real(u) == real(v) и imag(u) == imag(v).
  • Строковые значения сравнимы и упорядочены, лексически в байтовом выражении.
  • Значения указателя сравнимы. Два значения указателя равны, если они указывают на одну и ту же переменную или если оба имеют значение nil. Указатели на различные переменные нулевого размера могут совпадать или не совпадать.
  • Значения канала сравнимы. Два значения канала равны, если они были созданы одним и тем же вызовом make или оба имеют значение nil.
  • Значения интерфейса сравнимы. Два значения интерфейса равны, если они имеют идентичные динамические типы и одинаковые динамические значения или оба имеют значение nil.
  • Значение x неинтерфейсного типа X и значение t интерфейсного типа T сравнимы, когда значения типа X сравнимы и X реализует T. Они равны, если динамический тип t идентичен X, а динамическое значение t равно x.
  • Значения структур сравнимы, если все их поля сравнимы. Два значения структуры равны, если их соответствующие непустые поля равны.
  • Значения массива сравнимы, если значения типа элемента массива сравнимы. Два значения массива равны, если их соответствующие элементы равны.

Сравнение двух значений интерфейса с идентичными динамическими типами вызывает панику во время выполнения, если значения этого типа не сравнимы. Такое поведение применимо не только к прямому сравнению значений интерфейса, но также при сравнении массивов значений интерфейса или структур с полями с интерфейсным значением.

Значения среза, карты и функции не сравнимы. Однако в особом случае значение среза, карты или функции можно сравнить с предварительно объявленным идентификатором nil. Сравнение значений указателя, канала и интерфейса с nil также допускается и следует из общих правил, приведенных выше.

const c = 3 < 4   // c это нетипизированная булева постоянная true

type MyBool bool
var x, y int
var (
  // Результат сравнения это нетипизированное булево значение.
  // Применяются обычные правила присваивания.
  b3        = x == y // b3 имеет тип bool
  b4 bool   = x == y // b4 имеет тип bool
  b5 MyBool = x == y // b5 имеет тип MyBool
)


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


Спецификация Go: арифметические операторы

Арифметические операторы применяются к числовым значениям и дают результат того же типа, что и первый операнд. Четыре стандартных арифметических оператора (+, -, *, /) применяются к целым числам, числам с плавающей точкой и сложным типам; + также относится к строкам. Битовые логические операторы и операторы сдвига применяются только к целым числам.

+    sum                    integers, floats, complex values, strings
-    difference             integers, floats, complex values
*    product                integers, floats, complex values
/    quotient               integers, floats, complex values
%    remainder              integers

&    bitwise AND            integers
|    bitwise OR             integers
^    bitwise XOR            integers
&^   bit clear (AND NOT)    integers

<<   left shift             integer << unsigned integer
>>   right shift            integer >> unsigned integer

Целочисленные операторы

Для двух целочисленных значений x и y целочисленное отношение q = x / y и остаток r = x % y удовлетворяют следующим соотношениям:

x = q*y + r  и  |r| < |y|

х / у усекается до нуля ("усеченное деление", "truncated division").

 x     y     x / y     x % y
 5     3       1         2
-5     3      -1        -2
 5    -3      -1         2
-5    -3       1        -2

Единственное исключение из этого правила состоит в том, что если дивиденд x является самым отрицательным значением для типа int типа x, частное q = x / -1 равно x (и r = 0) из-за переполнения двух-комплементного целого числа из двух дополнений:

                         x, q
int8                     -128
int16                  -32768
int32             -2147483648
int64    -9223372036854775808

Если делитель является константой, он не должен быть нулевым. Если делитель равен нулю во время выполнения, возникает паника во время выполнения. Если дивиденд неотрицательный и делитель имеет постоянную степень 2, деление может быть заменено сдвигом вправо, а вычисление остатка может быть заменено побитовой операцией И (bitwise AND):

 x     x / 4     x % 4     x >> 2     x & 3
 11      2         3         2          3
-11     -2        -3        -3          1

Операторы сдвига смещают левый операнд на число смещения, указанное правым операндом. Они реализуют арифметические сдвиги, если левый операнд представляет собой целое число со знаком, и логические сдвиги, если это целое число без знака. Там нет верхнего предела на счет сдвига. Сдвиги ведут себя так, как будто левый операнд смещен n раз на 1 для числа сдвигов n. В результате x << 1 совпадает с x*2, а x >> 1 совпадает с x/2, но усекается до отрицательной бесконечности.

Для целочисленных операндов унарные операторы +, - и ^ определяются следующим образом:

+x                          это 0 + x
-x    negation              это 0 - x
^x    bitwise complement    это m ^ x  с m = "все биты устанавливаются в 1" для беззнакового (unsigned) x
                                      и  m = -1 для x со знаком (signed)

Переполнение целых чисел

Для целочисленных значений без знака (unsigned integer) операции +, -, * и << вычисляются по модулю 2n, где n - ширина в битах типа целого числа без знака. Грубо говоря, эти целочисленные операции без знака отбрасывают старшие биты при переполнении, и программы могут полагаться на "циклический переход".

Для целых чисел со знаком операции +, -, *, / и << могут легально переполняться, и результирующее значение существует и детерминировано определяется представлением целого числа со знаком, операцией и ее операндами. Переполнение не вызывает паники во время выполнения. Компилятор может не оптимизировать код при условии, что переполнения не происходит. Например, он может не предполагать, что x < x + 1 всегда верно.

Операторы для чисел с плавающей точкой

Для чисел с плавающей точкой и комплексных чисел +x - это то же самое, что и x, а -x - отрицание x. Результат деления с плавающей запятой или сложного деления на ноль не указан вне стандарта IEEE-754; возникновение паники во время выполнения зависит от реализации.

Реализация может объединять несколько операций с плавающей запятой в одну объединенную операцию, возможно, между операторами, и производить результат, который отличается от значения, полученного путем выполнения и округления инструкций по отдельности. Явное преобразование типа с плавающей точкой округляет до точности целевого типа, предотвращая слияние, которое отбрасывает это округление.

Например, в некоторых архитектурах предусмотрена инструкция «FMA», которая вычисляет x * y + z без округления промежуточного результата x * y. Следующие примеры показывают, когда реализация Go может использовать эту инструкцию:

// FMA включена при вычислении r, потому что x*y явно не округляется:
r  = x*y + z
r  = z;   r += x*y
t  = x*y; r = t + z
*p = x*y; r = *p + z
r  = x*y + float64(z)

// FMA выключена при вычислении r, потому что она будет пропускать округление x*y:
r  = float64(x*y) + z
r  = z; r += float64(x*y)
t  = float64(x*y); r = t + z

Конкатенация строк

Строки могут быть объединены с помощью оператора + или оператора присвоения +=

s := "hi" + string(c)
s += " and good bye"

Добавление строки создает новую строку путем объединения операндов.


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


купить игрушку gopher

суббота, 8 июня 2019 г.

Спецификация Go: операторы, приоритет операторов

Операторы объединяют операнды в выражения.

Expression = UnaryExpr | Expression binary_op Expression .
UnaryExpr  = PrimaryExpr | unary_op UnaryExpr .

binary_op  = "||" | "&&" | rel_op | add_op | mul_op .
rel_op     = "==" | "!=" | "<" | "<=" | ">" | ">=" .
add_op     = "+" | "-" | "|" | "^" .
mul_op     = "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" .

unary_op   = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .

Операторы сравнения будут обсуждаться в последующих постах. Для других бинарных операторов типы операндов должны быть идентичны, если только операция не включает сдвиги или нетипизированные константы.

За исключением операций сдвига, если один операнд является нетипизированной константой, а другой - нет, константа неявно преобразуется в тип другого операнда.

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

var s uint = 33
var i = 1<<s                  // 1 имеет тип int
var j int32 = 1<<s            // 1 имеет тип int32; j == 0
var k = uint64(1<<s)          // 1 имеет тип uint64; k == 1<<33
var m int = 1.0<<s            // 1.0 имеет тип int; m == 0 если int являются 32-битными (32bits) в размере
var n = 1.0<<s == j           // 1.0 имеет тип int32; n == true
var o = 1<<s == 2<<s          // 1 и 2 имеют тип int; o == true если int являются 32-битными (32bits) в размере
var p = 1<<s == 1<<33         // недопустимо если int являются 32-битными (32bits) в размере: 1 имеет тип int, но 1<<33 переполняет int
var u = 1.0<<s                // недопустимо: 1.0 имеет тип float64, не может сдвигаться
var u1 = 1.0<<s != 0          // недопустимо: 1.0 имеет тип float64, не может сдвигаться
var u2 = 1<<s != 1.0          // недопустимо: 1 имеет тип float64, не может сдвигаться
var v float32 = 1<<s          // недопустимо: 1 имеет тип float32, не может сдвигаться
var w int64 = 1.0<<33         // 1.0<<33 является константным выражением сдвига
var x = a[1.0<<s]             // 1.0 имеет тип int; x == a[0] если int являются 32-битными (32bits) в размере
var a = make([]byte, 1.0<<s)  // 1.0 имеет тип int; len(a) == 0 если int являются 32-битными (32bits) в размере

Приоритет операторов

Унарные операторы имеют наивысший приоритет. Поскольку операторы ++ и -- формируют заявления (statements), а не выражения (expressions), они выходят за пределы иерархии операторов. Как следствие, заявление (statement) *p++ идентично (*p)++.

Существует пять уровней приоритета для бинарных операторов. Операторы умножения связывают сильнее всего, затем следуют операторы сложения, операторы сравнения, && (логическое И) и, наконец, || (логическое ИЛИ):

Приоритет     Оператор
    5             *  /  %  <<  >>  &  &^
    4             +  -  |  ^
    3             ==  !=  <  <=  >  >=
    2             &&
    1             ||

Бинарные операторы с одинаковым приоритетом ассоциируются слева направо. Например, x / y * z - это то же самое, что и (x / y) * z.

+x
23 + 3*x[i]
x <= f()
^a >> b
f() || g()
x == y+1 && <-chanPtr > 0


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


пятница, 22 февраля 2019 г.

Go FAQ: Почему ++ и -- в Go являются операторами, а не выражениями? И почему постфикс, а не префикс?

Без арифметики указателей, удобство префикс и постфикс операторов приращения пропадает. Удаление их из иерархии выражений в целом, упростило синтаксис выражений и грязные проблемы оценки порядка ++ и -- (например, f(i++) и p[i] = q[++i]) также устранены. Упрощение значительное. Что касается постфикса и префикса, то все будет работать нормально, но постфиксная версия более традиционна; настойчивое требование префикса возникло с STL, библиотеки для языка, имя которого, по иронии судьбы, содержит постфиксный прирост (C++).


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


понедельник, 18 февраля 2019 г.

Go FAQ: Почему в Go нет тернарного (?:) оператора?

В Go нет тернарной операции тестирования. Вы можете использовать следующее для достижения того же результата:

if expr {
    n = trueVal
} else {
    n = falseVal
}

Причина, по которой ?: (тернарный оператор) отсутствует в Go, заключается в том, что разработчики языка видели, что операция использовалась слишком часто, чтобы создавать излишне сложные выражения. Форма if-else, хотя и дольше, но, несомненно, яснее. Языку нужна только одна условная конструкция потока управления.


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