1/Путь к первому мобильному приложению. Часть 1.4 - Изучаем язык Dart: Операторы и проверка типов

Операторы бывают следующих типов:

  1. арифметические
  2. сравнения
  3. типовых проверок
  4. присваивания
  5. логические
  6. побитовые и операторы сдвига
  7. условные
  8. каскадный
  9. другие

Арифметические операторы:

+     Сложение
–     Вычитание
-expr Отрицание переменной expr
*     Умножение
/     Деление
~/    Целочисленный результат деления
%     Остаток от деления

Также есть сокращённые операторы сложения и вычитания:

var++; // var = var + 1
++var; // var = var + 1
var--; // var = var - 1
--var; // var = var - 1
print ( var++ ); // var
print ( ++var ); // var + 1
print ( var-- ); // var
print ( --var ); // var - 1

Рассмотрим последовательность выполнения операций на примере:

int a = 1;
int b = 5;
int c = 12;
int d = 15;
print ( 'a++ / 4 + --b ~/ 3 - ( ++c % ( 5 - 2 ) + d-- * ( 3 + 5 ) ) + d = ?' );
// Сначала выполняются все операции в скобках, всё как в обычной математике - слева направо, если внутри скобки есть другая скобка - выполняется сначала внутренняя
print ( '( 5 - 2 ) = ${( 5 - 2 )}' ); // 3
print ( '( 3 + 5 ) = ${( 3 + 5 )}' ); // 8
// Наивысший приоритет у постфиксный операций var++ и var--
// Затем выполняются префиксные  ++var и --var
// Далее идут операции * , / , %  и ~/
// И в последнюю очередь + и -
print ( 'd-- = ${d--}' ); // 15 (не смотря на то, что d уже теперь 14, в самой операции используется значение 15)
print ( '++c = ${++c}' ); // 13
print ( '++c % ( 5 - 2 ) = ${++c % ( 5 - 2 )}' ); // 1
print ( 'd-- * ( 3 + 5 ) = ${d-- * ( 3 + 5 )}' ); // 120 (в этом примере становится более очевидным что d-- используется как 15)
print ( '( ++c % ( 5 - 2 ) + d-- * ( 3 + 5 ) ) = ${( ++c % ( 5 - 2 ) + d-- * ( 3 + 5 ) )}' ); // 121
print ( 'a++ = ${a++}' ); // 1
print ( '--b = ${--b}' ); // 4
print ( 'a++ / 4 = ${a++ / 4}' ); // 0.25
print ( '--b ~/ 3 = ${--b ~/ 3}' ); // 1
print ( 'a++ / 4 + --b ~/ 3 = ${a++ / 4 + --b ~/ 3}' ); // 1.25
print ( 'a++ / 4 + --b ~/ 3 - ( ++c % ( 5 - 2 ) + d-- * ( 3 + 5 ) ) = ${a++ / 4 + --b ~/ 3 - ( ++c % ( 5 - 2 ) + d-- * ( 3 + 5 ) )}' ); // -119.75
print ( 'a++ / 4 + --b ~/ 3 - ( ++c % ( 5 - 2 ) + d-- * ( 3 + 5 ) ) + d = ${a++ / 4 + --b ~/ 3 - ( ++c % ( 5 - 2 ) + d-- * ( 3 + 5 ) ) + d}' ); // -105.75 (на момент последней операции d = 14)

Операторы сравнения

== Равно
!= Не равно
>  Больше
<  Меньше
>= Больше или равно
<= Меньше или равно

Операторы типовых проверок

as  Приведение к типу
is  Истина, если тип совпадает
is! Ложь, если тип совпадает

Операторы присваивания

=    –=    /=    %=   >>=    ^=
+=   *=   ~/=   <<=    &=    |=

Например,

a = 5;
a += 6; // a = a + 6
a ??= 7; // a = ( a == null ? 7 : a );

Логические операторы

!expr Отрицание выражения
||    логическое ИЛИ
&&    логическое И
&     И
|     ИЛИ
^     Исключающее ИЛИ

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

int a = 1;
print ( true | ( ++a == 2 ) ); 
print ( a ); // 2, так как ++a код выполнился
print ( true || ( ++a == 2 ) );
print ( a ); // 2, не изменилось, так как из-за значения ИСТИНА первого условия, второе условие не выполнялось
print ( false || ( ++a == 2 ) );
print ( a ); // 3, изменилось так как пришлось вычислять второе условие из-за ЛОЖНОГО первого

Побитовые и операторы сдвига

~expr Побитовое дополнение (0 в 1, 1 в 0)
<<    Сдвиг влево
>>    Сдвиг вправо

Условные операторы

expr = condition ? expr1 : expr2; // if ( condition ) { expr = expr1; } else { expr = expr2; }
expr = expr1 ?? expr2; // if ( expr1 != null ) { expr = expr1; } else { expr = expr2; }

В примерах:

  // Условные операторы и проверка типов
  print ( 'Hello, world!' is String ); // true
  print ( 'Hello, world!' is int ); // false
  print ( 'Hello, world!' is! int ); // true
  
  var isGuest = false;
  var userGroup = isGuest ? 'guest' : 'user';
  print ( userGroup ); // user
  
  var username;
  String getUserName ( String username ) => username ?? 'Guest';
  print ( getUserName ( username ) ); // Guest
  
  var valueNull;
  var valueNotNull = 0;
  var valueInt = 12;
  
  valueNull ??= valueInt; // обозначает присвоить значение, если изначально NULL
  print ( valueNull ); // 12
  valueNotNull ??= valueInt;
  print ( valueNotNull ); // 0

  // Каскадный оператор
  querySelector ( '#alert' )
  ..text = 'Warning'
  ..classes.add('danger')
  ..onClick.listen((e) => window.alert('ERROR!'));
  // Его аналог в классическом виде
  var button = querySelector ( '#alert' );
  button.text = 'Warning';
  button.classes.add('danger');
  button.onClick.listen((e) => window.alert('ERROR!'));