Glossário
Um glossário de referência para a terminologia usada em todo o dartbrasil.dev.
A seguir estão as definições de termos usados em toda a documentação do Dart.
AOT
A compilação Ahead-of-Time (AOT) gera binários nativos otimizados em tempo de build.
A compilação Ahead-of-Time (AOT) converte código Dart em código de máquina nativo em tempo de build. Isso resulta em executáveis menores e mais rápidos, que iniciam instantaneamente e têm desempenho consistente. Builds AOT passam por tree shaking para remover código não utilizado e são usados para publicar apps em produção.
Documentos e recursos relacionados
Application package
Um pacote Dart que contém uma aplicação executável.
Um application package (pacote de aplicação) é um pacote Dart que contém um programa ou aplicativo com um main entrypoint. Destinado a ser executado diretamente, seja na linha de comando, em um navegador, ou por outro embedder, como o fornecido pelo Flutter.
Pacotes de aplicação podem ter dependencies em outros packages, mas nunca são dependências de outros pacotes. Diferente de pacotes regulares, eles não são destinados a serem compartilhados.
Pacotes de aplicação devem incluir seus lockfiles no controle de versão, para que todos trabalhando na aplicação e todos os locais onde a aplicação é implantada tenham um conjunto consistente de dependências.
Documentos e recursos relacionados
Assist
Uma edição de código automatizada e local direcionada a fazer melhorias comuns no código.
Um assist é uma edição de código automatizada e local direcionada a fazer melhorias
comuns no código.
Exemplos de assists incluem converter declarações switch em expressões
switch,
inverter os blocos then e else em uma declaração
if,
e inserir widgets em uma estrutura de widgets.
Documentos e recursos relacionados
Asynchronous
Paradigma de programação em Dart em que operações como I/O ou chamadas de rede são concluídas depois, sem bloquear o event loop.
Dart usa um modelo de event loop de thread única para programação assíncrona, permitindo a execução não bloqueante de tarefas demoradas, como I/O de arquivos, requisições HTTP e timers. Diferente do código síncrono, que bloqueia até terminar, operações async são enfileiradas como microtasks/eventos, mantendo as UIs responsivas.
Os principais componentes são:
-
Futures:
Representam um valor disponível depois, criados por APIs como
http.get(). - async/await: Keywords do Dart para escrever código assíncrono legível e fácil de manter.
- Streams: Tratam sequências de eventos assíncronos, como dados vindos de web sockets.
- Isolates: Permitem paralelismo real por meio de contextos de execução independentes com troca de mensagens.
Bottom type
Um tipo que não tem valores e é um subtipo de todos os outros tipos.
O bottom type (tipo inferior) em Dart é o tipo que não tem valores e é considerado um subtypeSubtypeUm tipo que pode ser usado em qualquer lugar em que se espera um valor do seu supertipo. Saiba mais de todos os outros tipos.
Em Dart, o bottom type é representado pelo tipo Never.
Isso significa que um valor do tipo Never pode ser usado em qualquer lugar,
porque tal valor nunca pode realmente existir.
É mais frequentemente usado como o tipo de retorno de funções para
indicar que elas nunca retornam, como aquelas que
lançam exceções ou entram em loop infinito.
Por exemplo, a seguinte função fail sempre lança uma exceção,
então ela é declarada com um tipo de retorno Never para
indicar que ela nunca retorna:
Never fail(String message) {
throw Exception(message);
}
void main() {
String result = fail('Oops'); // OK: Never is a subtype of String.
}
Como fail nunca retorna, atribuí-la a uma String é permitido.
Documentos e recursos relacionados
Callback
Uma função passada como argumento para outra função para ser chamada posteriormente.
Um callback é uma função que você passa como argumento para outra função para que ela possa ser invocada (ou "chamada de volta") em um momento posterior.
Callbacks são frequentemente usados para:
- Manipulação de eventos.
- Personalização do comportamento de APIs.
- Operações assíncronas, como responder ao resultado de um future.
Por exemplo, no seguinte trecho, a função printResult é passada
como callback para doOperation, e é chamada após a operação terminar:
void doOperation(int a, int b, void Function(int) callback) {
final result = a + b;
callback(result);
}
void printResult(int value) {
print('The result is $value.');
}
void main() {
doOperation(3, 4, printResult); // Prints: The result is 7.
}
Documentos e recursos relacionados
Closurization
O processo de transformar um método ou função em um closure.
Closurization (closurização) é o processo onde o Dart transforma um método ou função em um objeto de função (ou tear-off) que pode ser armazenado, passado ou invocado posteriormente.
Um tear-off é uma referência a uma função ou método existente que é avaliado como um objeto de função para aquela entidade, mas não a chama. Quando você faz tear-off de uma função, o runtime (ou compilador) a envolve em um closure para que ela se comporte como qualquer outro objeto de função em Dart.
Exemplo:
class Greeter {
void greet(String name) {
print('Hello, $name!');
}
}
void main() {
final greeter = Greeter();
// Tear-off of the instance method `greet`.
final sayHello = greeter.greet;
sayHello('Dart'); // Prints: Hello, Dart!
}
Neste exemplo, greeter.greet é closurizado em
um objeto de função que captura a instância greeter.
Quando você chama sayHello, ele executa como se
você tivesse chamado greeter.greet(...) diretamente.
A closurização garante que tear-offs possam ser usados onde quer que uma função seja esperada.
Documentos e recursos relacionados
Code asset
Código nativo compilado que é empacotado com um app Dart usando um build hook
e pode ser usado por meio de dart:ffi.
Um code asset (asset de código) é código compilado que não é escrito em Dart, mas
pode ser empacotado e usado por uma aplicação Dart.
Exemplos incluem bibliotecas compartilhadas (.so, .dll,
.dylib) construídas
em linguagens como C, C++ ou Rust.
Code assets podem ser empacotados com um pacote Dart usando um build hook. O código Dart pode chamar esses assets usando FFI.
Historicamente, code assets também eram chamados de native assets ou native code assets.
Code assets são úteis para:
- Integrar com bibliotecas nativas existentes.
- Acessar recursos do sistema que não são expostos diretamente em Dart.
- Compartilhar funcionalidades críticas para desempenho entre plataformas.
Por exemplo, uma aplicação Dart poderia incluir uma biblioteca nativa .so
que expõe funções específicas, e chamar essas funções a partir do Dart.
Documentos e recursos relacionados
Combinator
Uma cláusula de palavra-chave que limita ou modifica o que é importado ou exportado.
Em Dart, um combinator (combinador) é uma cláusula que
segue uma diretiva import ou export para limitar ou modificar
o conjunto de nomes trazidos para o escopo.
Dart suporta dois tipos de combinadores:
show— inclui explicitamente nomes específicos.hide— exclui nomes específicos.
Combinadores ajudam a controlar a poluição do namespace e evitar conflitos quando múltiplas bibliotecas definem símbolos com o mesmo nome.
Exemplo usando show:
import 'dart:math' show pi, sqrt;
void main() {
print(pi); // Accessible
print(sqrt(9)); // Accessible
// print(Random()); // Error: Random is not imported.
}
Exemplo usando hide:
import 'dart:math' hide pi;
void main() {
// print(pi); // Error: pi is hidden.
print(Random()); // Accessible
}
Documentos e recursos relacionados
Constant context
Uma região do código em que a keyword const está implícita e tudo dentro dessa região precisa ser constante.
Um constant context (contexto constante) é uma região do código em que não é
necessário incluir a keyword const, porque ela está implícita pelo
fato de tudo naquela região ser obrigatoriamente constante.
Os seguintes locais são contextos constantes:
-
Tudo dentro de um literal de lista, map ou set precedido pela keyword
const. Por exemplo:dartvar l = const [/*constant context*/]; -
Os argumentos dentro da invocação de um construtor constante. Por exemplo:
dartvar p = const Point(/*constant context*/); -
O inicializador de uma variável precedida pela keyword
const. Por exemplo:dartconst v = /*constant context*/; Annotations.
-
A expressão em uma cláusula
case. Por exemplo:dartvoid f(int e) { switch (e) { case /*constant context*/: break; } }
Documentos e recursos relacionados
Context type
O tipo que o código ao redor espera de uma expressão.
O context type (tipo de contexto) é o tipo que o código ao redor espera de uma expressão, como o tipo de uma variável, o tipo de um parâmetro ou um tipo de retorno.
O Dart usa o context type para interpretar e inferir o significado de expressões, incluindo:
-
Inferência de tipo ("inferência descendente"):
dartList<int> list = [];O context type
List<int>permite que o compilador infira o tipo da lista como<int>[]. -
Downcast implícito:
dartString asString(dynamic value) => value;O contexto de retorno é
String, então o Dart insere um downcast implícito. -
Interpretação de literais:
dartdouble d = 0;O context type
doublefaz com que0se comporte como0.0. -
Atalho de acesso estático (dot shorthand):
dartint x = .parse(input);O context type é
int, então.parseé resolvido paraint.parse(input).
Algumas expressões não têm context type, incluindo:
-
Quando usadas como statements: Expressões como
set.remove(value);são usadas apenas pelo seu efeito, não pelo seu valor, então nenhum tipo é esperado. -
Quando o context type é inferido a partir da própria expressão: Por exemplo, em
var list = [1];, o literal de lista não tem context type. O Dart infereList<int>a partir do conteúdo e atribui esse tipo à variável.
Documentos e recursos relacionados
Dart SDK constraint
As versões do Dart que um pacote suporta.
O intervalo de versões do Dart SDK que o próprio pacote declara suportar.
Uma SDK constraint é especificada usando a sintaxe normal de version constraint,
mas em uma seção especial environment no pubspec.
Documentos e recursos relacionados
Definite assignment
A determinação de se uma variável recebeu com certeza um valor antes de ser usada.
A análise de definite assignment (atribuição definitiva) é o processo de determinar, para cada variável local em cada ponto do código, qual das seguintes situações é verdadeira:
- A variável recebeu com certeza um valor (definitely assigned).
- A variável com certeza não recebeu um valor (definitely unassigned).
- A variável pode ou não ter recebido um valor, dependendo do caminho de execução percorrido até aquele ponto.
A análise de definite assignment ajuda a encontrar problemas no código, como lugares onde uma variável que pode não ter recebido um valor é referenciada, ou lugares onde uma variável que só pode receber um valor uma vez é atribuída depois de talvez já ter recebido um valor.
Por exemplo, no código a seguir a variável s é
definitely unassigned quando é passada como argumento para print:
void f() {
String s;
print(s);
}
Mas no código a seguir, a variável s é definitely assigned:
void f(String name) {
String s = 'Hello $name!';
print(s);
}
A análise de definite assignment consegue até dizer se
uma variável é definitely assigned (ou unassigned) quando
há vários caminhos de execução possíveis.
No código a seguir, a função print é chamada se a
execução passar pelo ramo true ou pelo ramo false da
instrução if, mas como s recebe um valor independentemente de qual ramo for seguido,
ela é definitely assigned antes de ser passada para print:
void f(String name, bool casual) {
String s;
if (casual) {
s = 'Hi $name!';
} else {
s = 'Hello $name!';
}
print(s);
}
Na análise de fluxo, o fim da instrução if é chamado de
join (junção): um lugar onde dois ou mais caminhos de execução se reúnem novamente.
Onde há uma junção, a análise diz que
uma variável é definitely assigned se ela for definitely assigned em
todos os caminhos que se juntam, e definitely unassigned se
for definitely unassigned em todos os caminhos.
Às vezes uma variável recebe um valor em um caminho, mas não em outro,
caso em que a variável pode ou não ter recebido um valor.
No exemplo a seguir, o ramo true da instrução if pode ou não
ser executado, então a variável pode ou não ter recebido um valor:
void f(String name, bool casual) {
String s;
if (casual) {
s = 'Hi $name!';
}
print(s);
}
O mesmo vale se houver um ramo false que
não atribui um valor a s.
A análise de loops é um pouco mais complicada,
mas segue o mesmo raciocínio básico.
Por exemplo, a condição de um loop while é sempre executada,
mas o corpo pode ou não ser. Assim como em uma instrução if,
há uma junção no fim da instrução while entre
o caminho em que a condição é true e
o caminho em que a condição é false.
Documentos e recursos relacionados
Dependency
Um pacote Dart do qual um pacote depende.
Uma dependência é qualquer outro pacote Dart do qual um pacote depende. Se o seu pacote quer importar código de algum outro pacote, esse pacote precisa primeiro ser uma dependência sua. As dependências são especificadas no arquivo pubspec do seu pacote com a sintaxe descrita em Dependências de pacotes.
Para ver as dependências usadas por um pacote, use pub deps.
Documentos e recursos relacionados
Dependency graph
Uma representação de como os componentes de um sistema dependem uns dos outros.
Um dependency graph (grafo de dependências) é um grafo direcionado que mostra as relações entre diferentes componentes de um sistema, como arquivos, módulos, pacotes, funções ou assets. Cada nó representa um componente, e cada aresta representa uma dependência entre dois componentes.
No Dart e no Flutter, grafos de dependências são comumente usados por ferramentas como:
- O compilador, para determinar a ordem de build.
- O gerenciador de pacotes, para resolver as versões dos pacotes.
- Sistemas de build, para detectar o que precisa ser recompilado.
- Tree shaking, para remover código não utilizado.
Por exemplo, se o arquivo main.dart importa utils.dart, e utils.dart
por sua vez
importa math.dart, o grafo de dependências ajuda o compilador a entender a ordem correta
para processar esses arquivos e quais partes do programa são realmente usadas.
Grafos de dependências são essenciais para:
- Builds eficientes
- Eliminação de código morto (tree shaking)
- Resolução de dependências
- Compilação incremental
Documentos e recursos relacionados
Dependency source
Um tipo de local de onde o pub pode obter pacotes.
Um tipo de repositório ou local de onde o pub pode obter pacotes. Uma source não é um local específico, como o site pub.dev ou uma URL git específica. Cada source descreve um procedimento geral para acessar um pacote.
Como exemplo, git é uma das dependency sources suportadas. A source git sabe como baixar pacotes a partir de uma URL git. Várias sources suportadas estão disponíveis.
Documentos e recursos relacionados
Dot shorthand
Uma forma abreviada de sintaxe que permite omitir o nome do tipo ao acessar construtores ou membros estáticos, incluindo valores de enum.
Um dot shorthand (atalho com ponto) é um recurso da linguagem que permite um código mais conciso, omitindo o nome do tipo ao acessar construtores ou membros estáticos, incluindo valores de enum.
Esse recurso só é permitido quando o tipo esperado da expressão pode ser inferido de forma única a partir do contexto ao redor (o context type).
Por exemplo, em vez de escrever Status.running, você pode escrever .running
se o context type já for conhecido como Status:
enum Status { running, stopped }
void updateStatus(Status s) {
print('Status updated to: $s');
}
void main() {
updateStatus(.running); // Resolves to Status.running
}
Documentos e recursos relacionados
Entrypoint
Uma biblioteca Dart invocada diretamente por uma implementação Dart.
No contexto geral do Dart, um entrypoint (ponto de entrada) é
uma biblioteca Dart invocada diretamente por uma implementação Dart.
Por exemplo, quando você passa uma biblioteca Dart como argumento de linha de comando para
a Dart VM standalone, essa biblioteca é o entrypoint.
Em outras palavras, normalmente é o arquivo .dart que contém
main().
No contexto do pub, um entrypoint package ou root package é a raiz de um grafo de dependências. Geralmente é uma aplicação. Quando você executa seu app, ele é o entrypoint package. Todos os outros pacotes dos quais ele depende não são entrypoints nesse contexto.
Um pacote pode ser entrypoint em alguns contextos e não em outros.
Digamos que seu app use um pacote A.
Quando você executa seu app, A não é o entrypoint package.
No entanto, se você for até A e executar os testes dele, nesse contexto,
ele é o entrypoint, já que seu app não está envolvido.
Documentos e recursos relacionados
Entrypoint directory
Um diretório que contém entrypoints Dart.
Um entrypoint directory (diretório de entrypoint) é um diretório dentro do seu pacote Dart que tem permissão para conter entrypoints Dart.
O pub tem uma lista desses diretórios: benchmark, bin, example,
test, tool e web (e lib, para
apps Flutter).
Qualquer subdiretório deles (exceto bin) também pode conter entrypoints.
Documentos e recursos relacionados
Extension type
Um wrapper de tempo de compilação que oferece uma abstração de custo zero sobre um tipo subjacente.
Um extension type (tipo de extensão) introduz um wrapper estático, existente apenas em tempo de compilação, em torno de um tipo de representação subjacente.
Como um extension type é apagado em tempo de compilação, ele não tem custo de memória ou de CPU em tempo de execução, ao mesmo tempo que oferece uma API distinta e segura em relação a tipos.
Documentos e recursos relacionados
Function
Um termo genérico que se refere a funções de nível superior, funções locais, métodos estáticos e métodos de instância.
Documentos e recursos relacionados
Getter
Um método especial que oferece acesso de leitura às propriedades de um objeto.
Getters e setters são métodos especiais que
oferecem acesso de leitura e escrita às propriedades de um objeto.
Lembre que cada variável de instância tem um getter implícito,
além de um setter implícito quando apropriado.
Você pode criar propriedades adicionais implementando getters e setters,
usando as keywords get e set.
Documentos e recursos relacionados
Immediate dependency
Uma dependência que um pacote Dart usa diretamente.
Uma immediate dependency (dependência imediata) é uma dependência que um
pacote usa diretamente e declara por conta própria.
As dependências que você lista no arquivo pubspec.yaml
são
as dependências imediatas do seu pacote.
Todas as outras dependências são dependências transitivas.
Documentos e recursos relacionados
Immutable
Um objeto cujo estado, incluindo todos os valores aninhados, não pode ser alterado após ser criado.
Um objeto imutável é aquele cujo estado não pode ser modificado depois de criado.
Quando um objeto é imutável, todos os seus campos devem ser final
(não podem ser reatribuídos), e
os valores desses campos devem, por sua vez, ser imutáveis (não podem ser mutados).
Isso ajuda a garantir consistência e permite um uso mais seguro em código concorrente ou reativo.
No Dart, uma classe é imutável se você:
- Declarar todos os campos como final, para que não possam ser reatribuídos.
- Garantir que os próprios valores dos campos sejam imutáveis.
-
Opcionalmente, usar a annotation
@immutabledo pacote meta. Isso permite que o analyzer avise você se algum campo não for final ou referenciar um tipo mutável.
Além disso, todos os valores const do Dart são imutáveis. Por exemplo, const [1, 2, 3]
cria uma lista imutável. Se uma classe tem um construtor const
(que não seja factory), então
todos os seus campos devem ser final.
Exemplo:
import 'package:meta/meta.dart';
@immutable
class User {
final String name;
final int age;
const User(this.name, this.age);
}
No exemplo acima, depois de criado, você não pode modificar a instância de User.
Você precisa criar uma nova para alterar qualquer dado.
Documentos e recursos relacionados
Instantiate
Criar uma instância concreta (objeto) de uma classe.
Instanciar uma classe significa criar um objeto do tipo dessa
classe na memória.
No Dart, você faz isso chamando um construtor,
como em final myItem = Item().
Classes abstratas não podem ser instanciadas diretamente.
Documentos e recursos relacionados
Interop
A capacidade de código Dart interagir com código escrito em outras linguagens.
Interop (abreviação de interoperability, interoperabilidade) refere-se à capacidade do Dart de se comunicar e trabalhar com código escrito em outras linguagens de programação.
No Dart, interop é comumente usado para:
- Chamar código nativo escrito em linguagens como C, C++ ou Rust.
- Interagir com APIs específicas de plataforma.
- Reutilizar bibliotecas existentes que não são escritas em Dart.
O Dart oferece diferentes mecanismos de interop dependendo da plataforma e do caso de uso. Por exemplo, aplicações Dart podem usar a Foreign Function Interface (FFI) para chamar bibliotecas nativas, ou camadas de interop específicas de plataforma ao rodar no Flutter ou na web.
Documentos e recursos relacionados
Irrefutable pattern
Um padrão que sempre casa.
Irrefutable patterns (padrões irrefutáveis) são padrões que sempre casam. Padrões irrefutáveis são os únicos que podem aparecer em irrefutable contexts (contextos irrefutáveis): os contextos de padrão de declaração e atribuição.
Documentos e recursos relacionados
Just-in-Time compilation (JIT)
Just-in-Time (JIT) é um modo de compilação que compila código em tempo de execução para iterações rápidas de desenvolvimento.
A compilação Just-in-Time (JIT) compila código Dart para código de máquina nativo enquanto ele roda. Isso habilita recursos como hot reload e uma depuração rica, ao permitir compilação incremental. O JIT é tipicamente usado durante o desenvolvimento, enquanto builds de produção usam AOT.
Documentos e recursos relacionados
Late
Uma keyword que habilita a inicialização adiada de variáveis e é tipicamente usada com variáveis non-nullable.
A keyword late no Dart é usada para indicar que uma variável
será inicializada depois, após sua declaração, mas antes de ser usada.
Isso evita a necessidade de tornar uma variável nullable (?) quando você
sabe que ela vai receber um valor com certeza, só que não imediatamente.
Usar late adia a inicialização, permitindo escrever código mais
flexível e legível, especialmente ao lidar com dependências
ou configurações complexas.
Por exemplo:
late String description;
void setup() {
description = 'This will be initialized before use.';
}
Tenha cuidado com variáveis late que fazem parte de uma API pública.
Se um cliente acessar a variável antes de ela ser inicializada,
ele vai encontrar um LateInitializationError, que oferece
pouco contexto. Nesses casos, considere usar uma
variável nullable privada com um getter público que lança um
erro descritivo (por exemplo, StateError) se for acessada cedo demais,
já que isso pode dar um feedback mais claro aos usuários da API, apesar da
complexidade extra.
Você também pode usar late final quando a variável deve ser definida apenas uma vez.
Isso é útil em cenários em que o valor não está disponível no momento da
construção do objeto, como em dependências cíclicas em grafos de objetos.
Exemplo:
class LinkedQueue<T> {
late final QueueLink<T> _head;
LinkedQueue() {
_head = QueueLink<T>._head(owner: this); // Cyclic reference between objects
}
}
Cuidado: se uma variável late for acessada antes de ser inicializada ou nunca for inicializada, isso causará um erro em tempo de execução.
Documentos e recursos relacionados
Library
Uma unidade de compilação única em Dart, formada por um arquivo Dart principal e suas parts.
Uma library (biblioteca) Dart é uma unidade de compilação única em Dart,
formada por um arquivo .dart principal e qualquer número opcional de
parts.
Bibliotecas têm seu próprio escopo privado.
Documentos e recursos relacionados
Library-private
Acessibilidade restrita à biblioteca onde é definida.
Em Dart, a privacidade é definida no escopo da biblioteca, e não da classe.
Qualquer identificador prefixado com um underscore, como _myVariable, é library-private.
Documentos e recursos relacionados
Lockfile
Um arquivo chamado pubspec.lock que especifica as versões de cada dependência.
Um arquivo chamado pubspec.lock que especifica as
versões concretas e outras informações de identificação de cada
dependência imediata e transitiva
da qual um pacote depende.
Diferente do pubspec, que lista apenas as dependências imediatas e permite intervalos de versão, o lockfile fixa de forma abrangente todo o grafo de dependências em versões específicas dos pacotes. Um lockfile garante que você consiga recriar a configuração exata dos pacotes usados por uma aplicação.
O lockfile é gerado automaticamente pelo pub quando você executa
pub get, pub upgrade
ou pub downgrade.
O pub inclui um content hash para cada dependência
para verificar nas próximas resoluções.
Se o seu pacote for um application package, normalmente você o incluirá no controle de versão. Para pacotes regulares (de biblioteca), geralmente não.
Documentos e recursos relacionados
Mixin application
Uma classe criada quando um mixin é aplicado a uma classe.
Uma mixin application (aplicação de mixin) é a classe criada quando um mixin é aplicado a uma classe. Por exemplo, considere as seguintes declarações:
class A {}
mixin M {}
class B extends A with M {}
A classe B é uma subclasse da aplicação do mixin M sobre A,
às vezes chamada de A+M. A classe A+M é uma subclasse de
A e
tem membros copiados de M.
Você pode dar um nome de fato a uma aplicação de mixin definindo-a assim:
class A {}
mixin M {}
class A_M = A with M;
Dada essa declaração de A_M, a declaração de B a seguir é
equivalente à declaração de B do exemplo original:
class B extends A_M {}
Documentos e recursos relacionados
Null safety
Um recurso do sistema de tipos do Dart em que variáveis não podem
conter null, a menos que o tipo explicitamente permita.
Null safety (segurança contra null) no Dart é um recurso da linguagem que ajuda a
prevenir erros causados por acesso não intencional a valores null.
Com null safety, os tipos são non-nullable por padrão:
uma variável não pode conter null, a menos que você
declare o tipo dela como nullable com o sufixo ?.
int count = 42; // Can't be null.
int? maybeCount; // Can be null (and is initialized to null by default).
A null safety do Dart é sound (sólida).
Se o sistema de tipos determina que uma variável tem um tipo non-nullable,
essa variável é garantida para nunca ser null em tempo de execução.
Essa garantia de solidez é imposta por meio de
uma combinação de análise estática e verificações em tempo de execução,
e permite otimizações do compilador
que produzem código menor e mais eficiente.
Documentos e recursos relacionados
Obviously typed
Uma expressão cujo tipo pode ser determinado mecanicamente, sem ambiguidade.
Uma expressão em Dart é considerada obviously typed (de tipo óbvio) quando o seu tipo fica imediatamente claro pela sintaxe, sem precisar de inferência ou análise complexa.
Esse conceito é usado principalmente em regras de lint como
omit_obvious_local_variable_types e specify_nonobvious_property_types
para decidir se uma anotação de tipo explícita é redundante ou necessária.
Expressões de tipo óbvio
#Os seguintes tipos de expressões são considerados de tipo óbvio:
-
Literais que não são de coleção:
1,true,'Hello'. -
Literais de coleção com argumentos de tipo explícitos:
<int>[],<String, bool>{}. -
Literais de list/set homogêneos cujos elementos são de tipo óbvio:
[1, 2, 3],{true, false}. -
Literais de map homogêneos com tipos de chave e valor óbvios:
{1: 10, 2: 20}. -
Literais de record com tipos óbvios:
(1, enabled: true). - Variáveis locais e parâmetros formais que não foram promovidos.
-
Criação de instância com classes não genéricas ou com argumentos de tipo explícitos:
C(),Set<int>(). -
Cascades com alvos de tipo óbvio:
StringBuffer('Hello, ')..write('world!'). -
Casts de tipo:
x as int. -
Expressões condicionais com ramos de tipo óbvio e do mesmo tipo:
condition ? 1 : 2. -
Testes de tipo:
x is String. -
Expressões throw:
throw Exception(). -
Expressões entre parênteses cujo conteúdo é de tipo óbvio:
('Hello!'). -
thise literais de tipo:String.
Nesta lista, homogêneo significa "onde todo elemento tem o mesmo tipo".
Por exemplo, {1: 'one', 2: 'two'} é um map homogêneo,
mas {1: 'one', 1.5: true} não é.
Por outro lado, se o tipo de uma expressão exige inferência (por exemplo
[1, 2.5] → List<num>), ela não
é considerada de tipo óbvio.
Essa distinção ajuda as regras de estilo a decidir quando exigir ou omitir anotações de tipo para clareza e consistência.
Documentos e recursos relacionados
Override inference
Como os tipos ausentes em uma declaração de método são inferidos.
Override inference (inferência por sobrescrita) é o processo pelo qual quaisquer tipos ausentes em uma declaração de método são inferidos com base nos tipos correspondentes do método, ou métodos, que ele sobrescreve.
Se um método candidato (o método que está sem informação de tipo) sobrescreve um único método herdado, então os tipos correspondentes do método sobrescrito são inferidos. Por exemplo, considere o seguinte código:
class A {
int m(String s) => 0;
}
class B extends A {
@override
m(s) => 1;
}
A declaração de m em B é um candidato porque
está sem o tipo de retorno e sem o tipo do parâmetro.
Como ela sobrescreve um único método (o método m de A),
os tipos do método sobrescrito serão usados para inferir
os tipos ausentes, e será como se o método em B tivesse sido
declarado como int m(String s) => 1;.
Se um método candidato sobrescreve vários métodos, e o tipo de função de um desses métodos sobrescritos, Ms, é um supertipo dos tipos de função de todos os outros métodos sobrescritos, então Ms é usado para inferir os tipos ausentes. Por exemplo, considere o seguinte código:
class A {
int m(num n) => 0;
}
class B {
num m(int i) => 0;
}
class C implements A, B {
@override
m(n) => 1;
}
A declaração de m em C é um candidato à override inference porque
está sem o tipo de retorno e sem o tipo do parâmetro.
Ela sobrescreve tanto m em A quanto m
em B, então o compilador precisa
escolher um deles para inferir os tipos ausentes.
Mas como o tipo de função de m em A (int Function(num)) é
um supertipo do tipo de função de m em B (num Function(int)),
a função de A é usada para inferir os tipos ausentes. O resultado é
o mesmo que declarar o método em C como int m(num n) => 1;.
É um erro se nenhum dos métodos sobrescritos tiver um tipo de função que seja supertipo de todos os outros métodos sobrescritos.
Documentos e recursos relacionados
Package
Um diretório com uma coleção de bibliotecas Dart, recursos e um arquivo pubspec.yaml que os descreve.
Um package (pacote) Dart é uma coleção de bibliotecas Dart e recursos em
um diretório, com um arquivo pubspec.yaml
na raiz desse diretório.
Pacotes podem ter dependências em outros pacotes
e podem ser dependências em si.
O diretório /lib de um pacote contém as bibliotecas públicas
que
outros pacotes podem importar e usar.
Eles também podem incluir scripts para serem executados diretamente.
Um pacote que não se destina a ser usado como dependência por
outros pacotes é um application package.
Pacotes compartilhados são publicados no pub.dev,
mas você também pode ter pacotes não publicados.
Não inclua o lockfile de um pacote no controle de versão, já que bibliotecas devem suportar um intervalo de versões de dependências. As version constraints das dependências imediatas de um pacote devem ser o mais amplas possível, mantendo ao mesmo tempo a garantia de que as dependências serão compatíveis com as versões com as quais foram testadas.
Como o semantic versioning exige que
bibliotecas incrementem o número da versão major para
qualquer mudança incompatível com versões anteriores, pacotes normalmente
exigem que as versões das dependências sejam maiores ou iguais às
versões testadas e menores que a próxima versão major.
Então, se sua biblioteca dependesse do pacote (fictício) transmogrify
e
você a tivesse testado na versão 1.2.1, sua version constraint seria
^1.2.1.
Documentos e recursos relacionados
Package uploader
Um usuário do pub.dev que tem permissões administrativas sobre um pacote.
Um package uploader (publicador de pacote) é alguém que tem permissões administrativas sobre um pacote. Um package uploader pode enviar novas versões do pacote, e também pode adicionar e remover outros uploaders desse pacote.
Se um pacote tiver um verified publisher, então todos os membros do publisher podem publicar o pacote.
Documentos e recursos relacionados
Part file
Um arquivo-fonte Dart que contém uma diretiva part of.
Um part file (arquivo part) é um arquivo-fonte Dart que contém uma diretiva part of
e é incluído em uma biblioteca usando a diretiva part.
Documentos e recursos relacionados
Potentially constant
Uma expressão que pode ser avaliada em tempo de compilação se todos os parâmetros do construtor constante que a envolve forem substituídos por valores constantes, e todos os parâmetros de tipo forem substituídos por tipos concretos.
Uma potentially constant expression (expressão potencialmente constante) é uma expressão que é válida em contextos onde uma constante é exigida, como as listas de inicialização de construtores constantes, mesmo que ela não seja uma constante de tempo de compilação por si só, porque referencia parâmetros do construtor ou parâmetros de tipo.
Se todos os parâmetros do construtor constante que a envolve forem substituídos por valores constantes do tipo apropriado, e todos os parâmetros de tipo forem substituídos por tipos concretos, uma expressão potencialmente constante se torna uma expressão constante de tempo de compilação.
Por exemplo, na seguinte classe:
class ConstPoint {
final int x;
final int y;
const ConstPoint(int a) : x = a, y = a + 1;
}
As expressões de inicialização a e a + 1
são expressões potencialmente constantes.
Elas não são expressões constantes
porque o valor de a depende de como o construtor é chamado.
No entanto, se o construtor for invocado com const ConstPoint(3),
o parâmetro a é substituído pela constante 3,
tornando 3 e 3 + 1 expressões constantes.
Documentos e recursos relacionados
Potentially non-nullable
Um tipo que é non-nullable explicitamente ou por ser um parâmetro de tipo.
Um tipo é potentially non-nullable (potencialmente non-nullable) se for explicitamente non-nullable ou se for um parâmetro de tipo.
Um tipo é explicitamente non-nullable se for um
nome de tipo que não é seguido por um ponto de interrogação (?).
Observe que há alguns tipos que são sempre nullable, como
Null e dynamic, e que FutureOr só é non-nullable se
não for seguido por um ponto de interrogação e
o argumento de tipo for non-nullable (como em FutureOr<String>).
Parâmetros de tipo são potencialmente non-nullable porque o tipo
real em tempo de execução (o tipo especificado como argumento de tipo) pode ser non-nullable.
Por exemplo, dada a declaração class C<T> {},
o tipo C pode ser usado com um argumento de tipo non-nullable, como em
C<int>.
Documentos e recursos relacionados
Primary constructor
Uma sintaxe concisa para declarar um construtor principal diretamente no cabeçalho de uma classe, enum ou extension type.
Um primary constructor (construtor primário) é um atalho de sintaxe que declara um construtor principal diretamente no cabeçalho de definição de uma classe, enum ou extension type.
Construtores primários reduzem o código repetitivo de declarações de parâmetros e
inicialização de campos, permitindo declarar parâmetros (final
ou var)
e formais de inicialização (this.field) diretamente no cabeçalho.
Declarar um parâmetro com o modificador var ou final
cria e inicializa implicitamente esse campo:
class Point(var int x, var int y);
Documentos e recursos relacionados
Private named parameter
Um parâmetro nomeado de construtor com nome privado na declaração e nome público nos pontos de chamada.
Um private named parameter (parâmetro nomeado privado) é um parâmetro nomeado cujo nome é privado.
Ele só é permitido quando o parâmetro é de inicialização (como this._x)
ou de declaração (como final T _x ou var T _x). Parâmetros de inicialização
ocorrem em construtores tradicionais ou primários, enquanto parâmetros de declaração
só ocorrem em construtores primários.
Um parâmetro de inicialização inicializa a variável de instância com o nome privado informado. Um parâmetro de declaração tanto declara quanto inicializa implicitamente uma variável de instância com o nome privado informado.
Nos pontos de chamada, os argumentos são passados para parâmetros nomeados privados especificando o nome público correspondente (omitindo o underscore inicial):
class Point {
final double _x;
final double _y;
// Callers use the public names 'x' and 'y'.
Point.named({required this._x, required this._y});
}
void main() {
var p = Point.named(x: 10, y: 20); // Initializes '_x' and '_y'.
}
Documentos e recursos relacionados
Pub content hash
Hashes SHA256 mantidos pelo pub.dev para validar a integridade dos pacotes.
O repositório pub.dev mantém um content hash SHA256 de cada versão de cada pacote que hospeda. Os clientes do pub usam esse hash para validar a integridade dos pacotes baixados e se proteger contra alterações no repositório de origem.
Quando o dart pub get baixa um pacote,
ele calcula o hash do arquivo baixado.
O hash de cada dependência hospedada é armazenado junto com a
resolução no lockfile.
O cliente do pub usa esse content hash para verificar se
executar dart pub get novamente com o mesmo lockfile,
possivelmente em outro computador, usa exatamente os mesmos pacotes.
Se o hash travado não corresponder ao que está atualmente no pub cache, o pub baixa o arquivo novamente. Se ainda não corresponder, o lockfile é atualizado e um aviso é exibido.
Para transformar uma divergência em erro em vez de aviso,
use a opção --enforce-lockfile
do dart pub get.
Com essa opção, se o pub não conseguir encontrar arquivos de pacote com os mesmos hashes,
a resolução de dependências falha e o lockfile não é atualizado.
Documentos e recursos relacionados
Pub system cache
Um diretório onde o pub armazena os pacotes remotos baixados.
Quando o pub obtém um pacote remoto,
ele o baixa para um único diretório de pub system cache (cache do sistema do pub).
No macOS e no Linux, esse diretório fica por padrão em ~/.pub-cache.
No Windows, o diretório fica por padrão em %LOCALAPPDATA%\Pub\Cache,
embora o local exato possa variar conforme a versão do Windows.
Você pode especificar outro local usando a variável de ambiente
PUB_CACHE.
Depois que os pacotes estão no cache do sistema,
o pub cria um arquivo package_config.json que mapeia cada pacote
usado pela sua aplicação para o pacote correspondente no cache.
Você só precisa baixar uma determinada versão de um pacote uma vez
e depois pode reutilizá-la em quantos pacotes quiser.
Se você especificar a flag --offline para usar pacotes em cache,
pode apagar e regenerar seus arquivos package_config.json
sem precisar acessar a rede.
Documentos e recursos relacionados
Pub workspace
Uma coleção de pacotes desenvolvidos em conjunto com uma resolução compartilhada das restrições de dependência.
Um pub workspace (workspace do pub) associa uma coleção de pacotes locais que são tratados como uma única unidade durante o desenvolvimento, permitindo a resolução compartilhada das restrições de dependência deles. Útil para desenvolver em um monorepo.
Os pacotes compartilham os arquivos pubspec.lock e
.dart_tool/package_config.json no diretório raiz do workspace.
Documentos e recursos relacionados
Public library
Uma biblioteca localizada no diretório lib de um pacote, mas
não dentro do diretório lib/src.
Uma biblioteca pública é uma biblioteca localizada dentro do diretório lib
do pacote, mas não dentro do diretório lib/src.
Documentos e recursos relacionados
Quick fix
Uma edição de código automatizada e local direcionada a corrigir o problema relatado por um diagnóstico específico.
Documentos e recursos relacionados
Refactor
Uma edição de código direcionada a modificações não locais ou que exigem interação do usuário.
Um refactor (refatoração) é uma edição de código direcionada a modificações que são não locais ou que exigem interação do usuário. Exemplos de refactors incluem renomear, remover ou extrair código.
Documentos e recursos relacionados
Refutable pattern
Um padrão que pode ser testado contra um valor.
Um refutable pattern (padrão refutável) é um padrão que pode ser testado contra um valor para determinar se o padrão casa com o valor. Se não casar, o padrão refuta, ou nega, a correspondência. Padrões refutáveis aparecem em matching contexts (contextos de correspondência).
Documentos e recursos relacionados
Reified generics
A preservação dos argumentos de tipo genéricos em tempo de execução,
permitindo verificações de tipo contra o tipo genérico completo,
como com is List<String>.
No Dart, os argumentos de tipo genéricos são reified (reificados), o que significa que eles mantêm o controle dos seus argumentos de tipo em tempo de execução. Isso permite inspecionar e verificar o tipo genérico completo de um objeto, e não apenas o seu tipo bruto, sem argumentos de tipo.
Por exemplo, você pode verificar se uma lista é
especificamente um subtipo de List<String>:
final names = ['Dart', 'Flutter', 'Jaspr'];
print(names is List<String>); // Prints: true
print(names is List<int>); // Prints: false
Os genéricos reificados também habilitam as verificações de tipo em tempo de execução do Dart
para tipos genéricos covariantes.
Para garantir a solidez, quando você adiciona um elemento a uma lista,
o Dart valida em tempo de execução que o elemento corresponde
ao argumento de tipo real da lista.
Por exemplo, se você tentar adicionar um double a uma List<int>,
como double não é subtipo de int,
o Dart lança um erro em tempo de execução:
List<num> numbers = <int>[1, 2, 3]; // Explicitly typed as `List<num>`.
numbers.add(1.5); // Throws a TypeError because `1.5` isn't an int.
Isso contrasta com algumas outras linguagens, como Java,
em que os argumentos de tipo são removidos antes da execução, por meio de
type erasure (apagamento de tipo).
Assim, nessas linguagens, você pode testar se um objeto é uma List,
mas não se é uma List<String>.
Documentos e recursos relacionados
Scope
A região de um programa em que um nome (como uma variável, função ou classe) é visível e pode ser referenciado.
Scope (escopo) define onde os identificadores, como variáveis, parâmetros, funções e classes, são acessíveis dentro de um programa.
O Dart usa escopo léxico (estático), o que significa que o escopo de um nome é determinado pela estrutura do código-fonte, e não pela forma como o programa é executado em tempo de execução. Veja escopo léxico para mais detalhes.
Tipos comuns de escopo no Dart incluem:
- Escopo de classe: membros acessíveis dentro de uma classe.
-
Escopo de bloco: variáveis declaradas dentro de blocos como
if,forouwhile. - Escopo de função: parâmetros e variáveis locais dentro de uma função.
- Escopo de biblioteca: declarações de nível superior visíveis dentro de uma biblioteca.
Documentos e recursos relacionados
Shadowing
Quando uma declaração local oculta outra com o mesmo nome.
Shadowing (sombreamento) ocorre quando uma declaração local, como uma variável ou parâmetro, usa o mesmo nome de uma declaração existente em um escopo externo, tornando a externa inacessível dentro do escopo interno.
Embora seja válido em Dart, o shadowing pode levar a código confuso ou a comportamentos não intencionais. Por isso, geralmente é desencorajado, a menos que seja usado deliberadamente para melhorar a clareza do código.
Exemplo
#
Neste exemplo, a variável local message dentro
da função printMessage sombreia a variável message
de nível superior:
final message = 'Global';
void printMessage() {
final message = 'Local'; // Shadows the global `message` variable.
print(message); // Prints: Local
}
void main() {
printMessage();
print(message); // Prints: Global
}
O shadowing também pode ocorrer em blocos aninhados:
void main() {
final value = 10;
if (true) {
final value = 20; // Shadows the outer `value` variable.
print(value); // Prints: 20
}
print(value); // Prints: 10
}
Sound
Uma garantia do sistema de tipos de que o valor em tempo de execução de uma expressão sempre corresponde ao seu tipo estático.
Um sistema de tipos é sound (sólido) quando garante que um programa
nunca pode chegar a um estado em que uma expressão é avaliada como um valor
que não corresponde ao tipo estático da expressão.
Por exemplo, se o tipo estático de uma expressão é String,
o valor em tempo de execução é garantido como sendo uma String
quando avaliado.
O sistema de tipos do Dart é sólido. Ele impõe essa garantia por meio de uma combinação de verificação estática (erros de compilação) e verificações em tempo de execução:
-
Verificações estáticas pegam a maioria dos erros de tipo em tempo de compilação,
como atribuir uma
Stringa uma variável de tipoint. -
Verificações em tempo de execução tratam os casos que o compilador não consegue
verificar estaticamente, como casts com
ase argumentos de tipo genéricos covariantes.
A solidez traz vários benefícios práticos:
- Bugs relacionados a tipos aparecem em tempo de compilação. Um sistema de tipos sólido obriga o código a ser inequívoco sobre os seus tipos, então bugs de tipo que seriam difíceis de encontrar em tempo de execução são pegos cedo.
- Código mais legível. Você pode confiar que um valor realmente tem o tipo declarado. No Dart sólido, os tipos não mentem.
- Código mais fácil de manter. Quando você muda um trecho de código, o sistema de tipos sólido permite que as ferramentas do Dart avisem sobre outros trechos de código que quebraram.
- Melhor compilação ahead-of-time (AOT). Tipos sólidos ajudam o compilador a gerar código nativo menor e mais eficiente.
Solidez não significa que o Dart pega todos os bugs. Você ainda pode escrever código com erros de lógica, erros de off-by-one e outros problemas que o sistema de tipos não trata. Significa apenas que os próprios tipos são sempre confiáveis.
Documentos e recursos relacionados
Subclass
Uma classe que herda a implementação de outra classe.
Uma subclass (subclasse) é uma classe que herda a implementação de outra classe ao
usar a keyword extends, ou por
mixin application.
// A is a subclass of B; B is the superclass of A.
class A extends B {}
// B1 has the superclass `A with M`, which has the superclass A.
class B1 extends A with M {}
A relação de subclasse também implica uma relação de subtipo associada.
Por exemplo, class A define implicitamente um tipo associado
A
que as instâncias da classe A ocupam.
Assim, class A extends B declara não apenas que a classe
A é subclasse de B, mas também estabelece que o
tipo A é um
subtipo do tipo B.
As relações de subclasse são um subconjunto das relações de subtipo.
Quando a documentação diz "S deve ser um subtipo de T",
é aceitável que S seja uma subclasse de T.
No entanto, o inverso não é verdadeiro: nem todo subtipo é uma subclasse.
Documentos e recursos relacionados
Subtype
Um tipo que pode ser usado em qualquer lugar em que se espera um valor do seu supertipo.
A relação de subtype (subtipo) existe quando um valor de determinado tipo pode ser substituído
onde se espera o valor de outro tipo, o supertipo.
Por exemplo, se S é um subtipo de T,
então você pode substituir um valor do tipo S
onde se espera um valor do tipo T.
Um subtipo oferece todas as operações do seu supertipo (e possivelmente algumas operações extras). Na prática, isso significa que você pode atribuir o valor de um subtipo a qualquer local que espere o supertipo, e todos os métodos do supertipo estão disponíveis no subtipo.
Isso vale pelo menos estaticamente. Uma API específica pode não permitir a substituição em tempo de execução, dependendo das operações que realiza.
Algumas relações de subtipo se baseiam na estrutura do tipo,
como com tipos nullable (por exemplo, int é subtipo de int?)
e tipos de função
(por exemplo, String Function() é subtipo de void Function()).
Subtipos também podem ser introduzidos para classes por implementação ou herança (direta ou indireta):
// A is a subtype of B, but NOT a subclass of B.
class A implements B {}
// C is a subtype AND a subclass of D.
class C extends D {}
Documentos e recursos relacionados
Super parameter
Um parâmetro de construtor que passa automaticamente um argumento para o construtor da superclasse.
Um super parameter (super parâmetro) é um atalho de sintaxe que simplifica a passagem de parâmetros de um construtor de subclasse para um construtor de superclasse.
Em vez de declarar manualmente o parâmetro
e passá-lo na lista de inicialização,
você pode prefixar o nome do parâmetro com super..
Por exemplo, em Hammer({required super.price}),
o valor de price é passado
diretamente para o construtor da superclasse.
Documentos e recursos relacionados
Top type
Um tipo que é supertipo de todos os outros tipos,
incluindo Object?.
Um top type (tipo superior) é qualquer tipo que seja supertipo de Object?.
Como Object? é ele mesmo supertipo de todos os outros tipos do Dart,
um top type fica no topo da hierarquia de tipos,
então você pode atribuir qualquer valor a uma variável com top type.
O Dart tem vários top types, mas os principais são os três seguintes:
-
Object?- O supertipo nullable de todos os tipos. Todo valor em Dart, incluindonull, é umObject?. -
dynamic- Um tipo especial que desativa a verificação estática de tipos. Assim comoObject?, aceita qualquer valor, mas também permite acessar qualquer membro dele sem um erro de compilação. A verificação é adiada para o tempo de execução. -
void- Um tipo que indica que o valor não deve ser usado. Você pode atribuir qualquer valor avoid, mas não pode usar o resultado sem um cast.
Além desses três principais, há outros top types compostos.
FutureOr<T> é um top type sempre que T é um top type,
e adicionar ? a certos tipos também produz um top type.
Por exemplo, FutureOr<Object?>, FutureOr<Object>?
e dynamic? são todos top types.
Em contraste com Object?, o tipo Object non-nullable é
o supertipo de todos os tipos non-nullable, mas não é um top type verdadeiro
porque não é supertipo de Null.
O top type é o inverso do bottom type.
Enquanto um top type é supertipo de tudo,
o bottom type (Never no Dart) é subtipo de tudo.
Object? a = 42; // OK: int is a subtype of Object?.
Object? b = 'hello'; // OK: String is a subtype of Object?.
Object? c = null; // OK: Null is a subtype of Object?.
dynamic d = [1, 2, 3]; // OK: List<int> is a subtype of dynamic.
void e = true; // OK: bool is a subtype of void.
Transitive dependency
Uma dependência que um pacote usa indiretamente, porque uma das suas dependências a exige.
Uma transitive dependency (dependência transitiva) é uma dependência que um pacote usa indiretamente, porque uma das suas dependências, ou as dependências delas, a exige.
Se o seu pacote depende de A, que por sua vez depende de B, que depende de C, então A é uma dependência imediata e B e C são transitivas.
Documentos e recursos relacionados
Tree shaking
Uma otimização do compilador que remove código não utilizado.
Tree shaking (sacudida de árvore) é uma otimização do compilador que analisa quais partes do código são realmente usadas por uma aplicação e remove todo o resto da saída final.
Isso torna o programa compilado menor e mais rápido de carregar, já que código morto que nunca é referenciado não acaba no binário ou no bundle.
O tree shaking é especialmente importante para apps web e mobile, em que o tamanho do código impacta diretamente o tempo de download e o desempenho em tempo de execução.
Por exemplo, se você importar uma biblioteca que define dez funções de nível superior, mas seu app chama apenas duas, o tree shaking garante que as outras oito funções sejam excluídas da saída compilada.
Documentos e recursos relacionados
Type alias
Um nome definido pelo usuário para um tipo existente.
Um type alias (alias de tipo) é um nome alternativo que se refere a outro tipo.
Eles podem ser usados para simplificar definições de tipo complexas, melhorar a legibilidade ou criar significado semântico no código.
O Dart permite definir type aliases usando a keyword typedef.
Você pode criar aliases para funções, classes e até tipos genéricos.
Exemplos
#Alias de tipo de função
#typedef StringTransformer = String Function(String);
void printTransformed(String input, StringTransformer transformer) {
print(transformer(input));
}
void main() {
printTransformed('hello', (str) => str.toUpperCase()); // Output: HELLO
}
Alias de classe
#class HttpClient {}
typedef Client = HttpClient;
Client client = HttpClient();
Type aliases não criam novos tipos, apenas oferecem nomes alternativos.
Documentos e recursos relacionados
Uninitialized
Uma variável que foi declarada, mas ainda não recebeu um valor.
Uma variável está uninitialized (não inicializada) quando foi declarada, mas ainda não recebeu um valor.
Variáveis non-nullable precisam ser inicializadas antes de serem lidas, seja no momento da declaração, seja em todos os caminhos de execução possíveis antes do primeiro uso:
void f() {
int x;
print(x); // Error: variable 'x' must be assigned before it can be used.
}
Variáveis nullable que não são inicializadas explicitamente recebem null por padrão:
int? count; // Implicitly initialized to null.
print(count); // Prints: null
Para adiar a inicialização de uma variável non-nullable,
use a keyword late. Uma variável late fica não inicializada
até a primeira atribuição, e acessá-la antes de ser atribuída
lança um erro de inicialização late em tempo de execução:
late String name;
print(name); // Throws a late initialization error if not yet assigned.
Documentos e recursos relacionados
Variance and variance positions
Como a mudança de um argumento de tipo afeta a relação entre o tipo original e o resultante.
No Dart, mudar o argumento de tipo de uma declaração de tipo (como uma classe) ou o tipo de retorno de uma função muda a relação de tipo geral na mesma direção (covariante).
Já mudar os tipos dos parâmetros de uma função muda a relação de tipo geral na direção oposta (contravariante).
Um parâmetro de tipo de uma classe (ou de outra declaração de tipo, como um mixin) é dito covariante quando o tipo como um todo "covaria" com o argumento de tipo real. Em outras palavras, se o argumento de tipo for substituído por um subtipo, então o tipo como um todo também é um subtipo.
Por exemplo, o parâmetro de tipo da classe List é covariante porque
os tipos de lista covariam com o argumento de tipo: List<int>
é um subtipo de
List<Object> porque int é um subtipo de Object.
No Dart, todos os parâmetros de tipo de todas as declarações de class, mixin, mixin class e enum são covariantes.
No entanto, os tipos de função são diferentes:
um tipo de função é covariante no seu tipo de retorno, mas
o oposto (conhecido como contravariante) nos seus tipos de parâmetro.
Por exemplo, o tipo int Function(int) é um
subtipo do tipo Object Function(int), mas é um supertipo de int Function(Object).
Isso faz sentido se você considerar a sua substituibilidade.
Se você chamar uma função com tipo estático int Function(int),
essa função pode na verdade ser do tipo int Function(Object) em tempo de execução.
Com base no tipo estático, você espera poder passar um int para ela.
Isso funciona, já que a função na verdade aceita qualquer Object,
e isso inclui todo objeto do tipo int.
Da mesma forma, o resultado retornado será do tipo int,
o que também é o esperado com base no tipo estático.
Logo, int Function(Object) é um subtipo de int Function(int).
Observe que tudo se inverte para os tipos de parâmetro.
Em particular, essa relação de subtipo entre tipos de função exige que
a relação de subtipo oposta exista para o tipo do parâmetro.
Por exemplo, void Function(Object) é um subtipo de void Function(int)
porque int é um subtipo de Object.
Com um tipo mais complexo, como List<void Function(int)>,
você precisa considerar as posições no tipo.
Para isso, transforme uma das partes do tipo em um placeholder,
e depois considere o que acontece com o tipo quando
diferentes tipos são colocados nessa posição.
Por exemplo, considere List<void Function(_)> como um modelo para
um tipo em que você pode colocar diferentes tipos no lugar do placeholder
_.
Esse tipo é contravariante na posição em que esse placeholder aparece.
O exemplo a seguir ilustra isso substituindo _ por Object e por int.
List<void Function(Object)> é um subtipo de List<void Function(int)>
porque void Function(Object) é um subtipo de void Function(int), já que
void é um subtipo de void (os tipos de retorno) e
int é um subtipo de Object (os tipos de parâmetro, na ordem inversa).
Logo, o tipo em _ varia na direção oposta à do
tipo List<void Function(_)> como um todo, e essa
"direção oposta" por definição faz dela uma posição contravariante.
Uma posição covariante é definida de forma semelhante.
Por exemplo, _ está em posição covariante no tipo List<_>,
e _ também está em posição covariante no tipo _ Function(int).
Existe ainda outro tipo de posição, chamada invariante, mas ela aparece com muito menos frequência, então os detalhes são omitidos aqui.
Na prática, geralmente basta saber que os argumentos de tipo de uma classe, mixin etc. estão em posição covariante, assim como o tipo de retorno de um tipo de função, mas os tipos dos parâmetros estão em posição contravariante.
Documentos e recursos relacionados
Verified publisher
Um publicador de pacotes no site pub.dev cuja identidade foi verificada pelo pub.dev.
Um verified publisher (publicador verificado) é um conjunto de um ou mais usuários identificados por um nome de domínio único. A propriedade do nome de domínio é verificada pelo pub.dev, como no caso do publicador dart.dev no pub.dev, mantido pela equipe do Dart.
Documentos e recursos relacionados
Version constraint
Uma restrição associada a cada dependência que especifica com quais versões um pacote deve funcionar.
Uma version constraint (restrição de versão) é um intervalo especificado de versões compatíveis
de uma dependência para um pacote.
Pode ser uma única versão (0.3.0) ou um intervalo de versões (^1.2.1).
Embora any também seja permitido, por motivos de desempenho não é recomendado.
Pacotes de biblioteca devem sempre especificar version constraints para cada uma de suas dependências que não são de desenvolvimento. Application packages, por outro lado, podem aceitar qualquer versão de suas dependências, já que usam o lockfile para gerenciar as versões das dependências.
Documentos e recursos relacionados
WebAssembly (Wasm)
Um formato de instruções binárias que permite a execução de alto desempenho de código em navegadores web.
WebAssembly (normalmente abreviado para Wasm) é um formato binário portável projetado como alvo de compilação para linguagens de programação, permitindo velocidades de execução próximas às nativas na web.
O Dart permite compilar código diretamente para WebAssembly (usando a
ferramenta dart compile wasm). Compilar Dart para Wasm pode ser especialmente
vantajoso para apps Flutter web, melhorando a taxa de quadros, os tempos de inicialização
e o tamanho da aplicação em comparação com a compilação padrão para JavaScript.
Documentos e recursos relacionados
Wildcard
Um símbolo (_) usado no lugar de um nome de variável para
indicar um valor não utilizado em padrões e outros contextos.
Um wildcard (curinga) é o caractere de underscore (_) usado para
ignorar valores ou indicar que um valor é intencionalmente não utilizado.
Ele é frequentemente usado em padrões, desestruturação e expressões switch para
casar com qualquer valor sem vinculá-lo a um nome.
Wildcards ajudam a tornar o código mais intencional, deixando claro quais valores não são necessários em um contexto específico.
Exemplo:
// Ignoring the value in a for-each loop.
var names = ['Alice', 'Bob', 'Charlie'];
for (var _ in names) {
print('Someone is here!');
}
O padrão wildcard é especialmente útil quando:
- Você só precisa de certas partes de um valor desestruturado.
- Você quer mostrar explicitamente que alguns valores estão sendo ignorados.
- Você precisa de um caso genérico no pattern matching.
Documentos e recursos relacionados
Zone
Um mecanismo para personalizar o comportamento de código assíncrono sem modificar o próprio código assíncrono.
Uma zone (zona) é um contexto de execução que permite rodar código com comportamento personalizado para eventos assíncronos, como timers, microtasks e erros não capturados.
Zones são úteis para:
- Logging
- Rastreamento de erros
- Manter estado específico de requisição entre lacunas assíncronas (por exemplo, em apps de servidor)
- Testar e depurar comportamento assíncrono
Zones oferecem uma forma de rastrear e influenciar a execução assíncrona sem exigir que o código assíncrono tenha consciência disso.
Você pode criar uma nova zone usando runZoned (ou runZonedGuarded)
e sobrescrever comportamentos específicos da zone, como tratamento de erros e timers.
Até mesmo o print pode ser sobrescrito, embora ele não seja assíncrono e esteja
incluído apenas por conveniência.
Exemplo:
import 'dart:async';
void main() {
runZonedGuarded(() {
Future.delayed(Duration(seconds: 1), () {
throw 'Zone caught this error!';
});
}, (error, stackTrace) {
print('Caught error: $error');
});
}
No exemplo anterior, o erro não capturado dentro do callback assíncrono é interceptado pela zone personalizada.
Documentos e recursos relacionados
Salvo indicação em contrário, a documentação neste site reflete Dart 3.13.7. 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ê.