Métodos de extensão
Aprenda a adicionar funcionalidades a APIs existentes.
Extension methods adicionam funcionalidade a bibliotecas existentes. Você pode usar extension methods sem nem saber disso. Por exemplo, quando você usa o autocompletar de código em uma IDE, ele sugere extension methods junto com os métodos comuns.
Se assistir a vídeos ajuda você a aprender, confira esta visão geral sobre extension methods.
Visão geral
#Quando você está usando a API de outra pessoa ou quando implementa uma biblioteca amplamente usada, muitas vezes é impraticável, ou impossível, mudar a API. Mesmo assim, você pode querer adicionar alguma funcionalidade.
Por exemplo, considere o código a seguir, que converte uma string em um inteiro:
int.parse('42')
Seria mais agradável (mais curto e mais fácil de usar com ferramentas) ter
essa funcionalidade em String:
'42'.parseInt()
Para habilitar esse código,
você pode importar uma biblioteca que contém uma extensão da classe String:
import 'string_apis.dart';
void main() {
print('42'.parseInt()); // Use an extension method.
}
Extensions podem definir não apenas métodos,
mas também outros membros, como getters, setters e operadores.
Além disso, extensions podem ter nomes, o que ajuda se surgir um conflito de API.
Veja como você pode implementar o extension method parseInt(),
usando uma extension (chamada NumberParsing) que opera sobre strings:
extension NumberParsing on String {
int parseInt() {
return int.parse(this);
}
}
A próxima seção descreve como usar extension methods. Depois dela, há seções sobre implementar extension methods.
Usando extension methods
#Como todo código Dart, extension methods ficam em bibliotecas. Você já viu como usar um extension method: basta importar a biblioteca em que ele está e usá-lo como um método comum:
// Import a library that contains an extension on String.
import 'string_apis.dart';
void main() {
print('42'.padLeft(5)); // Use a String method.
print('42'.parseInt()); // Use an extension method.
}
Isso é tudo o que você costuma precisar saber para usar extension methods.
À medida que escreve seu código, pode também precisar saber
como extension methods dependem de tipos estáticos (em oposição a dynamic) e
como resolver conflitos de API.
Tipos estáticos e dynamic
#
Você não pode invocar extension methods em variáveis do tipo dynamic.
Por exemplo, o código a seguir resulta em uma exceção em tempo de execução:
dynamic d = '2';
print(d.parseInt()); // Runtime exception: NoSuchMethodError
Extension methods funcionam com a inferência de tipos do Dart.
O código a seguir está correto porque
a variável v é inferida como tendo o tipo String:
var v = '2';
print(v.parseInt()); // Output: 2
A razão pela qual dynamic não funciona é que
extension methods são resolvidos com base no tipo estático do receptor.
Como são resolvidos estaticamente,
eles são tão rápidos quanto chamar uma função estática.
Para mais informações sobre tipos estáticos e dynamic, veja
O sistema de tipos do Dart.
Conflitos de API
#Se um membro de extension entrar em conflito com uma interface ou com outro membro de extension, você tem algumas opções.
Uma opção é mudar a forma como você importa a extension conflitante,
usando show ou hide para limitar a API exposta:
// Defines the String extension method parseInt().
import 'string_apis.dart';
// Also defines parseInt(), but hiding NumberParsing2
// hides that extension method.
import 'string_apis_2.dart' hide NumberParsing2;
void main() {
// Uses the parseInt() defined in 'string_apis.dart'.
print('42'.parseInt());
}
Outra opção é aplicar a extension explicitamente, o que resulta em um código que parece uma classe wrapper:
// Both libraries define extensions on String that contain parseInt(),
// and the extensions have different names.
import 'string_apis.dart'; // Contains NumberParsing extension.
import 'string_apis_2.dart'; // Contains NumberParsing2 extension.
void main() {
// print('42'.parseInt()); // Doesn't work.
print(NumberParsing('42').parseInt());
print(NumberParsing2('42').parseInt());
}
Se as duas extensions tiverem o mesmo nome, talvez você precise importar usando um prefixo:
// Both libraries define extensions named NumberParsing
// that contain the extension method parseInt(). One NumberParsing
// extension (in 'string_apis_3.dart') also defines parseNum().
import 'string_apis.dart';
import 'string_apis_3.dart' as rad;
void main() {
// print('42'.parseInt()); // Doesn't work.
// Use the ParseNumbers extension from string_apis.dart.
print(NumberParsing('42').parseInt());
// Use the ParseNumbers extension from string_apis_3.dart.
print(rad.NumberParsing('42').parseInt());
// Only string_apis_3.dart has parseNum().
print('42'.parseNum());
}
Como o exemplo mostra, você pode invocar extension methods implicitamente mesmo se importar usando um prefixo. A única vez em que você precisa usar o prefixo é para evitar um conflito de nome ao invocar uma extension explicitamente.
Implementando extension methods
#Use a sintaxe a seguir para criar uma extension:
extension <extension name>? on <type> { // <extension-name> is optional
(<member definition>)* // Can provide one or more <member definition>.
}
Por exemplo, veja como você pode implementar uma extension na classe String:
extension NumberParsing on String {
int parseInt() {
return int.parse(this);
}
double parseDouble() {
return double.parse(this);
}
}
Os membros de uma extension podem ser métodos, getters, setters ou operadores. Extensions também podem ter campos estáticos e métodos auxiliares estáticos. Para acessar membros estáticos fora da declaração da extension, invoque-os pelo nome da declaração, como em variáveis e métodos de classe.
Extensions sem nome
#Ao declarar uma extension, você pode omitir o nome. Extensions sem nome são visíveis apenas na biblioteca onde são declaradas. Como não têm nome, elas não podem ser aplicadas explicitamente para resolver conflitos de API.
extension on String {
bool get isBlank => trim().isEmpty;
}
Implementando extensions genéricas
#
Extensions podem ter parâmetros de tipo genéricos.
Por exemplo, aqui está um código que estende o tipo embutido List<T>
com um getter, um operador e um método:
extension MyFancyList<T> on List<T> {
int get doubleLength => length * 2;
List<T> operator -() => reversed.toList();
List<List<T>> split(int at) => [sublist(0, at), sublist(at)];
}
O tipo T é vinculado com base no tipo estático da lista sobre
a qual os métodos são chamados.
Recursos
#Para mais informações sobre extension methods, veja o seguinte:
Salvo indicação em contrário, a documentação neste site reflete Dart 3.13.7. Página atualizada pela última vez em 2026-11-12. Ver código-fonte ou relatar um problema.
Encontrou essa página sem tradução ou que precisa de correção? Abra uma issue e nos ajude a manter esse site em PT-BR para ajudar pessoas como você.