🧮 Declaración e inicialización de variables. Inferencia de tipos #
En Dart, para declarar unha variable podes:
- Usar
var
(Dart infire o tipo automaticamente) - Indicar directamente o tipo (
String
,int
, etc.) - Usar tipos máis xerais como
Object
oudynamic
, se necesitas máis flexibilidade
✅ Exemplo básico con inferencia de tipos #
var nome = 'Diego';
Neste caso:
- Usamos
var
- Dart infire que
nome
é de tipoString
, porque o valor inicial é'Diego'
- A partir dese momento,
nome
só poderá almacenar cadeas (String
)
nome = 'Uxía'; // ✅ correcto
nome = 10; // ❌ erro: non é unha String
✅ Declaración explícita do tipo #
String nome = 'Diego';
Funciona igual que co var
, pero o tipo está especificado claramente, o que mellora a lectura e o mantemento do código.
✅ Uso de Object
#
Object dato = 'Diego';
Object
é o pai de tódolos obxectos en Dart.- Isto significa que pode almacenar calquera valor que sexa un obxecto:
int
,String
,bool
,List
, etc.
dato = 42; // ✅ permitido
dato = true; // ✅ permitido
dato = ['a', 'b']; // ✅ permitido
✅ Uso de dynamic
#
dynamic
permite cambiar o tipo da variable en calquera momento.- Dart non comproba o tipo en tempo de compilación, polo hai que ter coidado xa que é posible facer cousas que poidan fallar en tempo de execución.
dynamic valor = 'Diego';
valor = 123;
valor = true;
valor = [1, 2, 3];
print(valor.nonExiste()); // ❌ Isto compilará, pero fallará ao executarse
🧠 Comparativa: var
, Object
, dynamic
#
Declaración | Pode cambiar de tipo? | Acceso a métodos? | Seguridade de tipos |
---|---|---|---|
var nome = 'Ana' | ❌ Non | ✅ Si (de String ) | ✅ Alta |
String nome = ... | ❌ Non | ✅ Si | ✅ Alta |
Object nome = ... | ✅ Si (pero restrinxido) | ❌ Precisa casting | ⚠️ Media |
dynamic nome = ... | ✅ Si (totalmente) | ✅ Sen restricións | ❌ Baixa |
✅ Recomendacións xerais #
- Usa
var
cando o tipo é obvio e non cambiará. - Usa o tipo explícito (
String
,int
, etc.) cando queiras claridade. - Usa
Object
se necesitas flexibilidade pero queres algo de seguridade. - Usa
dynamic
só se realmente necesitas cambiar tipos, ou estás traballando con código moi xenérico.
🧪 Exemplo completo #
void main() {
var nome = 'Ana'; // infírese como String
String apelido = 'López'; // tipo especificado
Object idade = 30; // pode ser calquera obxecto
dynamic calquera = true; // pode ser calquera cousa
print(nome.toUpperCase()); // ✅
// print(idade.toUpperCase()); // ❌ erro
print((idade as int).isEven); // ✅ usando casting
print(calquera); // ✅
}
✅ Opcionais #
Dart implementa unha xestión fiable de valores nulos (sound null safety), o que significa que os erros por acceso a un null
son detectados en tempo de compilación.
Para facer un tipo de dato opcional, engade ?
ao tipo para permitir que sexa null
ou que teña calquera valor do tipo:
String? apelido = null; // Variable opcional (pode conter null ou un String)
apelido = "Rodicio"; // Reasígnase un valor de tipo String
🧭 Valor por defecto #
En Dart, todas as variables opcionais teñen por defecto o valor null
, a non ser que se inicialicen explicitamente.
Mesmo tipos como int
, double
, bool
ou String
poden ser null
, pero só se se declaran como opcionais, porque Dart emprega o sistema de null safety (seguridade contra nulos) e todo é un obxecto, mesmo os números.
Así, por exemplo:
int? idade;
print(idade); // imprime: null
Neste caso:
- Declaramos unha variable
idade
de tipoint?
, é dicir, un enteiro que pode ser nulo. - Como non lle damos ningún valor, Dart lle asigna automaticamente
null
.
📌 Nota:
- A non ser que sexa un tipo opcional, non podemos asignar
null
directamente.- Así, por exemplo, se facemos
int numero = null;
daría un erro en tempo de compilación:
int numero = null; // ❌ Erro: non se pode asignar null a un tipo non opcional
Se queremos declarar unha variable non opcional sen inicializala de inmediato, podemos usar late
:
late int numero;
numero = 42; // ✅ Permitido
🚫 Tipos non opcionais #
Se declaras unha variable non opcional (por defecto), Dart obrígache a inicializala antes de usala. Se non o fas, dará erro en tempo de compilación.
int contador;
print(contador); // ❌ Erro: a variable non foi inicializada
✅ Solución:
int contador = 0;
print(contador); // 0
✅ Asignación condicional #
A seguinte estrutura é válida porque Dart asegura que a variable será inicializada en todos os casos posibles antes de usarse:
int lineas;
if (modoResumo) {
lineas = 10;
} else {
lineas = 0;
}
print(lineas); // ✅ Correcto, Dart sabe que sempre se inicializa
🧠 Resumo #
Declaración | Inicialización obrigatoria? | Valor por defecto |
---|---|---|
int contador; | ✅ Si | ❌ Erro se non se inicializa |
int? contador; | ❌ Non | ✅ null |
var nome = 'Ana' | ✅ Si (inferencia) | — |
✅ Recomendación #
- Se non sabes o valor inicial, usa tipos opcionais (
int?
,String?
…) ou inicializa con valores por defecto (= 0
,= ''
, etc.). - Usa
late
se garantes que a variable se inicializará antes de usarse (ver seguinte punto).
🕓 Variables late
#
O modificador late
permite:
- Declarar variables non opcionais que se inicializan máis tarde.
- Inicializar variables só cando se usan por primeira vez.
/*
• Declárase unha variable descrición de tipo String, que non é opcional.
• Como non se lle dá valor nese momento, Dart esixiría un erro… a non ser que uses late.
• late di: “Confía en min, prometo que lle darei un valor antes de usala”.
*/
late String descricion;
void main() {
descricion = 'Almendrados!';
print(descricion);
/*
• A variable recibe un valor antes de usarse, así que non hai erro.
• Se intentas usala sen inicializar, Dart lanzaría un erro en tempo de execución.
*/
}
late String temperatura = lerTermometro(); // execútase só se se usa
/*
• Aquí tamén se usa late, pero con inicialización directa.
• Isto significa que a función lerTermómetro() non se executará ata que alguén use a variable temperatura por primeira vez.
• É unha forma de facer inicialización “vaga” (lazy initialization), útil cando:
• A operación é custosa (ex: ler dun sensor ou disco).
• Pode que nunca se necesite ese valor.
*/
⚠️ Se accedes a unha variable
late
sen inicializala, Dart lanza un erro en tempo de execución.
🔐 final
e const
#
Se non pensas modificar o valor dunha variable, usa final
ou const
.
final
: #
Unha variable final
pode obter o seu valor en tempo de execución, pero non pode cambiar despois de asignarse.
final data = DateTime.now(); // valor calculado no momento
print(data); // correcto
data = DateTime.utc(2024); // ❌ Erro: non se pode reasignar
Tamén se pode usar con tipo explícito:
final String nome = 'Diego';
const
: #
Unha variable const
debe conter un valor coñecido en tempo de compilación.
const pi = 3.1416;
const String saudo = 'Ola mundo';
const lista = [1, 2, 3]; // lista inmutable
Se usas const
con obxectos complexos, son completamente inmutables:
const usuario = {'nome': 'Ana', 'idade': 30};
// usuario['idade'] = 31; // ❌ Erro: os campos dun const non poden cambiar
📌 Comparativa rápida #
Característica | final | const |
---|---|---|
Reasignación | ❌ Non | ❌ Non |
Valor fixo necesario | ✅ Si (unha vez) | ✅ Si (en tempo de compilación) |
Pode calcularse | ✅ Si (ex. DateTime.now() ) | ❌ Non (só valores coñecidos) |
Obxecto mutable | ✅ Si (o obxecto si pode cambiar) | ❌ Non (todo o obxecto é inmutable) |
📌
const
require que o valor sexa coñecido en tempo de compilación.📌
final
permite valores calculados en execución, pero que non poden cambiar despois.
❔ Variables comodín (_
) #
Dende Dart 3.7, podes usar o carácter subliñado _
para declarar variables locais non vinculantes (wildcards), que se ignoran. Vexamos tres exemplos de uso:
/*
• Aquí créanse dúas variables locais chamadas _, que conteñen valores.
• A pesar de ter o mesmo nome, Dart permíteo porque _ é tratado como non vinculante.
• É útil cando só precisas executar unha expresión ou inicializar algo, pero non necesitas acceder ao valor despois.
*/
var _ = 1;
int _ = 2;
/*
• Este bucle percorre lista, pero como non necesitas o valor de cada elemento, usas _ como comodín.
• Exemplo típico cando só che interesa repetir unha acción n veces, sen importar o contido.
*/
for (var _ in lista) {}
/*
Aquí usas _ como parámetro do catch, porque non necesitas o obxecto da excepción, só queres xestionar o erro.
• Equivalente a dicir: “non me importa que tipo de erro foi, só quero reaccionar”.
*/
try {
throw 'erro!';
} catch (_) {
print('Oops!');
}
💡 Consello: usa
_
para variables temporais que non precises empregar. Dart admite múltiples_
no mesmo ámbito sen erros de colisión.