Pular para o conteúdo principal

Introdução ao Dart

Uma breve introdução aos programas Dart e conceitos importantes.

Esta página fornece uma breve introdução à linguagem Dart por meio de exemplos de seus principais recursos.

Para aprender mais sobre a linguagem Dart, visite as páginas detalhadas de tópicos individuais listadas em Language no menu lateral esquerdo.

Para a cobertura das bibliotecas principais do Dart, confira a documentação da biblioteca principal. Você também pode conferir o Dart cheatsheet, para uma introdução mais interativa.

Hello World

#

Toda aplicação exige a função main() de nível superior, onde a execução começa. Funções que não retornam explicitamente um valor têm o tipo de retorno void. Para exibir texto no console, você pode usar a função print() de nível superior:

dart
void main() {
  print('Hello, World!');
}

Leia mais sobre a função main() em Dart, incluindo parâmetros opcionais para argumentos de linha de comando.

Variáveis

#

Mesmo em código Dart type-safe, você pode declarar a maioria das variáveis sem especificar explicitamente o tipo, usando var. Graças à inferência de tipos, os tipos dessas variáveis são determinados pelos valores iniciais:

dart
var name = 'Voyager I';
var year = 1977;
var antennaDiameter = 3.7;
var flybyObjects = ['Jupiter', 'Saturn', 'Uranus', 'Neptune'];
var image = {
  'tags': ['saturn'],
  'url': '//path/to/saturn.jpg',
};

Leia mais sobre variáveis em Dart, incluindo valores padrão, as keywords final e const e tipos estáticos.

Instruções de fluxo de controle

#

Dart suporta as instruções de fluxo de controle habituais:

dart
if (year >= 2001) {
  print('21st century');
} else if (year >= 1901) {
  print('20th century');
}
​
for (final object in flybyObjects) {
  print(object);
}
​
for (int month = 1; month <= 12; month++) {
  print(month);
}
​
while (year < 2016) {
  year += 1;
}

Leia mais sobre instruções de fluxo de controle em Dart, incluindo break e continue, switch e case, e assert.

Funções

#

Recomendamos especificar os tipos dos argumentos e do valor de retorno de cada função:

dart
int fibonacci(int n) {
  if (n == 0 || n == 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}
​
var result = fibonacci(20);

Uma sintaxe abreviada com => (arrow) é útil para funções que contêm uma única instrução. Essa sintaxe é especialmente útil ao passar funções anônimas como argumentos:

dart
flybyObjects.where((name) => name.contains('turn')).forEach(print);

Além de mostrar uma função anônima (o argumento de where()), este código mostra que você pode usar uma função como argumento: a função print() de nível superior é um argumento de forEach().

Leia mais sobre funções em Dart, incluindo parâmetros opcionais, valores padrão de parâmetros e escopo léxico.

Comentários

#

Comentários em Dart geralmente começam com //.

dart
// This is a normal, one-line comment.
​
/// This is a documentation comment, used to document libraries,
/// classes, and their members. Tools like IDEs and dartdoc treat
/// doc comments specially.
​
/* Comments like these are also supported. */

Leia mais sobre comentários em Dart, incluindo como funciona a ferramenta de documentação.

Imports

#

Para acessar APIs definidas em outras bibliotecas, use import.

dart
// Importing core libraries
import 'dart:math';
​
// Importing libraries from external packages
import 'package:test/test.dart';
​
// Importing files
import 'path/to/my_other_file.dart';

Leia mais sobre bibliotecas e visibilidade em Dart, incluindo prefixos de biblioteca, show e hide, e carregamento preguiçoso (lazy) pela keyword deferred.

Classes

#

Aqui está um exemplo de uma classe com três propriedades, dois construtores e um método. Uma das propriedades não pode ser definida diretamente, então ela é definida usando um método getter (em vez de uma variável). O método usa interpolação de strings para imprimir o equivalente em string das variáveis dentro de literais de string.

dart
class Spacecraft {
  String name;
  DateTime? launchDate;
​
  // Read-only non-final property
  int? get launchYear => launchDate?.year;
​
  // Constructor, with syntactic sugar for assignment to members.
  Spacecraft(this.name, this.launchDate) {
    // Initialization code goes here.
  }
​
  // Named constructor that forwards to the default one.
  Spacecraft.unlaunched(String name) : this(name, null);
​
  // Method.
  void describe() {
    print('Spacecraft: $name');
    // Type promotion doesn't work on getters.
    var launchDate = this.launchDate;
    if (launchDate != null) {
      int years = DateTime.now().difference(launchDate).inDays ~/ 365;
      print('Launched: $launchYear ($years years ago)');
    } else {
      print('Unlaunched');
    }
  }
}

Leia mais sobre strings, incluindo interpolação de strings, literais, expressões e o método toString().

Você pode usar a classe Spacecraft assim:

dart
var voyager = Spacecraft('Voyager I', DateTime(1977, 9, 5));
voyager.describe();
​
var voyager3 = Spacecraft.unlaunched('Voyager III');
voyager3.describe();

Leia mais sobre classes em Dart, incluindo listas de inicialização, new e const opcionais, construtores de redirecionamento, construtores factory, getters, setters e muito mais.

Enums

#

Enums são uma forma de enumerar um conjunto predefinido de valores ou instâncias, de modo a garantir que não possa haver outras instâncias desse tipo.

Aqui está um exemplo de um enum simples que define uma lista simples de tipos de planeta predefinidos:

dart
enum PlanetType { terrestrial, gas, ice }

Aqui está um exemplo de declaração de enum aprimorado de uma classe que descreve planetas, com um conjunto definido de instâncias constantes, a saber, os planetas do nosso próprio sistema solar.

dart
/// Enum that enumerates the different planets in our solar system
/// and some of their properties.
enum Planet {
  mercury(planetType: PlanetType.terrestrial, moons: 0, hasRings: false),
  venus(planetType: PlanetType.terrestrial, moons: 0, hasRings: false),
  // ···
  uranus(planetType: PlanetType.ice, moons: 27, hasRings: true),
  neptune(planetType: PlanetType.ice, moons: 14, hasRings: true);
​
  /// A constant generating constructor
  const Planet({
    required this.planetType,
    required this.moons,
    required this.hasRings,
  });
​
  /// All instance variables are final
  final PlanetType planetType;
  final int moons;
  final bool hasRings;
​
  /// Enhanced enums support getters and other methods
  bool get isGiant =>
      planetType == PlanetType.gas || planetType == PlanetType.ice;
}

Você pode usar o enum Planet assim:

dart
final yourPlanet = Planet.earth;
​
if (!yourPlanet.isGiant) {
  print('Your planet is not a "giant planet".');
}

Quando o compilador consegue inferir o tipo do enum pelo contexto, você pode usar a sintaxe mais concisa de dot shorthand para acessar valores de enum. Em vez de escrever o EnumName.value completo, basta escrever .value. Isso pode deixar seu código mais limpo e mais fácil de ler.

Por exemplo, ao declarar uma variável com o tipo explícito Planet, você pode omitir o nome do enum, porque o tipo Planet já está estabelecido:

dart
// Instead of the full, explicit syntax:
Planet myPlanet = Planet.venus;
​
// You can use a dot shorthand:
Planet myPlanet = .venus;

Atalhos de ponto (dot shorthands) não se limitam a declarações de variáveis. Eles também podem ser usados em contextos como argumentos de função e casos de switch, onde o tipo do enum é claro para o compilador.

Leia mais sobre enums em Dart, incluindo os requisitos de enum aprimorado, propriedades introduzidas automaticamente, acesso aos nomes dos valores enumerados, suporte a instruções switch e muito mais. Leia mais sobre a sintaxe de atalho de ponto.

Herança

#

Dart tem herança simples (single inheritance).

dart
class Orbiter extends Spacecraft {
  double altitude;
​
  Orbiter(super.name, DateTime super.launchDate, this.altitude);
}

Leia mais sobre extensão de classes, a anotação opcional @override e muito mais.

Mixins

#

Mixins são uma forma de reutilizar código em múltiplas hierarquias de classes. A seguir está uma declaração de mixin:

dart
mixin Piloted {
  int astronauts = 1;
​
  void describeCrew() {
    print('Number of astronauts: $astronauts');
  }
}

Para adicionar as capacidades de um mixin a uma classe, basta estender a classe com o mixin.

dart
class PilotedCraft extends Spacecraft with Piloted {
  // ···
}

PilotedCraft agora tem o campo astronauts, assim como o método describeCrew().

Leia mais sobre mixins.

Interfaces e classes abstratas

#

Todas as classes definem implicitamente uma interface. Por isso, você pode implementar qualquer classe.

dart
class MockSpaceship implements Spacecraft {
  // ···
}

Leia mais sobre interfaces implícitas ou sobre a keyword explícita interface.

Você pode criar uma classe abstrata para ser estendida (ou implementada) por uma classe concreta. Classes abstratas podem conter métodos abstratos (com corpos vazios).

dart
abstract class Describable {
  void describe();
​
  void describeWithEmphasis() {
    print('=========');
    describe();
    print('=========');
  }
}

Qualquer classe que estenda Describable tem o método describeWithEmphasis(), que chama a implementação de describe() feita por quem estende.

Leia mais sobre classes e métodos abstratos.

Para definir uma interface pura, combine os modificadores abstract e interface. Como outras classes abstratas, uma classe interface abstrata não pode ser instanciada. Outras bibliotecas podem implementá-la, mas não podem estendê-la.

dart
abstract interface class Launchable {
  void launch();
}
​
class Rocket implements Launchable {
  @override
  void launch() => print('Liftoff!');
}

Leia mais sobre classes interface abstratas.

Async

#

Evite o callback hell e torne seu código muito mais legível usando async e await.

dart
const oneSecond = Duration(seconds: 1);
// ···
Future<void> printWithDelay(String message) async {
  await Future.delayed(oneSecond);
  print(message);
}

O método acima é equivalente a:

dart
Future<void> printWithDelay(String message) {
  return Future.delayed(oneSecond).then((_) {
    print(message);
  });
}

Como o próximo exemplo mostra, async e await ajudam a tornar o código assíncrono fácil de ler.

dart
Future<void> createDescriptions(Iterable<String> objects) async {
  for (final object in objects) {
    try {
      var file = File('$object.txt');
      if (await file.exists()) {
        var modified = await file.lastModified();
        print(
          'File for $object already exists. It was modified on $modified.',
        );
        continue;
      }
      await file.create();
      await file.writeAsString('Start describing $object in this file.');
    } on IOException catch (e) {
      print('Cannot create description for $object: $e');
    }
  }
}

Você também pode usar async*, que oferece uma forma agradável e legível de construir streams.

dart
Stream<String> report(Spacecraft craft, Iterable<String> objects) async* {
  for (final object in objects) {
    await Future.delayed(oneSecond);
    yield '${craft.name} flies by $object';
  }
}

Leia mais sobre o suporte a assincronia, incluindo funções async, Future, Stream e o loop assíncrono (await for).

Exceções

#

Para lançar uma exceção, use throw:

dart
if (astronauts == 0) {
  throw StateError('No astronauts.');
}

Para capturar uma exceção, use uma instrução try com on ou catch (ou ambos):

dart
Future<void> describeFlybyObjects(List<String> flybyObjects) async {
  try {
    for (final object in flybyObjects) {
      var description = await File('$object.txt').readAsString();
      print(description);
    }
  } on IOException catch (e) {
    print('Could not describe object: $e');
  } finally {
    flybyObjects.clear();
  }
}

Observe que o código acima é assíncrono; try funciona tanto para código síncrono quanto assíncrono em uma função async.

Leia mais sobre exceções, incluindo stack traces, rethrow e a diferença entre Error e Exception.

Conceitos importantes

#

Enquanto você continua aprendendo a linguagem Dart, tenha em mente estes fatos e conceitos:

  • Tudo o que você pode colocar em uma variável é um objeto, e todo objeto é uma instância de uma classe. Até números, funções e null são objetos. Com exceção de null (se você habilitar o null safety sólido), todos os objetos herdam da classe Object.

  • Embora o Dart seja fortemente tipado, as anotações de tipo são opcionais porque o Dart consegue inferir os tipos. Em var number = 101, number é inferido como sendo do tipo int.

  • Variáveis não podem conter null a menos que você diga que podem. Você pode tornar uma variável anulável colocando um ponto de interrogação (?) no final do seu tipo. Por exemplo, uma variável do tipo int? pode ser um inteiro ou pode ser null. Se você sabe que uma expressão nunca avalia para null, mas o Dart discorda, você pode adicionar ! para afirmar que ela não é null (e lançar uma exceção se for). Um exemplo: int x = nullableButNotNullInt!

  • Quando você quiser dizer explicitamente que qualquer tipo é permitido, use o tipo Object? (se você habilitou null safety), Object, ou, se precisar adiar a verificação de tipos até o tempo de execução, o tipo especial dynamic.

  • O Dart suporta tipos genéricos, como List<int> (uma lista de inteiros) ou List<Object> (uma lista de objetos de qualquer tipo).

  • O Dart suporta funções de nível superior (como main()), assim como funções vinculadas a uma classe ou a um objeto (métodos static e de instância, respectivamente). Você também pode criar funções dentro de funções (funções aninhadas ou locais).

  • Da mesma forma, o Dart suporta variáveis de nível superior, assim como variáveis vinculadas a uma classe ou a um objeto (variáveis static e de instância). Variáveis de instância às vezes são chamadas de fields ou properties.

  • Diferentemente do Java, o Dart não tem as keywords public, protected e private. Se um identificador começa com underscore (_), ele é privado à sua biblioteca. Para detalhes, veja Libraries and imports.

  • Identificadores podem começar com uma letra ou underscore (_), seguidos de qualquer combinação desses caracteres mais dígitos.

  • O Dart tem tanto expressões (que têm valores em tempo de execução) quanto instruções (que não têm). Por exemplo, a expressão condicional condition ? expr1 : expr2 tem o valor de expr1 ou expr2. Compare isso com uma instrução if-else, que não tem valor. Uma instrução frequentemente contém uma ou mais expressões, mas uma expressão não pode conter diretamente uma instrução.

  • As ferramentas do Dart podem reportar dois tipos de problemas: warnings e errors. Warnings são apenas indicações de que seu código pode não funcionar, mas não impedem seu programa de executar. Errors podem ser de tempo de compilação ou de tempo de execução. Um erro de tempo de compilação impede que o código execute de forma alguma; um erro de tempo de execução resulta em uma exceção lançada enquanto o código executa.

Recursos adicionais

#

Você pode encontrar mais documentação e exemplos de código na documentação da biblioteca principal e na referência da API do Dart. O código deste site segue as convenções do guia de estilo do Dart.

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ê.