Construtores primários
Crie classes de forma concisa declarando parâmetros e campos no cabeçalho da classe.
Visão geral
#Construtores primários oferecem uma forma concisa de declarar os campos de uma classe e seu construtor principal em uma única linha. Eles reduzem o boilerplate de declarar campos, receber parâmetros e atribuí-los no corpo do construtor. Essa forma abreviada muda como você escreve a declaração, mas não muda o comportamento em tempo de execução.
Antes e depois
#Considere esta classe tradicional com dois campos e um construtor:
// Current syntax.
class Point {
int x;
int y;
Point(this.x, this.y);
}
Usar um construtor primário torna a mesma classe muito mais concisa:
// Using a primary constructor.
class Point(var int x, var int y);
Declarar um parâmetro no construtor primário com var ou final
induz implicitamente uma variável de instância para esse parâmetro.
Quaisquer outros construtores declarados dentro do corpo da classe são chamados de construtores no corpo (in-body constructors).
Para garantir que o construtor primário seja executado em toda nova instância, uma classe, mixin class ou enum com construtor primário não pode ter nenhum outro construtor generativo no corpo que não seja de redirecionamento.
Declarações de campo em parâmetros
#
Parâmetros em construtores primários com o modificador var ou final,
chamados de parâmetros declarantes, induzem implicitamente um campo.
Se você omitir o modificador, o parâmetro não cria um campo. Ele se comporta exatamente como um parâmetro em um construtor tradicional.
// Declares both fields x and y.
class Point(var int x, var int y);
// Doesn't declare a field.
class User(String name);
Para extension types, o construtor primário deve ter exatamente um parâmetro. Esse parâmetro é sempre um parâmetro declarante, mesmo que você omita o modificador.
Mixin classes só podem ter um construtor primário sem parâmetros, corpo ou lista de inicializadores.
Escopos de construtor primário
#Quando você usa um construtor primário, os parâmetros que você declara no cabeçalho da classe ficam disponíveis em diferentes partes da declaração da classe. O Dart gerencia a visibilidade deles usando dois escopos distintos:
-
Escopo de inicializador primário:
Aplica-se aos inicializadores de campos não-late no corpo da classe e
à lista de inicializadores do construtor primário (após
this :). Nesse escopo, um nome de parâmetro comoxse refere diretamente ao parâmetro do construtor. -
Escopo de parâmetro primário:
Aplica-se ao bloco do corpo do construtor primário (dentro de
{ ... }). Nesse escopo, o nome de um parâmetro declarante se refere à variável de instância induzida (campo), enquanto o nome de um parâmetro não declarante ainda se refere ao parâmetro do construtor.
O escopo de inicializador primário torna os parâmetros do cabeçalho diretamente disponíveis para inicializar campos não-late, o que elimina a necessidade de uma lista de inicializadores separada. Funciona exatamente como se você estivesse inicializando variáveis na lista de inicializadores de um construtor tradicional:
class DeltaPoint(final int x, int delta) {
// Accesses 'x' and 'delta' parameters directly!
final int y = x + delta;
}
O escopo de parâmetro primário garante que
quaisquer atualizações nas variáveis de instância sejam
refletidas corretamente no corpo do construtor,
enquanto os inicializadores continuam tendo acesso aos parâmetros originais.
O exemplo a seguir mostra como o
mesmo nome x é resolvido de forma diferente em cada escopo:
class ScopingDemo(var String x, String suffix) {
// In a non-late field initializer, 'x' refers to the parameter 'x'.
final String fieldAtDeclaration = x;
final String fieldInInitializer;
// In the initializer list, 'x' refers to the parameter 'x'.
this : fieldInInitializer = x {
// Inside the body, 'x' refers to the induced instance variable,
// so assigning to it updates the field.
x = x.toUpperCase();
// 'suffix' induces no field, so it still refers to the parameter.
print('$x$suffix');
}
}
Esse comportamento consistente torna a refatoração entre construtores tradicionais e primários mais simples e segura.
Adicionar corpos de construtor
#
Para validar entradas ou realizar inicializações complexas,
você pode adicionar um corpo ao construtor primário dentro da definição da classe.
Esse corpo usa a keyword this seguida de um bloco:
class Point(var int x, var int y) {
this : assert(x >= 0 && y >= 0) {
print('Point initialized at ($x, $y)');
}
}
O bloco pode especificar uma lista de inicializadores após this e/ou um corpo de função.
Para fornecer apenas uma lista de inicializadores,
termine-a com um ponto e vírgula, como em this : assert(x >= 0);.
Você também pode anotar o bloco com metadados,
como em @metadata this;.
Inicializar campos privados
#Para inicializar um campo privado usando um parâmetro nomeado, em um construtor tradicional você precisa escrever a atribuição manual como boilerplate:
// Variant not using a private named parameter.
class User({required String name}) {
String _name = name;
}
Com construtores primários e o recurso de parâmetros nomeados privados, você pode declarar o campo privado diretamente no cabeçalho do construtor. Quando você usa um nome privado (com underscore inicial) para um parâmetro nomeado, o compilador torna o nome do parâmetro público para quem chama, removendo o underscore:
// Variant using a private named parameter.
class User({required var String _name});
Nos dois casos, quem chama usa o nome público name
no ponto de chamada: User(name: 'John Doe').
Corpos vazios
#
O corpo vazio de uma classe, mixin class, extension ou extension type ({})
pode ser substituído por um ponto e vírgula (;).
Isso vale em geral para essas declarações,
mas é especialmente útil quando se usa um construtor primário para
manter toda a declaração em uma única linha.
class Point(var int x, var int y);
Construtores primários constantes
#
Assim como os construtores tradicionais,
um construtor primário pode ser constante
se a classe e seus campos permitirem.
Para declarar um construtor primário constante,
coloque o modificador const antes do nome da classe no cabeçalho:
class const ConstPoint(final int x, final int y) {
final int z;
// A constant primary constructor can have an initializer list,
// but can't have a body block.
this : z = x + y;
}
Construtores primários constantes têm estas restrições importantes:
-
Sem bloco de corpo:
Ter um corpo
{ ... }é um erro em tempo de compilação, mesmo que esteja vazio. Um construtor primário constante só pode usar uma lista de inicializadores seguida de um ponto e vírgula. -
Campos final definitivamente inicializados:
Assim como em qualquer classe com construtor generativo const,
toda variável de instância deve ser
final, não pode serlatee deve ser definitivamente inicializada por um parâmetro declarante, um inicializador de campo ou a lista de inicializadores do construtor primário. - Inicializadores potencialmente constantesPotentially constantUma 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. Saiba mais: As expressões de inicialização de cada variável de instância devem ser potencialmente constantes. Isso inclui inicializadores de campo e expressões na lista de inicializadores do construtor primário.
Construtores primários nomeados
#
Você também pode declarar um construtor primário como um
construtor nomeado, acrescentando um ponto (.) e
um nome após o nome da classe no cabeçalho:
// A named primary constructor.
class Point.custom(var int x, var int y);
Um padrão comum é definir um
construtor primário privado (como Point._) que
restringe a instanciação direta e
obriga quem chama a usar métodos factory ou outros construtores:
// A private named primary constructor.
class Point._(var int x, var int y);
Super parameters
#Super parameters funcionam exatamente como em construtores tradicionais, permitindo repassar parâmetros para o construtor da superclasse:
class Person(final String name, final int age);
class Employee(super.name, super.age, final String role) extends Person;
Isso reduz o boilerplate em estruturas de classes hierárquicas, eliminando a necessidade de escrever manualmente listas de inicializadores ou duplicar declarações de parâmetros.
Construtores primários em enums
#Você pode usar construtores primários para declarar enums aprimorados de forma muito mais concisa.
Ao usar um construtor primário, você pode definir os campos do enum e seu construtor em uma única linha, eliminando o boilerplate habitual de declarar campos, parâmetros e inicializá-los:
enum Color(final String hex) {
red('#FF0000'),
green('#00FF00'),
blue('#0000FF'),
}
Construtores primários em enums são implicitamente constantes.
Embora você possa opcionalmente escrever o modificador const antes do nome do enum
(como em enum const Color), isso é redundante e pode ser omitido.
Restrições e mudanças que quebram compatibilidade
#Tenha em mente estas restrições e possíveis erros ao usar construtores primários:
-
Parâmetros declarantes não podem ser
lateouexternal: Os modificadoreslateeexternalnão são permitidos em parâmetros no cabeçalho do construtor primário. Para usar esses modificadores, declare os campos no corpo da classe, como de costume. - Colisões de nome: Declarar um parâmetro no construtor primário com o mesmo nome de um método ou de outro campo no corpo da classe resulta em um erro em tempo de compilação.
-
Sem atribuições a parâmetros do construtor primário:
Parâmetros do construtor primário são somente leitura
dentro do escopo de inicializador primário.
Atribuir a eles (como com
x = 5oux++) em um inicializador de campo ou na lista de inicializadores do construtor primário é um erro em tempo de compilação. - Dupla inicialização: Você não pode inicializar uma variável de instância tanto em sua declaração quanto na lista de inicializadores do construtor primário (ou como parâmetro formal de inicialização), mesmo que o campo seja mutável. Fazer isso resulta em erro em tempo de compilação.
-
Restrições da parte de corpo:
- Uma parte de corpo do construtor primário (o bloco
this) não pode usar os modificadoresasync,async*ousync*, e não pode usar a sintaxe de corpo com seta (=>). - Você não pode escrever um bloco
thisse o cabeçalho da classe não declarar um construtor primário. - Uma classe pode ter no máximo uma parte de corpo de construtor primário.
- Uma parte de corpo do construtor primário (o bloco
- Construtores primários de mixin class devem ser triviais: Uma mixin class só pode declarar um construtor primário se não tiver parâmetros, lista de inicializadores nem corpo.
-
Parâmetros covariant:
Você só pode usar o modificador
covariantem um parâmetro de construtor primário se ele for um parâmetro declarante mutável (usa o modificadorvar). -
Caso especial do método
factory: Se você tiver um método chamadofactorysem tipo de retorno (por exemplo,factory() {}), o compilador o interpreta como um construtor factory conciso. Garanta que esses métodos tenham um tipo de retorno explícito (por exemplo,void factory() {}) para evitar esse conflito.
Restrições de modificadores de parâmetro
#
Os modificadores de parâmetro final e var são reservados exclusivamente para
parâmetros declarantes em construtores primários.
Usar final ou var em parâmetros formais de qualquer outra declaração
(como funções de nível superior, métodos, closures e construtores no corpo)
produz um erro em tempo de compilação (extraneous_modifier).
// Valid: Primary constructor declaring parameter.
class Point(final int x, final int y);
// Compile-time error (extraneous_modifier):
void printValue(final int x) => print(x);
Para corrigir esse erro, remova o modificador ou execute dart fix.
Para impor parâmetros imutáveis como escolha de estilo,
use a regra de lint parameter_assignments.
Se você estiver usando uma versão da linguagem 3.12 ou anterior,
pode habilitar as regras de lint avoid_final_parameters
e
var_with_no_type_annotation
para encontrar e
remover esses modificadores proativamente, antes de atualizar para o Dart 3.13.
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ê.