Operadores de cascata do Dart

Existem dois tipos de sintaxe em cascata: .. e ?..

Executar várias atribuições de propriedades e chamadas de método consecutivas no mesmo objeto, elimina variáveis temporais e deixa o código mais fluido e coeso.

A sintaxe em cascata não é um operador, é um açúcar sintático exclusivo do Dart.

1. Cascata comum ..

Usar quando tiver certeza que o objeto nunca é null

Todas as operações com .. agem sobre o objeto original do início, ignorando os valores retornados por cada método intermediário.

Exemplo oficial

import 'dart:ui';

void main() {
  // Escrita em cascata
  var paint = Paint()
    ..color = Colors.black
    ..strokeCap = StrokeCap.round
    ..strokeWidth = 5.0;

  // Forma dividida equivalente (sem cascata, repetir nome da variável)
  var paint2 = Paint();
  paint2.color = Colors.black;
  paint2.strokeCap = StrokeCap.round;
  paint2.strokeWidth = 5.0;
}Code language: JavaScript (javascript)

Esse exemplo importa a biblioteca dart:ui exclusiva do Flutter, só funcionando em projetos Flutter. Como esse guia fala de Dart puro, basta entender a sintaxe mostrada acima. O próximo exemplo usa uma classe nativa padrão do Dart: StringBuffer.

Classe para manipulação de strings: StringBuffer

void main() {
  // Sintaxe em cascata
  var sb = StringBuffer()
    ..write("Hello ")
    ..write("FoxDevelop.com ")
    ..writeln("Cascade");

  print(sb.toString());

  // Versão equivalente sem cascata
  var sb2 = StringBuffer();
  sb2.write("Hello ");
  sb2.write("FoxDevelop.com ");
  sb2.writeln("Cascade");
  print(sb2.toString());
}Code language: PHP (php)

Resultado da execução

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

Hello FoxDevelop.com CascadeCode language: CSS (css)

A sintaxe acima é usada quando você tem garantia que objetos como paint, sb e sb2 nunca valem null: permite atribuir valores rapidamente sem repetir o nome do objeto. Por outro lado, se o objeto for null, um erro aparece imediatamente.

void main() {

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

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

Para resolver esse problema, existe a segunda forma de uso mostrada abaixo.

2. Cascata segura para null ?..

Se o objeto for null, toda a cadeia de cascata não será executada, evitando erros de ponteiro nulo. Apenas o primeiro elo usa ?..; os seguintes usam diretamente ...

void main() {

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

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

Repare no ponto de interrogação antes de ?..write(“Hello “)

Ao compilar novamente, o código roda normalmente

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

Não ocorre nenhum erro

Abaixo o exemplo oficial: basta entender a estrutura sintática.

// Comece com ?.., depois use apenas ..
document.querySelector('#confirm')
  ?..textContent = 'Confirm'
  ..classList.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'))
  ..scrollIntoView();

// Forma dividida segura para null equivalente
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)

Cascata aninhada

final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      // Cascata separada para o objeto interno PhoneNumberBuilder
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();Code language: PHP (php)

O atributo phone é um objeto instanciado via PhoneNumberBuilder() com valores atribuídos.

Observações importantes

A sintaxe em cascata só funciona com instâncias de objeto; se colocada após um método que retorna void, ocorre erro de compilação.

var sb = StringBuffer();
sb.write('foo') // write retorna void
  ..write('bar'); // Erro: o tipo void não tem o método writeCode language: Dart (dart)

Aqui criamos primeiro um objeto StringBuffer chamado sb

Mas a linha termina com ponto e vírgula antes de chamar write no sb; como write retorna void, não é possível encadear outro ..write depois, a menos que o método write retorne uma instância de objeto.

Forma correta de escrita

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

Resumo

  1. .. retorna sempre ao objeto raiz original em cada operação, ignorando os valores retornados pelos métodos. Funciona similar ao encadeamento de métodos de outras linguagens como JavaScript.
  2. ?.. é a cascata segura para null, evitando erros quando o objeto é null. Só é usado no início da cadeia: se a primeira operação rodar, o objeto não é null, então os próximos elos não precisam de ?..
  3. Suporta cascatas aninhadas
  4. Não se pode adicionar cascata após um método com retorno void
  5. .. não é um operador, mas sim um açúcar sintático do Dart
O que é açúcar sintático?

Açúcar sintático é uma abreviação leve oferecida por linguagens de programação para uma mesma lógica base durante a análise sintática; não adiciona novas funcionalidades à linguagem. O compilador ou interpretador converte automaticamente essa sintaxe curta para o código padrão equivalente antes de gerar código intermediário.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *