Dart: Operadores do Dart
Última atualização: 2026-08-26
Operadores são os verbos do código — domine-os para fazer os dados "se moverem."
1. O que Você Aprenderá
- Operadores Aritméticos / Relacionais / Lógicos / Bitwise
- Operadores de Atribuição e Atribuição Composta
- Operador cascade
..e?..(uma ferramenta poderosa para encadeamento de métodos) - Operadores de Null Safety:
?./??/??= - Operadores de Teste de Tipo: is / is! / as
2. A História Real de um Desenvolvedor
(1) Dor: NullPointerException Derrubando Tarefas em Lote
O DataPipeline do Bob frequentemente crashava ao processar milhões de pedidos porque alguns pedidos careciam campos opcionais. O código estava repleto de verificações if (value != null), mas uma foi esquecida, causando a interrupção do processamento de 300.000 pedidos e exigindo uma reexecução completa.
(2) A Solução com Operadores de Null Safety
O Dart oferece três operadores — ?. (acesso seguro), ?? (coalescência nula) e ??= (atribuição awareness de nulo) — que tornam o tratamento de nulos conciso e seguro.
// Antes: verificação de nulo verbosa
String getCity(Order order) {
if (order.customer != null) {
if (order.customer!.address != null) {
return order.customer!.address!.city;
}
}
return 'Unknown';
}
// Depois: operadores null-safe
String getCity(Order order) =>
order.customer?.address?.city ?? 'Unknown';
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
(3) Benefícios
- Redução de 60% nas linhas de código, tornando a lógica de tratamento de nulos clara à primeira vista.
- O operador cascade
..permite encadeamento de métodos mais fluido. - Operadores de teste de tipo tornam a verificação de tipos mais segura.
3. Operadores Aritméticos e Relacionais
(1) Operadores Aritméticos
▶ Exemplo
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
: Aritmética Básica
void main() {
int a = 17;
int b = 5;
print(a + b); // 22 - Adição
print(a - b); // 12 - Subtração
print(a * b); // 85 - Multiplicação
print(a / b); // 3.4 - Divisão (retorna double)
print(a ~/ b); // 3 - Divisão inteira
print(a % b); // 2 - Módulo (resto)
// Incremento prefixado e sufixado
int count = 10;
print(count++); // 10 (retorna depois incrementa)
print(count); // 11
print(++count); // 12 (incrementa depois retorna)
}
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
| Operador | Significado | Exemplo | Resultado |
|---|---|---|---|
+ |
Adição | 17 + 5 |
22 |
- |
Subtração | 17 - 5 |
12 |
* |
Multiplicação | 17 * 5 |
85 |
/ |
Divisão (retorna double) | 17 / 5 |
3.4 |
~/ |
Divisão Inteira | 17 ~/ 5 |
3 |
% |
Módulo (Resto) | 17 % 5 |
2 |
(2) Operadores Relacionais
▶ Exemplo
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
: Operações de Comparação
void main() {
int orders = 1500;
int threshold = 1000;
print(orders > threshold); // true
print(orders < threshold); // false
print(orders >= 1500); // true
print(orders <= 1500); // true
print(orders == 1500); // true
print(orders != 1000); // true
// Comparação de strings é lexicográfica
print('apple' < 'banana'); // true
print('USD' == 'USD'); // true
}
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
4. Operadores Lógicos e Bitwise
(1) Operadores Lógicos
▶ Exemplo
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
: Operações Lógicas
void main() {
bool isProduction = true;
bool hasErrors = false;
print(isProduction && !hasErrors); // true - AND + NOT
print(isProduction || hasErrors); // true - OR
print(!isProduction); // false - NOT
// Avaliação de curto-circuito
String? name = null;
// name.length > 0 causaria crash, mas:
print(name != null && name.isNotEmpty); // false (seguro)
}
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
| Operador | Significado | Curto-Circuito |
|---|---|---|
&& |
AND Lógico | Esquerda falsa -> direita não avaliada |
| ` | ` | |
! |
NOT Lógico | — |
(2) Operadores Bitwise
▶ Exemplo
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
: Operações Bitwise
void main() {
int flags = 0b1010; // 10 em binário
int mask = 0b1100; // 12 em binário
print(flags & mask); // 8 (0b1000) - AND
print(flags | mask); // 14 (0b1110) - OR
print(flags ^ mask); // 6 (0b0110) - XOR
print(~flags); // -11 (bits invertidos) - NOT
print(flags << 2); // 40 (0b101000) - Deslocamento à esquerda
print(flags >> 1); // 5 (0b0101) - Deslocamento à direita
}
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
5. Operadores de Atribuição e Atribuição Composta
▶ Exemplo
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
: Atribuição Composta
void main() {
int total = 0;
double revenue = 0.0;
total += 100; // total = total + 100 = 100
total -= 30; // total = 70
total *= 2; // total = 140
total ~/= 3; // total = 46 (divisão inteira)
revenue += 52500.75; // revenue = 52500.75
// Atribuição awareness de nulo
String? outputPath;
outputPath ??= '/tmp/output'; // Atribuir se nulo
print(outputPath); // /tmp/output
outputPath ??= '/other/path'; // Não atribuído (já não é nulo)
print(outputPath); // /tmp/output
}
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
| Operador | Equivalente A | Exemplo |
|---|---|---|
+= |
a = a + b |
total += 100 |
-= |
a = a - b |
total -= 30 |
*= |
a = a * b |
total *= 2 |
~/= |
a = a ~/ b |
total ~/= 3 |
??= |
a = a ?? b |
path ??= '/default' |
6. Operador Cascade .. e ?..
(1) Operador Cascade
O operador cascade .. permite realizar múltiplas operações no mesmo objeto sem referenciar repetidamente o nome da variável.
graph TD A[Sistema de Operadores] --> B[Aritméticos + Relacionais + Lógicos] A --> C[Cascade ..] A --> D[Null Safety ?. ?? ??=] A --> E[Teste de Tipo is/as] C --> C1["objeto..metodo1()..metodo2()"]
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
▶ Exemplo
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
: Operador Cascade
class DataPipeline {
String name = '';
int batchSize = 0;
bool verbose = false;
final List<String> sources = [];
void start() => print('$name iniciado');
}
void main() {
// Sem cascade - repetitivo
final pipeline1 = DataPipeline();
pipeline1.name = 'Analytics';
pipeline1.batchSize = 50000;
pipeline1.verbose = true;
pipeline1.sources.add('orders.csv');
pipeline1.start();
// Com cascade - fluído e limpo
final pipeline2 = DataPipeline()
..name = 'Analytics'
..batchSize = 50000
..verbose = true
..sources.add('orders.csv')
..start();
}
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
▶ Exemplo
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
: Null-Safe Cascade ?..
class Customer {
String? name;
String? email;
}
void main() {
Customer? customer;
// Null-safe cascade - ignorado se o objeto for nulo
customer?..name = 'Bob'..email = 'bob@example.com';
print(customer); // null (cascade foi ignorado)
customer = Customer();
customer?..name = 'Bob'..email = 'bob@example.com';
print(customer?.name); // Bob
}
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
| Operador | Significado | Quando o Objeto é nulo |
|---|---|---|
.. |
Operação cascade | Erro |
?.. |
Null-safe cascade | Ignora todo o cascade |
7. Operadores de Null Safety
▶ Exemplo
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
: Três Operadores de Null Safety
class Address {
final String city;
Address(this.city);
}
class Customer {
final String name;
final Address? address;
Customer(this.name, {this.address});
}
class Order {
final String id;
final Customer? customer;
Order(this.id, {this.customer});
}
void main() {
// ?. - acesso null-safe
Order order = Order('ORD-001');
print(order.customer?.name); // null (seguro)
// print(order.customer.name); // Erro em tempo de execução!
// ?? - coalescência nula
String city = order.customer?.address?.city ?? 'Unknown';
print(city); // Unknown
// ??= - atribuição awareness de nulo
String? outputPath;
outputPath ??= '/tmp/reports';
print(outputPath); // /tmp/reports
outputPath ??= '/other/path';
print(outputPath); // /tmp/reports (inalterado)
}
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
| Operador | Significado | Exemplo | Resultado |
|---|---|---|---|
?. |
Acesso seguro | obj?.method() |
null ou resultado da chamada |
?? |
Coalescência nula | value ?? default |
valor se não-nulo, senão default |
??= |
Atribuição awareness de nulo | var ??= value |
Atribui se for nulo |
8. Operadores de Teste de Tipo
▶ Exemplo
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
: is / is! / as
void main() {
Object value = '1,500.00 USD';
// is - verificação de tipo (retorna bool)
if (value is String) {
print('Comprimento da String: ${value.length}'); // Tipo promovido!
}
// is! - verificação negativa de tipo
if (value is! int) {
print('Não é um inteiro');
}
// as - cast de tipo (lança exceção se errado)
String text = value as String; // OK
// int number = value as int; // Erro em tempo de execução!
// Padrão de cast seguro
if (value is String) {
String safe = value; // Sem cast necessário (promovido)
print(safe.toUpperCase());
}
}
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
| Operador | Significado | Em Caso de Falha |
|---|---|---|
is |
Verificação de tipo | Retorna false |
is! |
Verificação negativa de tipo | Retorna true |
as |
Cast de tipo | Lança TypeError |
9. Exemplo Completo: Processamento de Pedidos do DataPipeline com Operadores
// ============================================
// Processamento de Pedidos do DataPipeline com Operadores
// Demonstra todas as categorias de operadores
// ============================================
class Order {
final String id;
final double amount;
String? discountCode;
double? discountPercent;
Order({required this.id, required this.amount});
// Operadores null-safe para cálculo de desconto
double get discountedAmount =>
amount - (amount * (discountPercent ?? 0));
double get tax => discountedAmount * 0.08;
double get total => discountedAmount + tax;
String formatUSD() => '\$${total.toStringAsFixed(2)} USD';
}
class Report {
final List<Order> orders = [];
var totalRevenue = 0.0;
var orderCount = 0;
void addOrder(Order order) {
orders.add(order);
totalRevenue += order.total; // Atribuição composta
orderCount++;
}
double get averageOrderValue =>
orderCount > 0 ? totalRevenue / orderCount : 0;
bool get isHighVolume => orderCount >= 1000;
String get statusLabel => isHighVolume ? 'Alto Volume' : 'Normal';
}
void main() {
final report = Report()
..addOrder(Order(id: 'ORD-001', amount: 1500.0)
..discountPercent = 0.1)
..addOrder(Order(id: 'ORD-002', amount: 3250.50)
..discountCode = 'SAVE20'
..discountPercent = 0.2)
..addOrder(Order(id: 'ORD-003', amount: 890.25));
print('=== Relatório de Pedidos do DataPipeline ===');
for (final order in report.orders) {
final discount = order.discountPercent != null
? '${(order.discountPercent! * 100).toInt()}%'
: 'Nenhum';
print(' ${order.id}: ${order.formatUSD()} (Desconto: $discount)');
}
print('\n--- Resumo ---');
print('Pedidos: ${report.orderCount}');
print('Receita: \$${report.totalRevenue.toStringAsFixed(2)} USD');
print('Média: \$${report.averageOrderValue.toStringAsFixed(2)} USD');
print('Status: ${report.statusLabel}');
// Teste de tipo
print('\nVerificação de tipo: report é ${report.runtimeType}');
print('É Report: ${report is Report}');
}
> **Saída:** Execute em seu DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x; os resultados podem variar ligeiramente com a versão do SDK.
Saída:
=== Relatório de Pedidos do DataPipeline ===
ORD-001: $1458.00 USD (Desconto: 10%)
ORD-002: $2807.43 USD (Desconto: 20%)
ORD-003: $961.47 USD (Desconto: Nenhum)
--- Resumo ---
Pedidos: 3
Receita: $5226.90 USD
Média: $1742.30 USD
Status: Normal
Verificação de tipo: report é Report
É Report: true
❓ Perguntas Frequentes
P: Qual a diferença entre
/e~/? R:/sempre retorna um double (ex: 17 / 5 = 3.4), enquanto~/retorna o resultado da divisão inteira (ex: 17 ~/ 5 = 3). Use~/quando precisar de um resultado inteiro.
P: Qual é o valor de retorno do operador cascade
..? R:..retorna o próprio objeto (não o valor de retorno do último método), permitindo encadeamento contínuo. Esta é uma diferença chave de uma chamada de método regular.
P: Qual a diferença entre
??=e??? R:??é o operador de coalescência nula, que retorna o valor não-nulo.??=é o operador de atribuição awareness de nulo, que só atribui se a variável for nula e retorna o resultado.x ??= yé equivalente ax = x ?? y.
P: Quando devo usar
asem vez deis? R: Prefiraispara verificação de tipo, pois o compilador realiza promoção automática de tipo. Só useasquando tiver certeza do tipo ou precisar de um cast explícito, pois um cast incorreto lançará uma exceção.
P: Quando usar
?..vs..? R: Use?..quando o objeto pode ser nulo, e..quando você tem certeza de que não é nulo.?..ignora todo o cascade se o objeto for nulo.
P:
==compara referências ou valores? R: O==do Dart usa comparação de referências por padrão (mesmo que Java), mas muitos tipos integrados (String, int, double) sobrescrevem==para comparar valores. Classes personalizadas precisam sobrescrever ambos==ehashCode.
P: Operadores bitwise são comumente usados na prática? R: Não frequentemente, mas são essenciais em cenários como sistemas de permissões (flags), parsing de protocolos de rede e algoritmos de criptografia. O desenvolvimento diário usa principalmente operadores aritméticos e lógicos.
📖 Resumo
- Note a diferença entre os operadores aritméticos
/(retorna double) e~/(divisão inteira). - Operadores lógicos
&&e||têm propriedades de curto-circuito, úteis para acesso seguro. - O operador cascade
..simplifica o encadeamento de métodos;?..é sua versão null-safe. - A tríade de Null Safety:
?.(acesso seguro),??(coalescência nula),??=(atribuição awareness de nulo). - Testes de tipo:
isverifica e promove tipos;asforça um cast (lança exceção se inseguro).
📝 Exercícios
- Básico (Dificuldade ⭐): Escreva código usando operadores aritméticos para calcular o valor médio por pedido para 1.500.000 pedidos com um total de 75.000.000 USD. Use o operador de divisão correto.
- Intermediário (Dificuldade ⭐⭐): Use o operador cascade
..para criar e configurar um objeto, definindo pelo menos 4 propriedades e chamando 2 métodos. Depois compare com a versão sem usar cascade. - Desafio (Dificuldade ⭐⭐⭐): Implemente uma classe
SafeValue<T>usando os operadores?.,??e??=para fornecer acesso seguro a valores, valores padrão e atribuição preguiçosa, garantindo que nenhuma exceção de ponteiro nulo seja lançada durante qualquer operação.