Skip to main content


Introdução ao Dart


O Dart é uma linguagem de programação criada para desenvolver aplicações modernas. Ela é muito usada com Flutter, mas Dart não é Flutter. Dart é a linguagem e Flutter é um framework que usa Dart para criar interfaces gráficas, principalmente aplicativos mobile, web e desktop.


Você pode usar Dart para criar:

  • Aplicações de linha de comando
  • Aplicações web
  • APIs
  • Aplicativos com Flutter
  • Ferramentas internas e scripts


Para que Dart é usado


O Dart resolve principalmente o problema de escrever aplicações multiplataforma com uma linguagem só, um exemplo prático seria:

void main() {
print('Sistema de cadastro iniciado');
}

Esse código pode ser usado em um programa simples de terminal. Mas com o Flutter, a mesma linguagem Dart também pode ser usada para criar telas, botões, formulários e aplicativos completos.



Dart não é Java


Apesar do Dart poder parecer um pouco com Java, C# ou JavaScript em alguns pontos, ele tem suas próprias regras.


Um exemplo de código Dart seria:

String nome = 'fulano';
int idade = 27;

print(nome);
print(idade);

Explicação:

  • String nome = 'fulano';
    Cria uma variável chamada nome que armazena texto.

  • int idade = 27;
    Cria uma variável chamada idade que armazena um número inteiro.

  • print(nome);
    Mostra o valor da variável nome na tela.

  • print(idade);
    Mostra o valor da variável idade na tela.


Em Dart, o tipo da variável vem antes do nome da variável, parecido com Java e C#.



Como Dart é executado


O Dart pode ser executado de duas formas principais. Durante o desenvolvimento, normalmente se usa:

dart run

Nesse modo, o código roda na Dart VM usando JIT (que significa Just-in-Time). O código é compilado enquanto roda. Isso ajuda durante o desenvolvimento porque facilita testes rápidos e depuração. Para gerar um executável, você pode usar:

dart compile exe bin/meu_app.dart

# Para compilar explicitamente para Linux, use --target-os=linux:
dart compile exe bin/cli.dart \
--target-os=linux \
--target-arch=x64 \
-o cli

Nesse caso, Dart gera um executável nativo. Esse processo usa AOT (que significa Ahead-of-Time). O código é compilado antes da execução, gerando um binário para produção.


Binário executável

Quando uma aplicação Dart é compilada como binário executável, o servidor não precisa ter o Dart instalado. O comando dart compile exe gera um executável autônomo para o sistema de destino. Esse arquivo já inclui o código nativo da aplicação, as dependências usadas pelo projeto e uma pequena parte do runtime do Dart necessária para executar o programa.


Existe apenas um cuidado importante. O binário precisa ser compatível com o sistema onde será executado. Por exemplo, um binário gerado para Linux x64 deve ser executado em um servidor Linux x64. Não basta compilar no Windows e copiar o arquivo para um servidor Linux esperando que ele funcione diretamente. O binário precisa ser gerado para o sistema operacional e para a arquitetura corretos.



Ferramentas básicas


O comando dart é a interface principal do SDK. Com ele você cria projetos, executa programas, analisa código, testa e compila aplicações.



Instalando no Linux Ubuntu/Debian


No Ubuntu ou Debian, a documentação oficial recomenda instalar pelo gerenciador de pacotes.

sudo apt-get update
sudo apt-get install apt-transport-https

Adicione a chave GPG:

wget -qO- https://dl-ssl.google.com/linux/linux_signing_key.pub \
| sudo gpg --dearmor -o /usr/share/keyrings/dart.gpg

Adicione o repositório:

echo 'deb [signed-by=/usr/share/keyrings/dart.gpg arch=amd64] https://storage.googleapis.com/download.dartlang.org/linux/debian stable main' \
| sudo tee /etc/apt/sources.list.d/dart_stable.list

Instale o Dart:

sudo apt-get update
sudo apt-get install dart

Verifique a instalação:

dart --version


Criando um projeto Dart


Depois de instalar, você pode criar um projeto de console:

dart create -t console meu_app

Entre no diretório:

cd meu_app

Execute:

dart run
  • dart create
    Cria um novo projeto Dart.

  • -t console
    Define que o projeto será uma aplicação de terminal.

  • meu_app
    É o nome da pasta do projeto.

  • dart run
    Executa o projeto.



Estrutura inicial de um projeto


Um projeto Dart simples costuma ter uma estrutura parecida com esta:

meu_app/
├── bin/
│ └── meu_app.dart
├── pubspec.yaml
└── README.md
  • bin/
    Guarda o arquivo principal de execução da aplicação.

  • meu_app.dart
    Arquivo Dart principal do projeto.

  • pubspec.yaml
    Arquivo de configuração do projeto. Nele ficam nome, versão e dependências.

  • README.md
    Arquivo de documentação do projeto.



Erros comuns de iniciantes


Esquecer o ponto e vírgula. Em Dart, a maioria das instruções termina com ;.

# Errado:
print('Olá')

# Correto:
print('Olá');


Variáveis e tipos de dados


Uma variável é um nome usado para guardar um valor na memória, exemplo:

void main() {
String usuario = 'Fulano';
int idade = 27;

print(usuario);
print(idade);
}

Saída:

Fulano
27

O trecho abaixo cria uma variável chamada usuario. Esse variável é do tipo String, que é usado para armazenar texto.

String usuario = 'Fulano';

O trecho abaixo cria uma variável chamada idade. Esse variável é do tipo int, que é usado para armazenar números inteiros.

int idade = 27;

Em Dart, toda variável aponta para um objeto, e os tipos principais incluem int, double, String, bool, List, Set, Map e Null. A tabela abaixo mostra as diferenças entre os tipos:


TipoUsoExemplo
StringUsado para armazenar texto. Pode ser um nome, email, mensagem, endereço IP ou qualquer valor textual.String nome = 'Fulano';
intUsado para armazenar números inteiros, sem casas decimais.int idade = 27;
doubleUsado para armazenar números com casas decimais.double preco = 19.90;
numUsado quando o valor pode ser inteiro ou decimal. É um tipo mais genérico para números.num valor = 10.5;
boolUsado para armazenar verdadeiro ou falso. Muito usado em condições.bool ativo = true;
ListUsado para armazenar vários valores em ordem. É parecido com um array em outras linguagens.List<String> usuarios = ['Ana', 'Bruno'];
MapUsado para armazenar dados no formato chave e valor. É parecido com dicionário em Python ou objeto em JavaScript.Map<String, String> usuario = {'nome': 'Ana'};
SetUsado para armazenar vários valores sem repetição.Set<String> permissoes = {'read', 'write'};
String?Usado quando uma variável de texto também pode não ter valor, ou seja, pode ser null.String? telefone = null;

O tipo List em Dart apesar de parecer com array em outras linguagens, segue a mesma premissa da Lista em Python. No entanto, a lista em Python aceita qualquer tipo por padrão, mas em Dart, você precisa definir o tipo dos itens.


Map com valores misturados

Na maioria dos casos, o Map vai receber chave sendo string e valores também sendo string ou int. Nesse caso, temos duas opções principais.


Usar Map<String, Object>. Quando as chaves são String, mas os valores podem ser de tipos diferentes, devemos usar Object.


Por enquanto vou deixar apenas essa opção.


Criando variáveis com tipo explícito


A forma mais clara de criar uma variável é informando o tipo.

void main() {
String nome = 'Ana';
int quantidade = 3;
double preco = 19.90;
bool ativo = true;

print(nome);
print(quantidade);
print(preco);
print(ativo);
}


Criando variáveis com var


No Dart também é possível usar var. Isso informa ao Dart que ele deve descobrir o tipo da variável pelo valor dela.

void main() {
var produto = 'Teclado';
var quantidade = 2;
var preco = 150.50;

print(produto);
print(quantidade);
print(preco);
}

Nesse caso, ficaria assim:

CódigoTipo entendido pelo Dart
var produto = 'Teclado';String
var quantidade = 2;int
var preco = 150.50;double

Depois que o tipo é definido, ele não muda.



var não é igual a dynamic


O var deixa Dart descobrir o tipo da variável sozinho, já o dynamic desativa boa parte da checagem de tipo. Exemplo com var:

void main() {
var servidor = 'dns01';

servidor = 'dns02';
print(servidor);
}

Isso funciona, porque o valor continua sendo String. Vejamos com dynamic:

void main() {
dynamic valor = 'Servidor';

valor = 10;
valor = true;

print(valor);
}

Isso funciona, mas pode deixar o código mais perigoso. Dart permite dynamic, mas a própria documentação recomenda usar Object ou Object? quando a intenção for aceitar valores de tipos diferentes, porque dynamic reduz a checagem estática.



Criando variáveis com late


O late é usado quando uma variável ou atributo não recebe valor imediatamente, mas será inicializado depois, antes de ser usado. Em Dart, variáveis não nulas precisam receber valor antes de serem usadas. Quando usamos late, estamos dizendo ao Dart: essa variável não será inicializada agora, mas será preenchida antes do uso".


Um exemplo simples:

class Configuracao {
late String caminhoArquivo;

void carregar() {
caminhoArquivo = '/etc/app/config.yml';
}

void exibir() {
print(caminhoArquivo);
}
}

void main() {
Configuracao config = Configuracao();

config.carregar();
config.exibir();
}

Nesse exemplo, o atributo caminhoArquivo não recebe valor no momento em que o objeto é criado. Ele só recebe valor depois, dentro do método carregar.


Depois disso, o método exibir pode usar o valor normalmente:

print(caminhoArquivo);

Mas é preciso tomar cuidado. Se uma variável late for usada antes de receber valor, o programa dará erro em tempo de execução. Exemplo ruim:

void main() {
late String nome;

print(nome);
}

Esse código dá erro porque nome foi declarado como late, mas nunca recebeu valor antes de ser usado. O late pode ser útil em alguns casos, mas não deve ser usado sem necessidade. Para atributos que já são recebidos no construtor, prefira inicializar diretamente.



final e const


Além de variáveis comuns, Dart tem final e const.



final


Use final quando o valor só pode ser definido uma vez.

void main() {
final String cpf = '123.456.789-00';

print(cpf);
}

Depois disso, você não pode alterar cpf.



const


O const quer dizer que o valor é fixo e já é conhecido antes do programa rodar. O valor também não pode ser alterado.

void main() {
const double pi = 3.14159;

print(pi);
}

Resumindo, use const quando você sabe que aquele valor sempre será o mesmo e já está escrito no código.



Principais tipos de dados


Vamos ver um pouco mais em detalhes sobre os principais tipos de dados.



String


Usado para texto.

void main() {
String nome = 'Servidor DNS';
String endereco = "192.168.0.10";

print(nome);
print(endereco);
}

Dart aceita aspas simples e aspas duplas para textos. Para interpolação de texto:

void main() {
String usuario = 'Bruno';
String sistema = 'Financeiro';

print('Usuário $usuario acessou o sistema $sistema');
}


int


Usado para números inteiros.

void main() {
int portas = 48;
int usuarios = 120;

print(portas);
print(usuarios);
}


double


Usado para números com casas decimais.

void main() {
double preco = 199.90;
double temperatura = 36.5;

print(preco);
print(temperatura);
}

Em Dart, double é um número decimal de 64 bits, parecido com float64 em outras linguagens. Na prática, ele consegue trabalhar bem com algo em torno de 15 a 17 dígitos significativos. Em cálculos, o double pode gerar pequenas imprecisões, já que ele acaba arredondando.


Para mostrar com uma quantidade fixa de casas decimais, podemos usar toStringAsFixed().



num


Use num quando a variável pode receber int ou double.

void main() {
num valor = 10;
print(valor);

valor = 10.50;
print(valor);
}

Use com moderação, o melhor é Especificar o tipo com int ou double.



bool


Usado para verdadeiro ou falso.

void main() {
bool usuarioAtivo = true;
bool pagamentoAprovado = false;

print(usuarioAtivo);
print(pagamentoAprovado);
}

Uso comum com condição:

void main() {
bool servidorOnline = true;

if (servidorOnline) {
print('Servidor disponível');
} else {
print('Servidor indisponível');
}
}


List


Uma lista guarda vários valores em ordem.

void main() {
List<String> usuarios = ['Ana', 'Jose', 'Carlos'];

print(usuarios); // Exibe: [Ana, Jose, Carlos]
print(usuarios[0]); // Exibe: Ana
}

O trecho abaixo cria uma lista de textos:

List<String> usuarios


Map


Um Map guarda dados no formato chave e valor.

void main() {
Map<String, String> usuario = {
'nome': 'Fulano',
'email': 'fulano@example.com',
};

print(usuario['nome']);
print(usuario['email']);
}


Set


Um Set guarda valores únicos.

void main() {
Set<String> permissoes = {'read', 'write', 'read'};

print(permissoes);
}

Resultado:

{read, write}

Como o valor read aparece duas vezes, ele imprime apenas uma ocorrência, eliminando entradas repetidas.



Valores nulos


O Dart possui null safety. Isso significa que, por padrão, uma variável não pode receber null. O método correto pra fazer uma variável ser null é:

void main() {
String? nome = null;

print(nome);
}


Conversão de tipos


Conversão de tipos é transformar um valor de um tipo para outro.



String para int


void main() {
String texto = '150';
int valor = int.parse(texto);

print(valor);
}

O trecho abaixo cria um texto (parece número mas não é):

String texto = '150';

Então fazemos a conversão usando int.parse(texto);:

int.parse(texto);


String para double


void main() {
String texto = '19.90';
double preco = double.parse(texto);

print(preco);
}


int para String


void main() {
int idade = 27;
String texto = idade.toString();

print(texto);
}


double para String com casas decimais


void main() {
double valor = 19.9876;
String formatado = valor.toStringAsFixed(2);

print(formatado);
}