Каскадные операторы Dart

Существует два вида каскадного синтаксиса: .. и ?..

Последовательное многократное присваивание свойств и вызов методов для одного объекта, позволяет отказаться от временных переменных и сделать код более связным и плавным.

Каскадный синтаксис не является оператором, это синтаксический сахар, характерный исключительно для Dart.

1. Обычный каскад ..

Используйте, если объект гарантированно не равен null

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

Официальный пример

import 'dart:ui';

void main() {
  // Запись с каскадом
  var paint = Paint()
    ..color = Colors.black
    ..strokeCap = StrokeCap.round
    ..strokeWidth = 5.0;

  // Эквивалентная раздельная запись (без каскада, требуется повтор имени переменной)
  var paint2 = Paint();
  paint2.color = Colors.black;
  paint2.strokeCap = StrokeCap.round;
  paint2.strokeWidth = 5.0;
}Code language: JavaScript (javascript)

В этом примере импортируется библиотека dart:ui, принадлежащая Flutter, она работает только в проектах Flutter. Поскольку мы разбираем чистый синтаксис Dart, достаточно понять приведенный выше синтаксис. В следующем примере используется встроенный класс чистого Dart — StringBuffer.

Класс для работы со строками: StringBuffer

void main() {
  // Каскадный синтаксис
  var sb = StringBuffer()
    ..write("Hello ")
    ..write("FoxDevelop.com ")
    ..writeln("Cascade");

  print(sb.toString());

  // Аналогичная запись без каскада
  var sb2 = StringBuffer();
  sb2.write("Hello ");
  sb2.write("FoxDevelop.com ");
  sb2.writeln("Cascade");
  print(sb2.toString());
}Code language: PHP (php)

Результат выполнения

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Hello FoxDevelop.com Cascade

Hello FoxDevelop.com CascadeCode language: CSS (css)

При использовании данного синтаксиса нужно быть уверенным, что объекты paint, sb, sb2 никогда не принимают значение null — это позволяет быстро присваивать значения без повторного указания имени объекта. Если объект равен null, сразу возникнет ошибка.

void main() {

  var sb = null
    ..write("Hello ")
    ..write("FoxDevelop.com ")
    ..writeln("Cascade");

  print(sb.toString());
}Code language: JavaScript (javascript)

Для решения этой проблемы существует второй вариант синтаксиса, описанный ниже.

2. Безопасный каскад для null ?..

Если объект равен null, вся цепочка каскада не выполняется, что предотвращает ошибки нулевого указателя. Только первый элемент цепочки использует ?.., далее пишите просто ...

void main() {

  var sb = null
    ?..write("Hello ")
    ..write("FoxDevelop.com ")
    ..writeln("Cascade");

  print(sb.toString());
}Code language: Dart (dart)

Обратите внимание: перед ?..write(«Hello «) стоит вопросительный знак

При повторной компиляции код работает корректно

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
nullCode language: CSS (css)

Ошибок не возникает

Ниже приведен официальный пример — достаточно запомнить форму записи синтаксиса.

// Цепочка начинается с ?.., далее только ..
document.querySelector('#confirm')
  ?..textContent = 'Confirm'
  ..classList.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'))
  ..scrollIntoView();

// Эквивалентная раздельная запись с защитой от null
final button = document.querySelector('#confirm');
button?.textContent = 'Confirm';
button?.classList.add('important');
button?.onClick.listen((e) => window.alert('Confirmed!'));
button?.scrollIntoView();Code language: JavaScript (javascript)

Вложенные каскады

final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      // Отдельный каскад для внутреннего объекта PhoneNumberBuilder
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();Code language: PHP (php)

Поле phone — это объект, созданный вызовом PhoneNumberBuilder(), которому присваиваются значения.

Важные замечания

Каскад можно применять только к экземплярам объектов; если поставить его после метода, возвращающего void, возникнет ошибка компиляции.

var sb = StringBuffer();
sb.write('foo') // write возвращает void
  ..write('bar'); // Ошибка: тип void не имеет метода writeCode language: Dart (dart)

Здесь сначала создается объект StringBuffer с именем sb

Но оператор завершается точкой с запятой перед вызовом метода write у объекта sb; поскольку write возвращает void, после него нельзя добавлять последовательность ..write, если только метод write не возвращает экземпляр объекта.

Правильный вариант записи

var sb = StringBuffer()
  ..write('foo')
  ..write('bar');Code language: Dart (dart)

Итог

  1. .. после каждой операции возвращается к исходному корневому объекту, игнорируя возвращаемые значения методов. Это аналог цепных вызовов методов из других языков, например JavaScript.
  2. ?.. — безопасный каскад для предотвращения ошибок при значении null у объекта. Используется только в начале цепочки: если первый шаг выполнился, объект точно не равен null, поэтому далее ?.. не нужен.
  3. Поддерживаются вложенные каскады
  4. Нельзя добавлять каскад после метода с возвращаемым типом void
  5. .. не является оператором, это синтаксический сахар Dart
Что такое синтаксический сахар?

Синтаксический сахар — это упрощенная краткая запись, предоставляемая языком программирования для одинаковой базовой логики на этапе синтаксического анализа; он не добавляет новых возможностей языку. Компилятор или интерпретатор автоматически преобразует эту сокращенную запись в эквивалентный стандартный базовый код перед генерацией промежуточного кода.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *