Escolar Documentos
Profissional Documentos
Cultura Documentos
OCTOBER 1, 2020
2.10 RELEASE
Reder Weyers
Copyright © 2021 Reder Weyers
Todos os direitos reservados
Sumário
LANGUAGE: EXEMPLO DA LINGUAGEM DART
Olá Mundo
Variáveis
Declarações De Fluxo De Controle
Funções
Comentários
Importações
Classes
Herança
Mixins
Interfaces E Classes Abstratas
Assíncrono
Exceções
SOBRE O AUTOR
Language: Exemplo da Linguagem Dart
As próximas linhas são apenas uma breve introdução ao idioma
Dart para pessoas que gostam de aprender pelo exemplo. Você
também pode querer verificar as diversidades da linguagem e
biblioteca Dart, visitando o Dart cheatsheet codelab.
Olá Mundo
Todo aplicativo tem uma função main (). Para exibir texto no console,
você pode usar a função print() de nível superior:
Variáveis
Mesmo em código Dart seguro para tipos, a maioria das variáveis
não precisam de tipos explícitos, graças à inferência de tipo:
Uma sintaxe abreviada => (seta) é útil para funções que contêm
uma única instrução. Essa sintaxe é especialmente útil ao passar
funções anônimas como argumentos:
Você também pode usar o async* , que oferece uma maneira legal e
legível de criar fluxos (streams).
Leia mais sobre o suporte a assincronia, incluindo funções async ,
Future , Stream e o loop assíncrono ( await for ) .
Exceções
Para levantar uma exceção, use throw :
PREFIRA Brevidade.
Seja claro e preciso, mas também conciso.
E não:
NÃO USE importação de bibliotecas que estejam
dentro do diretório src de outro pacote.
Regra de Linter: implementação_imports
O diretório src em lib é especificado para conter bibliotecas
privadas para a própria implementação do pacote. A forma como os
mantenedores dos pacotes cria versões de seus pacotes leva esta
convenção em consideração. Eles são livres para fazer mudanças
radicais no código src sem que isso seja uma mudança significativa
no pacote.
Isso significa que se você importar a biblioteca privada de algum
outro pacote, um lançamento menor e teoricamente ininterrupto
desse pacote pode quebrar seu código.
E não:
EVITAR abreviações.
A menos que a abreviatura seja mais comum do que o termo não
abreviado, não abrevie. Se você abreviar, capitalize corretamente.
PREFIRA colocar o substantivo mais descritivo por
último.
A última palavra deve ser a mais descritiva do que a coisa é. Você
pode prefixá-lo com outras palavras, como adjetivos, para descrever
melhor a coisa.
Se a variável local não tiver um inicializador, seu tipo não pode ser
inferido. Nesse caso, é uma boa ideia fazer anotações. Caso
contrário, você obtém dynamic e perde os benefícios da verificação
de tipo estático.
Observe que isso não se aplica a setters, onde o nome deixa claro o
que o valor representa:
Pode ser bom - mais curto e fácil de usar com ferramentas - ter essa
funcionalidade String ativada:
Para habilitar esse código, você pode importar uma biblioteca que contém
uma extensão da classe String :
Isso é tudo que você geralmente precisa saber para usar métodos de
extensão. Ao escrever seu código, você também pode precisar saber
como os métodos de extensão dependem de tipos estáticos (em oposição
a dynamic ) e como resolver conflitos de API.
O
motivo de isso não funcionar no dynamic é que os métodos de extensão
são resolvidos em relação ao tipo estático do receptor. Como os métodos
de extensão são resolvidos estaticamente, eles são tão rápidos quanto
chamar uma função estática.
Conflitos de api
Se um membro de extensão entrar em conflito com uma interface ou com
outro membro de extensão, você terá algumas opções.
Uma opção é alterar a forma como você importa a extensão conflitante,
usando show ou hide para limitar a API exposta:
Por exemplo, veja como você pode implementar uma extensão na classe
String :
Para criar uma extensão local que seja visível apenas na biblioteca onde
está declarada, omita o nome da extensão ou dê a ela um nome que
comece com um sublinhado ( _ ).
Os membros da extensão podem ser métodos, getters, setters,
operadores. As extensões também podem ter campos estáticos e
métodos auxiliares estáticos.
Implementando Extensões Genéricas
As extensões podem ter parâmetros de tipo genérico. Por exemplo, aqui
está um código que estende o tipo integrado List<T> com um getter, um
operador e um método:
O
tipo T é vinculado com base no tipo estático da lista em que os métodos
são chamados.
Language: Null Safety: Segurança Nula do
Som
Segurança nula de som - atualmente em beta - está chegando à
linguagem Dart!
Quando você opta por segurança nula, os tipos em seu código não
podem ser nulos por padrão, o que significa que os valores não podem
ser nulos a menos que você diga que podem ser. Com segurança nula,
seus erros de desreferência nula de tempo de execução se transformam
em erros de análise de tempo de edição.
Você pode tentar segurança nula em seu ambiente de desenvolvimento
normal, configurando seu projeto para usar um SDK de visualização de
tecnologia. Ou você pode praticar o uso de segurança nula no aplicativo
da web DartPad com segurança nula, mostrado na captura de tela a
seguir.
Princípios De Segurança Nulos
O suporte de segurança nula do Dart é baseado nos seguintes três
princípios básicos de design:
Não anulável por padrão. A menos que você diga explicitamente
ao Dart que uma variável pode ser nula, ela é considerada não
anulável. Esse padrão foi escolhido depois que a pesquisa descobriu
que não nulo era de longe a escolha mais comum em APIs.
Incrementalmente adotável. Você escolhe o que migrar para a
segurança nula e quando. Você pode migrar de forma incremental,
combinando código seguro para nulo e código seguro não nulo no
mesmo projeto. Fornecemos ferramentas para ajudá-lo com a
migração.
Totalmente correto. A segurança nula do Dart é boa, o que permite
otimizações do compilador. Se o sistema de tipos determina que
algo não é nulo, então esse algo nunca pode ser nulo. Depois de
migrar todo o seu projeto e suas dependências para segurança nula,
você obtém todos os benefícios da integridade - não apenas menos
bugs, mas binários menores e execução mais rápida.
Um Tour Pelo Recurso De Segurança Nula
Novos operadores e palavras-chave relacionadas com a segurança nula
incluem ? , ! e late . Se você usou Kotlin, TypeScript ou C#, a sintaxe para
segurança nula pode parecer familiar. Isso é intencional: a linguagem Dart
pretende não surpreender.
Criação de variáveis
Ao criar uma variável, você pode usar ? e late para informar o Dart da
nulidade da variável.
Aqui estão alguns exemplos de declaração de variáveis não anuláveis
(assumindo que você optou pela segurança nula):
Se você sabe que uma variável não anulável será inicializada com um
valor não nulo antes de ser usada, mas o analisador Dart não concorda,
insira late antes do tipo da variável:
Este é um código semelhante, mas com uma instrução if que verifica se há nulo:
Se você tiver certeza de que uma expressão com um tipo anulável não é
nula, você pode adicionar ! para fazer o Dart tratá-la como não anulável:
* Mesmo quando todos os valores int no mapa não são nulos, quando
você usa uma chave inválida para fazer uma pesquisa no mapa, o valor
retornado é nulo.
Como as pesquisas de mapa podem retornar nulo, você não pode atribuí-
las a variáveis não anuláveis:
Atualizar dependências
Antes de migrar o código do seu pacote, atualize suas dependências para
versões nulas-seguras:
1. Atualize pubspec.yaml para usar versões nulas-seguras (conforme
listado na coluna Resolvable) de suas dependências. Omita .x
sufixos para tornar a solução de versão mais flexível e não atualize a
restrição mínima do SDK. Por exemplo, o pubspec.yaml arquivo
pode ter a seguinte aparência:
2. Execute dart pub upgrade .
Migrar
A maioria das mudanças que seu código precisa para ser null safe são
facilmente previsíveis. Por exemplo, se uma variável pode ser null , seu
tipo precisa de um sufixo . Um parâmetro nomeado que não deve ser
anulável precisa ser marcado como obrigatório.
Você tem duas opções para migrar:
Use a ferramenta de migração , que pode fazer a maioria das mudanças
facilmente previsíveis para você.
Migre seu código manualmente.
Uma única dica pode ter efeito cascata em outras partes do código. No
exemplo anterior, adicionar manualmente um /*!*/ marcador onde zero é
atribuído seu valor (na linha 2) faz a ferramenta de migração inferir o tipo
de as zero em int vez de int? . Essa mudança de tipo pode afetar o código
que usa direta ou indiretamente zero .
Com a dica acima, a ferramenta de migração muda suas edições
propostas, como mostram os trechos de código a seguir. A linha 3 não tem
mais um !depois zero e, na linha 4, zeroOne infere-se que é uma lista de
int , não int? .
Aplicando mudanças
Quando você gostar de todas as alterações propostas pela ferramenta de
migração, clique em Aplicar migração. A ferramenta de migração exclui
os marcadores de dica e salva o código migrado. A ferramenta também
atualiza a restrição mínima do SDK no pubspec, que opta pelo pacote
com segurança nula.
A próxima etapa é analisar estaticamente seu código . Se for válido, teste
seu código. Então, se você publicou seu código no pub.dev, publique um
pré-lançamento seguro para nulos.
Migrando manualmente
Se preferir não usar a ferramenta de migração, você pode migrar
manualmente.
Recomendamos que você primeiro migre as bibliotecas de folhas -
bibliotecas que não importam outros arquivos do pacote. Em seguida,
migre as bibliotecas que dependem diretamente das bibliotecas folha.
Termine migrando as bibliotecas que têm mais dependências dentro do
pacote.
Por exemplo, digamos que você tenha um lib/src/util.dart arquivo que
importa outros pacotes (null-safe) e bibliotecas centrais, mas que não tem
nenhuma import '<local_path>' diretiva. Considere migrar util.dart primeiro e
depois migrar arquivos simples que dependem apenas do util.dart . Se
alguma biblioteca tiver importações cíclicas (por exemplo, A importa B que
importa C e C importa A), considere migrar essas bibliotecas juntas.
Para migrar um pacote manualmente, siga estas etapas:
1. Edite o pubspec.yaml arquivo do pacote, definindo a restrição
mínima do SDK para 2.12.0-0 :
2. Gere novamente o arquivo de configuração do pacote:
3. A execução dart pub get com uma restrição SDK inferior de 2.12.0-0
define a versão de idioma padrão de cada biblioteca no pacote para
2.12, optando por segurança nula.
4. Abra o pacote em seu IDE. Você provavelmente verá muitos erros
de análise. Isso está ok.
5. Migre o código de cada arquivo Dart, usando o analisador para
identificar erros estáticos. Eliminar erros estáticos adicionando ? , ! ,
required , e late , conforme necessário.
Consulte Segurança nula não sólida para obter mais ajuda sobre como
migrar o código manualmente.
Análise
Atualize seus pacotes (usando pub get em seu IDE ou na linha de
comando). Em seguida, use seu IDE ou a linha de comando para realizar
uma análise estática em seu código:
Teste
Se seu código passar na análise, execute os testes:
Restrições SDK
Defina a restrição inferior do SDK para a versão beta de 2.12 que você
usou para testar a migração e a restrição superior do SDK para <3.0.0 .
Por exemplo, se você estiver usando 2.12.0-29.10.beta, suas restrições
devem ser assim:
Versão do pacote
Atualize a versão do pacote para indicar uma alteração importante e
incluir um sufixo nullsafety :
Se o seu pacote já estiver em 1.0.0 ou superior, aumente a versão
principal. Por exemplo, se a versão anterior for 2.3.2 , a nova versão
será 3.0.0-nullsafety.0 .
Se o seu pacote não atingiu 1.0.0 ainda, quer aumentar a versão
secundária ou atualizar a versão para 1.0.0. Por exemplo, se a
versão anterior for 0.3.2 , a nova versão será uma das seguintes:
0.4.0-nullsafety.0
1.0.0-nullsafety.0
Para atualizações subsequentes do pré-lançamento seguro para nulos do
pacote, incremente o sufixo de pré-lançamento. Por exemplo, se a
primeira versão segura para nulos for 3 .0.0-nullsafety.0 , então a próxima é
3.0.0-nullsafety.1 .
Você pode manter uma versão estável e um pré-lançamento seguro para
nulos ao mesmo tempo. Por exemplo, se você tiver uma versão estável
1.0.0 e um pré-lançamento 2.0.0-nullsafety.0 , ainda poderá publicar novas
versões da versão estável ( 1.0.1 ) e do pré-lançamento seguro para nulos
( 2.0.0-nullsafety.1 ).
Uma vez que a segurança nula está disponível em uma versão estável do
SDK do Dart, nós o encorajamos a publicar uma versão estável do seu
pacote de segurança nula.
Bem-Vindo Ao Null Safety
Se você chegou até aqui, deve ter um pacote Dart totalmente migrado e
seguro para nulos. Se todos os pacotes dos quais você depende também
forem migrados, então seu programa está correto com relação a erros de
referência nula.
De toda a equipe Dart, obrigado por migrar seu código.
Language: Null Safety: Compreendendo a
Segurança Nula
Escrito por Bob Nystrom em julho de 2020
Se você executar este programa Dart sem segurança nula, ele lançará
uma exceção na chamada NoSuchMethodError para .length . O valor
null é uma instância da classe Null e Null não tem getter de
“comprimento”. Falhas de tempo de execução são uma droga. Isso é
especialmente verdadeiro em uma linguagem como o Dart, projetado para
ser executado no dispositivo do usuário final. Se um aplicativo de servidor
falhar, você pode reiniciá-lo antes que alguém perceba. Mas quando um
aplicativo Flutter trava no telefone de um usuário, ele não fica feliz.
Quando seus usuários não estão satisfeitos, você não fica feliz.
Os desenvolvedores gostam de linguagens com tipos estáticos, como o
Dart, porque permitem que o verificador de tipo encontre erros no código
em tempo de compilação, geralmente direto no IDE. Quanto mais cedo
você encontrar um bug, mais cedo poderá corrigi-lo. Quando os designers
de linguagem falam sobre “consertar erros de referência nula”, eles
significam enriquecer o verificador de tipo estático para que a linguagem
possa detectar erros como a tentativa acima de chamar um valor .length
que possa ser null .
Não existe uma solução verdadeira para este problema. Rust e Kotlin têm
sua própria abordagem que faz sentido no contexto dessas linguagens.
Este doc aborda todos os detalhes de nossa resposta para Dart. Inclui
alterações no sistema de tipo estático e um conjunto de outras
modificações e novos recursos de linguagem para permitir que você não
apenas escreva código seguro para nulos, mas também que aproveite
isso.
Este documento é longo. Se você deseja algo mais curto que cubra
apenas o que você precisa saber para começar a trabalhar, comece com a
visão geral. Quando você estiver pronto para um entendimento mais
profundo e tiver tempo, volte aqui para entender como funciona a
linguagem null , porque a projetamos dessa forma e como escrever Dart
idiomático, moderno e seguro para nulos. (Alerta de spoiler: termina
surpreendentemente próximo de como você escreve Dart hoje.)
Cada uma das várias maneiras como uma linguagem pode lidar com
erros de referência nula tem seus prós e contras. Esses princípios
guiaram as escolhas que fizemos:
O código deve ser seguro por padrão. Se você escrever um novo
código Dart e não usar nenhum recurso explicitamente inseguro, ele
nunca lançará um erro de referência nula no tempo de execução.
Todos os erros de referência nula possíveis são detectados
estaticamente. Se quiser adiar parte dessa verificação para o tempo
de execução para obter maior flexibilidade, você pode, mas precisa
escolher isso usando algum recurso que seja textualmente visível no
código.
Em outras palavras, não estamos lhe dando um colete salva-vidas e
deixando que você se lembre de colocá-lo toda vez que entrar na
água. Em vez disso, oferecemos a você um barco que não afunda.
Você fica seco, a menos que pule no mar.
O código seguro nulo deve ser fácil de escrever. A maior parte do
código Dart existente é dinamicamente correto e não lança erros de
referência nula. Você gosta do seu programa Dart da maneira como
ele se parece agora, e queremos que seja capaz de continuar
escrevendo códigos dessa forma. A segurança não deve exigir o
sacrifício da usabilidade, o pagamento de penitências ao revisor de
tipos ou a mudança significativa de sua maneira de pensar.
O código de segurança nulo resultante deve ser totalmente correto.
“Solidez” no contexto da verificação estática significa coisas
diferentes para pessoas diferentes. Para nós, no contexto de
segurança nula, isso significa que se uma expressão tem um tipo
estático que não permite nenhuma execução null , possível dessa
expressão pode ser avaliada como null . A linguagem fornece essa
garantia principalmente por meio de verificações estáticas, mas
também pode haver algumas verificações de tempo de execução
envolvidas. (Porém, observe o primeiro princípio: qualquer lugar
onde essas verificações de tempo de execução acontecem será sua
escolha.)
Solidez é importante para a confiança do usuário. Um barco que quase
sempre flutua não é aquele em que você está entusiasmado para
enfrentar o mar aberto. Mas também é importante para nossos intrépidos
hackers de compiladores. Quando a linguagem oferece garantias rígidas
sobre as propriedades semânticas de um programa, isso significa que o
compilador pode realizar otimizações que pressupõem que essas
propriedades sejam verdadeiras. Quando se trata de null , isso significa
que podemos gerar um código menor que elimina verificações null
desnecessárias e um código mais rápido que não precisa verificar se um
receptor não é null antes de chamar métodos nele.
Uma advertência: só garantimos a integridade em programas Dart que
são totalmente seguros para nulos. O Dart oferece suporte a programas
que contêm uma mistura de código seguro nulo mais recente e código
legado mais antigo. Nesses programas de versão mista, erros de
referência nula ainda podem ocorrer. Em um programa de versão mista,
você obtém todos os benefícios de segurança estática nas partes que são
seguras para nulos, mas não obtém segurança total do tempo de
execução até que todo o aplicativo seja seguro para nulos.
Observe que eliminar null não é um objetivo. Não há nada de errado com
null . Pelo contrário, é muito útil poder representar a ausência de um valor.
Construir suporte para um valor especial “ausente” diretamente no idioma
torna o trabalho com ausência flexível e utilizável. Ele sustenta os
parâmetros opcionais, o prático ?. operador com reconhecimento de nulo
e a inicialização padrão. Não é null que isso seja ruim, é null ir aonde
você não espera que cause problemas.
Portanto, com segurança nula, nosso objetivo é dar a você controle e
percepção de onde null pode fluir seu programa e a certeza de que ele
não pode fluir em algum lugar que possa causar um travamento.
Anulabilidade No Sistema De Tipo
A segurança nula começa no sistema de tipo estático porque tudo o mais
depende disso. Seu programa Dart possui todo um universo de tipos: tipos
primitivos como int e String , tipos de coleção como List , e todas as
classes e tipos que você e os pacotes que você usa definem. Antes da
segurança nula, o sistema de tipo estático permitia que o valor null
fluísse para expressões de qualquer um desses tipos.
No jargão da teoria de tipo, o tipo Null foi tratado como um subtipo de
todos os tipos:
Mas ir à outra direção e passar um tipo anulável para algo que espera o
tipo não anulável subjacente não é seguro. O código que espera um
String pode chamar métodos String no valor. Se você passar um String?
para ele, null pode fluir e isso pode falhar:
Este programa não é seguro e não devemos permitir isso. No entanto,
Dart sempre teve essa coisa chamada downcasts implícitos. Se você, por
exemplo, passar um valor de tipo Object para uma função esperando um
String , o verificador de tipo permite:
Achamos que esta é uma boa mudança geral. Nossa impressão é que a
maioria dos usuários nunca gostou de downcasts implícitos. Em particular,
você pode ter se queimado por isso antes:
Identificar o bug? O método .where() é preguiçoso, então ele retorna um
Iterable , não a List . Este programa compila, mas lança uma exceção em
tempo de execução ao tentar converter Iterable no tipo List que declara
filterEvens que ele retorna. Com a remoção de downcasts implícitos, isso se
torna um erro de compilação.
Onde nós estávamos?
Certo, OK, então é como se pegássemos o universo de tipos em seu
programa e os dividíssemos em duas metades:
Existe uma região de tipos não anuláveis. Esses tipos permitem que você
acesse todos os métodos interessantes, mas nunca podem conter null . E
então há uma família paralela de todos os tipos anuláveis
correspondentes. Esses permitem null , mas você não pode fazer muito
com eles. Deixamos os valores fluírem do lado não anulável para o lado
anulável porque fazer isso é seguro, mas não na outra direção.
Parece que os tipos anuláveis são basicamente inúteis. Eles não têm
métodos e você não pode fugir deles. Não se preocupe, temos um
conjunto completo de recursos para ajudá-lo a mover os valores da
metade anulável para o outro lado, que veremos em breve.
Cabeçalho e rodapé
Esta seção é um pouco esotérica. Você pode geralmente ignorá-lo, exceto
por dois marcadores no final, a menos que você goste de coisas do
sistema de tipos. Imagine todos os tipos em seu programa com arestas
entre aqueles que são subtipos e supertipos uns dos outros. Se você
fosse desenhá-lo, como os diagramas neste documento, ele formaria um
enorme gráfico direcionado com supertipos como Object próximo ao topo
e classes folha como seus próprios tipos próximo ao fundo.
Se esse gráfico direcionado chega a um ponto no topo onde há um único
tipo que é o supertipo (direta ou indiretamente), esse tipo é chamado de
tipo superior. Da mesma forma, se houver um tipo estranho naquele fundo
que é um subtipo de todos os tipos, você tem um tipo fundo. (Neste caso,
seu gráfico direcionado é uma rede.)
É conveniente se o seu sistema de tipos tiver um tipo superior e inferior,
porque isso significa que as operações de nível de tipo, como limite
superior mínimo (que a inferência de tipo usa para descobrir o tipo de uma
expressão condicional com base nos tipos de seus dois ramos) podem
sempre produzir um tipo. Antes da segurança nula, Object era o tipo
superior do Dart e Null era o tipo inferior.
Como Object agora não é anulável, não é mais um tipo superior. Null não é
um subtipo disso. Dart não tem um tipo de topo nomeado. Se você precisa
de um tipo superior, você deseja Object?. Da mesma forma, Null não é
mais o tipo de fundo. Se fosse, tudo ainda seria anulável. Em vez disso,
adicionamos um novo tipo de fundo chamado Never :
Devoluções inválidas
Se uma função tiver um tipo de retorno não anulável, cada caminho
através da função deve alcançar uma instrução return que retorna um
valor. Antes da segurança nula, Dart era muito negligente quanto a
retornos perdidos. Por exemplo:
Se você analisar isso, terá uma leve sugestão de que talvez tenha
esquecido uma devolução, mas se não, não é grande coisa. Isso porque
se a execução chegar ao final do corpo de uma função, o Dart retornará
implicitamente null . Como todo tipo pode ser anulado, tecnicamente essa
função é segura, embora provavelmente não seja o que você deseja.
Com tipos de som não anuláveis, este programa é totalmente errado e
inseguro. Sob segurança nula, você obtém um erro de compilação se uma
função com um tipo de retorno não anulável não retornar um valor
confiável. Por “confiável”, quero dizer que a linguagem analisa todos os
caminhos do fluxo de controle através da função. Contanto que todos eles
devolvam algo, ele está satisfeito. A análise é muito inteligente, então
mesmo esta função está OK:
Iremos mergulhar mais profundamente na nova análise de fluxo na
próxima seção.
Análise de acessibilidade
Em primeiro lugar, corrigimos a reclamação de longa data de que a
promoção de tipo não é inteligente sobre devoluções antecipadas e outros
caminhos de código inacessíveis. Ao analisar uma função, agora leva em
conta return , break , throw , e qualquer outra execução maneira pode
terminar no início de uma função. Sob segurança nula, esta função:
Aqui está uma pergunta para você: O doohickey getter pode Thing voltar
null ?
Parece que ele poderia porque você está usando ?. no resultado. Mas
pode ser que o segundo ?. esteja lá apenas para lidar com casos em que
thing está null , não o resultado de doohickey . Você não pode dizer.
Para resolver isso, pegamos emprestada uma ideia inteligente do design
do C# do mesmo recurso. Quando você usa um operador com
reconhecimento de nulo em uma cadeia de método, se o receptor for
avaliado como null , todo o resto da cadeia de método sofre um curto-
circuito e é ignorado. Isso significa que se doohickey tiver um tipo de
retorno não anulável, você pode e deve escrever:
A conversão error para o tipo String não anulável lançará uma exceção
de tempo de execução se a conversão falhar. Caso contrário, ele nos dá
uma string não anulável na qual podemos chamar os métodos.
“Descartando a nulidade” surge com frequência suficiente para que
tenhamos uma nova sintaxe abreviada. Um ponto de exclamação pós-
fixado ( ! ) pega a expressão à esquerda e a converte em seu tipo não
anulável subjacente. Portanto, a função acima é equivalente a:
Este “operador bang” de um caractere é particularmente útil quando o tipo
subjacente é prolixo. Seria muito chato ter que escrever as
Map<TransactionProviderFactory, List<Set<ResponseFilter>>> apenas
para jogar fora um single ? de algum tipo.
Claro, como qualquer elenco, o uso ! vem com uma perda de segurança
estática. O elenco deve ser verificado em tempo de execução para
preservar a integridade e pode falhar e lançar uma exceção. Mas você
tem controle sobre onde esses casts são inseridos e sempre pode vê-los
examinando seu código.
Variáveis atrasadas
O lugar mais comum onde o verificador de tipo não pode provar a
segurança do código é em torno de variáveis e campos de nível superior.
Aqui está um exemplo:
Isso funciona bem. Mas isso envia um sinal confuso para o mantenedor
da classe. Ao marcar como _temperature anulável, você indica que null é
um valor útil e significativo para esse campo. Mas essa não é a intenção.
O campo _temperature nunca deve ser observado em seu estado null .
Para lidar com o padrão comum de estado com inicialização atrasada,
adicionamos um novo modificador late . Você pode usá-lo assim:
Observe que o campo _temperature tem um tipo não anulável, mas não
foi inicializado. Além disso, não há nenhuma asserção nula explícita
quando é usada. Existem alguns modelos que você pode aplicar à
semântica late , mas penso assim: O modificador late significa “impor as
restrições desta variável em tempo de execução em vez de em tempo de
compilação”. É quase como a palavra “atrasado” descreve quando reforça
as garantias da variável.
Nesse caso, como o campo não foi inicializado definitivamente, toda vez
que o campo é lido, uma verificação de tempo de execução é inserida
para garantir que um valor foi atribuído a ele. Se não tiver, uma exceção é
lançada. Atribuir à variável o tipo String significa “você nunca deve me ver
com um valor diferente de uma string” e o modificador late significa
“verificar isso em tempo de execução”.
De certa forma, o modificador late é mais “mágico” do que o uso, ?
porque qualquer uso do campo pode falhar e não há nada textualmente
visível no local de uso. Mas você não tem que escrever a declaração late
para obter esse comportamento, e nossa crença é que, vendo o
modificador há bastante explícita para que isso seja sustentável.
Em troca, você obtém melhor segurança estática do que usar um tipo
anulável. Como o tipo do campo agora é não anulável, é um erro de
compilação tentar atribuir null ou anulável ao campo String . O
modificador late permite adiar a inicialização, mas ainda proíbe tratá-la
como uma variável anulável.
Inicialização lenta
O modificador late também possui alguns outros poderes especiais. Pode
parecer paradoxal, mas você pode usar late em um campo que tenha um
inicializador:
Por razões pouco claras, o Dart há muito apoia três cantos desta tabela,
mas deixou a combinação de nomeado + obrigatório vazia. Com
segurança nula, preenchemos isso. Você declara um parâmetro nomeado
obrigatório colocando required antes do parâmetro:
Uma vez que a promoção de tipo se aplica aos habitantes locais, agora
funciona bem. Se você precisar alterar o valor, lembre-se de armazenar de
volta no campo e não apenas no local.
Nulidade e genéricos
Como a maioria das linguagens tipadas estaticamente modernas, o Dart
possui classes e métodos genéricos. Eles interagem com a nulidade de
algumas maneiras que parecem contraintuitivas, mas fazem sentido
quando você pensa nas implicações. Em primeiro lugar, "este tipo é
anulável?" não é mais uma simples pergunta sim ou não. Considerar:
Na definição de Box , é T um tipo anulável ou um tipo não anulável?
Como você pode ver, ele pode ser instanciado com qualquer tipo. A
resposta é que T é um tipo potencialmente anulável. Dentro do corpo de
uma classe ou método genérico, um tipo potencialmente anulável tem
todas as restrições de tipos anuláveis e tipos não anuláveis.
O primeiro significa que você não pode chamar nenhum método nele,
exceto um punhado definido em Object. O último significa que você deve
inicializar quaisquer campos ou variáveis desse tipo antes de serem
usados. Isso pode tornar os parâmetros de tipo muito difíceis de trabalhar.
Na prática, alguns padrões aparecem. Em classes semelhantes a
coleções, onde o parâmetro de tipo pode ser instanciado com qualquer
tipo, você só precisa lidar com as restrições. Na maioria dos casos, como
no exemplo aqui, significa garantir que você tenha acesso a um valor do
tipo do argumento type sempre que precisar trabalhar com um.
Felizmente, classes semelhantes a coleções raramente chamam métodos
em seus elementos.
Em locais onde você não tem acesso a um valor, você pode tornar o uso
do parâmetro de tipo anulável:
Este programa deve ser executado sem erros. Usando as T faz isso. Usar
! lançaria uma exceção.
Outros tipos genéricos têm algum limite que restringe os tipos de
argumentos de tipo que podem ser aplicados:
A execução dart pub get com uma restrição SDK inferior de 2.12.0-0
define a versão de idioma padrão de cada biblioteca no pacote para
2.12, optando por segurança nula.
3. Abra o pacote em seu IDE. Você provavelmente verá muitos erros
de análise. Isso está ok.
4. Adicione um comentário sobre a versão do idioma na parte superior
de todos os arquivos DART que você não deseja considerar durante
a migração atual:
Usar a versão 2.9 da linguagem para uma biblioteca que está em
um pacote 2.12 pode reduzir os erros de análise (rabiscos
vermelhos) provenientes de código não migrado. No entanto, a
segurança nula inadequada reduz as informações que o analisador
pode usar. Por exemplo, o analisador pode presumir que um tipo de
parâmetro não é anulável, embora um arquivo 2.9 possa passar um
valor nulo.
5. Migre o código de cada arquivo Dart, usando o analisador para
identificar erros estáticos.
Eliminar erros estáticos adicionando ? , ! , required , e late , conforme
necessário.
Testar Ou Executar Programas De Versão
Mista
Para testar ou executar o código de versão mista, você precisa desativar
a segurança de som nulo. Você pode fazer isso de duas maneiras:
Desative o som de segurança nula usando o --no-sound-null-safety
sinalizador para o comando dart ou flutter :
torna-se
Getters que foram não marcados @nullable devem não ter tipos
anuláveis, mesmo se a ferramenta de migração os sugerir. Adicione
! dicas conforme necessárias e execute novamente a análise.
Como Devo Migrar Uma Fábrica Que Posso
Retornar null ?
Prefira fábricas que não retornem nulos. Vimos um código que pretendia
lançar uma exceção devido a uma entrada inválida, mas acabou
retornando nulo.
Ao invés de:
Faz:
Isso significa que fooList pode conter valores nulos. Isso pode acontecer
se você estiver inicializando a lista com comprimento e preenchendo-a por
meio de um loop.
Se você está simplesmente inicializando a lista com o mesmo valor, você
deve usar o filled construtor.
Dart 2.1
O Dart 2.1 adicionou suporte para conversão int-para-double , permitindo
aos desenvolvedores definir valores double usando literais inteiros. Esse
recurso removeu o incômodo de ser forçado a usar um literal double (por
exemplo, 4.0 ) quando o valor era conceitualmente um inteiro. No seguinte
código Flutter horizontal e vertical tipo double :
Dart 2.2
O Dart sempre deu suporte a listas e mapas literais, mas o Dart 2.2
adicionou suporte para conjuntos de literais:
Dart 2.3
O Dart 2.3 adicionou três operadores projetados para melhorar o código
que executa a manipulação de lista, como o código de IU declarativo.
O operador de propagação permite desempacotar os elementos de uma
lista em outra. No exemplo a seguir, a lista retornada por
buildMainElements() é descompactada na lista que está sendo passada
para o argumento children :
O operador coleção if permite adicionar elementos condicionalmente. O
exemplo a seguir adiciona um elemento FlatButton , a menos que esta
seja a última página:
Dart 2.5
O Dart 2.5 não adicionou nenhum recurso à linguagem Dart, mas
adicionou suporte para chamar o código C nativo do código Dart usando
uma nova biblioteca central dart:ffi .
Dart 2.6
Dart 2.6 ainda não adicionou nenhum recurso para a linguagem Dart, mas
fez adicionar uma nova ferramenta, dart2native, para compilar o código
Dart para executáveis nativas.
Dart 2.7
O Dart 2.7 adicionou suporte para métodos de extensão, permitindo
adicionar funcionalidade a qualquer tipo - mesmo tipos que você não
controla - com a brevidade e a experiência de autocompletar de
chamadas de métodos regulares. Como a visualização técnica desse
recurso estava no 2.6, você pode usar métodos de extensão sem avisos
se especificar 2.6.0 ou uma versão posterior como a restrição inferior do
SDK.
O exemplo a seguir estende a classe String dart:core com um novo
método parseInt() :
Dart 2.8
O Dart 2.8 não adicionou nenhum recurso à linguagem Dart, mas continha
várias alterações preparatórias para garantir grande usabilidade e
desempenho relacionados à anulação no próximo recurso de segurança
nula.
Ele também continha uma ferramenta pub mais rápida e um novo
comando pub desatualizado.
Dart 2.9
O Dart 2.9 não adicionou nenhum recurso à linguagem Dart.
Dart 2.10
O Dart 2.10 não adicionou nenhum recurso à linguagem Dart, mas
adicionou uma ferramenta Dart expandida que é análoga à Flutter SDK
ferramenta Flutter .
Controle De Versão De Idioma
Um único Dart SDK pode suportar simultaneamente várias versões da
linguagem Dart. O compilador determina a versão que o código tem como
objetivo e interpreta o código de acordo com essa versão.
O controle de versão de idioma é importante nas raras ocasiões em que o
Dart introduz um recurso incompatível como segurança nula. O código que
costumava compilar de forma limpa antes da segurança nula (mas talvez
travar no tempo de execução) pode não ser mais compilado quando a
segurança nula é ativada. Como a migração de seus aplicativos e pacotes
- e de todos os pacotes dos quais eles dependem - para segurança nula
pode demorar um pouco, o Dart usa o controle de versão de idioma para
oferecer suporte ao código seguro não nulo junto com o código seguro
nulo.
Cada pacote tem uma versão de idioma padrão, igual à <major>.<minor>
parte da restrição inferior do SDK no pubspec. Por exemplo, a seguinte
entrada em um arquivo pubspec.yaml indica que este pacote usa a versão
de idioma Dart 2.7.
Por exemplo:
Aqui está o que este programa usa que se aplica a todos (ou quase
todos) os aplicativos Dart:
// This is a comment.
Um comentário de uma linha. O Dart também oferece suporte a
comentários de várias linhas e documentos. Para obter detalhes, consulte
os comentários.
void
Um tipo especial que indica um valor que nunca é usado. Funções como
printInteger() e main() que não retornam explicitamente um valor têm o
tipo void de retorno. Para obter mais informações, consulte este artigo.
int
Outro tipo, indicando um inteiro. Alguns adicionais tipos built-in são
String , List e bool .
42
Um número literal. Literais de número são um tipo de constante de tempo
de compilação.
print()
Uma maneira prática de exibir a saída.
'...' (ou "..." )
Um literal de string.
$ variableName (ou) ${ expression }
Interpolação de string: incluindo uma variável ou equivalente de string de
expressão dentro de um literal de string. Para obter mais informações,
consulte Strings .
main()
A função especial de nível superior necessária onde a execução do
aplicativo começa. Para obter mais informações, consulte A função main().
var
Uma maneira de declarar uma variável sem especificar seu tipo.
Conceitos Importantes
Conforme você aprende sobre a linguagem Dart, mantenha estes fatos e
conceitos em mente:
Tudo o que você pode colocar em uma variável é um objeto, e cada
objeto é uma instância de uma classe. Mesmo números, funções e
null são objetos. Todos os objetos são herdados da classe Object.
Embora o Dart seja fortemente tipado, as anotações de tipos são
opcionais porque o Dart pode inferir tipos. No código acima, number
infere-se que é do tipo int . Quando você quiser dizer explicitamente
que nenhum tipo é esperado, use o tipo especial dynamic.
O Dart suporta tipos genéricos, como List<int> (uma lista de inteiros)
ou List<dynamic> (uma lista de objetos de qualquer tipo).
O Dart oferece suporte a funções de nível superior (como main() ),
bem como funções vinculadas a uma classe ou objeto ( métodos
estáticos 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, bem
como variáveis vinculadas a uma classe ou objeto (variáveis
estáticas e de instância). Variáveis de instância às vezes são
conhecidas como campos ou propriedades.
Ao contrário de Java, Dart não tem as palavras-chave public ,
protected e private . Se um identificador começa com um sublinhado
(_), ele é privado para sua biblioteca. Para obter detalhes, consulte
Bibliotecas e visibilidade.
Os identificadores podem começar com uma letra ou sublinhado (_),
seguido por qualquer combinação desses caracteres mais dígitos.
O Dart tem expressões (que têm valores de tempo de execução) e
instruções (que não têm). Por exemplo, a expressão condicional
condition ? expr1 : expr2 tem um valor de expr1 ou expr2 . Compare
isso com uma instrução if-else , que não tem valor. Uma instrução
geralmente contém uma ou mais expressões, mas uma expressão
não pode conter diretamente uma instrução.
As ferramentas Dart podem relatar dois tipos de problemas: avisos e
erros. Os avisos são apenas indicações de que seu código pode não
funcionar, mas não impedem que seu programa seja executado. Os
erros podem ser em tempo de compilação ou em tempo de
execução. Um erro em tempo de compilação impede que o código
seja executado; um erro em tempo de execução resulta em uma
exceção sendo levantada enquanto o código é executado.
Palavras-Chave
A tabela a seguir lista as palavras que a linguagem Dart trata
especialmente.
abstract 2 else import 2 super
2
as enum in switch
assert export 2 interface 2 sync 1
async 1 extends is this
3 2 2
await extension library throw
break external 2 mixin 2 true
2
case factory new try
catch false null typedef 2
class final on 1 var
2
const finally operator void
2
continue for part while
2 2
covariant Function rethrow with
2
default get return yield 3
deferred 2 hide 1 set 2
do if show 1
dynamic 2 implements 2 static 2
Valor padrão
Variáveis não inicializadas têm um valor inicial de null . Mesmo as
variáveis com tipos numéricos são inicialmente nulas, porque os números
- como tudo o mais no Dart - são objetos.
Final e constante
Se você nunca pretende alterar uma variável, use final ou const , em vez
de var ou em adição a um tipo. Uma variável final pode ser definida
apenas uma vez; uma variável const é uma constante de tempo de
compilação. (Variáveis const são implicitamente finais.) Uma variável final
de nível superior ou classe é inicializada na primeira vez em que é usada.
Use const para variáveis que você deseja que sejam constantes de
tempo de compilação. Se a variável const estiver no nível da classe,
marque-a static const . Onde você declara a variável, defina o valor como
uma constante de tempo de compilação, como um número ou string
literal, uma variável const ou o resultado de uma operação aritmética em
números constantes:
A partir do Dart 2.5, você pode definir constantes que usam verificações e
conversões de tipo ( is e as ), operadores de coleta se e propagação (. .. e
...? ):
Para obter mais informações sobre const como criar valores constantes,
consulte Listas, Mapas e Classes.
Tipos Integrados
A linguagem Dart tem suporte especial para os seguintes tipos:
números
strings
booleanos
listas (também conhecidas como matrizes)
conjuntos
mapas
runas (para expressar caracteres Unicode em uma string)
símbolos
Você pode inicializar um objeto de qualquer um desses tipos especiais
usando um literal. Por exemplo, 'this is a string' é um literal de string e
true é um literal booleano.
Como cada variável no Dart se refere a um objeto - uma instância de uma
classe - você geralmente pode usar construtores para inicializar variáveis.
Alguns dos tipos integrados têm seus próprios construtores. Por exemplo,
você pode usar construtor o Map() para criar um mapa.
Números
Os números de Dart vêm em dois sabores:
int
Valores inteiros não maiores que 64 bits, dependendo da plataforma. No
Dart VM, os valores podem ser de -2 63 a 2 63-1. O Dart compilado para
JavaScript usa números JavaScript, permitindo valores de -2 53 a 2 53-1.
double
Números de ponto flutuante de 64 bits (precisão dupla), conforme
especificado pelo padrão IEEE 754.
Ambos int e double são subtipos de num . O tipo num inclui operadores
básicos, tais como +, -, / e *, e também é onde você vai encontrar abs() ,
ceil() e floor() , entre outros métodos. (Operadores bit a bit, como >>, são
definidos na classe int .) Se num e seus subtipos não tiverem o que você
está procurando, a biblioteca dart:math pode.
Os inteiros são números sem ponto decimal. Aqui estão alguns exemplos
de definição de literais inteiros:
Se um número inclui um decimal, é um double . Aqui estão alguns
exemplos de definição de literais double :
Listas
Talvez a coleção mais comum em quase todas as linguagens de
programação seja a matriz, ou grupo ordenado de objetos. No Dart,
matrizes são objetos List , então a maioria das pessoas os chama de
listas.
Literais de lista de DART parecem literais de listas JavaScript. Aqui está
uma lista simples de Dart:
Conjuntos
Um conjunto no Dart é uma coleção não ordenada de itens exclusivos. O
suporte de DART para conjuntos é fornecido por conjuntos de literais e o
tipo de Conjunto.
Mapas
Em geral, um mapa é um objeto que associa chaves e valores. Tanto as
chaves quanto os valores podem ser qualquer tipo de objeto. Cada chave
ocorre apenas uma vez, mas você pode usar o mesmo valor várias vezes.
O suporte de DART para mapas é fornecido por literais de mapa e o tipo
de mapa.
Aqui estão alguns mapas Dart simples, criados usando literais de mapa:
Símbolos
Um objeto Symbol representa um operador ou identificador declarado em
um programa Dart. Talvez você nunca precise usar símbolos, mas eles
são inestimáveis para APIs que se referem a identificadores por nome,
porque a minificação altera os nomes dos identificadores, mas não os
símbolos dos identificadores.
Para obter o símbolo de um identificador, use um literal de símbolo, que é
apenas # seguido pelo identificador:
Para funções que contêm apenas uma expressão, você pode usar uma
sintaxe abreviada:
Parâmetros
Uma função pode ter qualquer número de parâmetros posicionais
necessários. Eles podem ser seguidos por parâmetros nomeados ou por
parâmetros posicionais opcionais (mas não ambos).
Parâmetros nomeados
Os parâmetros nomeados são opcionais, a menos que sejam
especificamente marcados como obrigatórios.
Ao chamar uma função, você pode especificar parâmetros nomeados
usando paramName: value . Por exemplo:
A função main()
Cada aplicativo deve ter uma função main() de nível superior, que serve
como ponto de entrada para o aplicativo. A função main() retorna void e
tem um parâmetro opcional List<String> para argumentos.
Aqui está um exemplo da função main() de um aplicativo da web:
Este exemplo usa uma função anônima. Mais sobre eles na próxima
seção.
Funções anônimas
A maioria das funções são nomeadas, como main() ou printElement() .
Você também pode criar uma função sem nome chamada função anônima
ou, às vezes, lambda ou encerramento. Você pode atribuir uma função
anônima a uma variável para que, por exemplo, possa adicioná-la ou
removê-la de uma coleção.
Uma função anônima é semelhante a uma função nomeada - zero ou
mais parâmetros, separados por vírgulas e anotações de tipo opcionais,
entre parênteses.
O bloco de código a seguir contém o corpo da função:
O resultado do código é:
Âmbito lexical
Dart é uma linguagem com escopo léxico, o que significa que o escopo
das variáveis é determinado estaticamente, simplesmente pelo layout do
código. Você pode “seguir as chaves para fora” para ver se uma variável
está no escopo.
Aqui está um exemplo de funções aninhadas com variáveis em cada nível
de escopo:
Operadores aritméticos
O Dart suporta os operadores aritméticos usuais, conforme mostrado na
tabela a seguir.
Exemplo:
Outras operadoras
Você viu a maioria dos operadores restantes em outros exemplos:
Para mais informações sobre os operadores . , ?. , e .. , consulte
Classes.
Declarações De Fluxo De Controle
Você pode controlar o fluxo de seu código Dart usando qualquer um
dos seguintes:
if e else
for loops
while e do - while loops
break e continue
switch e case
assert
Você também pode afetar o fluxo de controle usando try-catch e
throw , conforme explicado em Exceções.
If e else
O Dart oferece suporte a instruções if com instruções opcionais
else , como mostra o próximo exemplo. Veja também as expressões
condicionais.
For loops
Você pode iterar com o loop for padrão. Por exemplo:
Os fechamentos dentro dos loops, for do Dart capturam o valor do
índice, evitando uma armadilha comum encontrada no JavaScript.
Por exemplo, considere:
While e do-while
Um loop while avalia a condição antes do loop:
Switch e case
As instruções de switch no Dart comparam constantes de tempo de
compilação, string ou inteiros usando == . Os objetos comparados
devem ser todas instâncias da mesma classe (e não de nenhum de
seus subtipos) e a classe não deve ser substituída == . Os tipos
enumerados funcionam bem em declarações switch .
Cada cláusula case não vazia termina com uma instrução break ,
como regra. Outras formas válidas para acabar com um não-vazia
cláusula case são uma continue , throw ou declaração return .
Use uma cláusula default para executar o código quando nenhuma
cláusula case corresponder:
O exemplo a seguir omite a instrução break em uma cláusula case ,
gerando um erro:
Uma cláusula case pode ter variáveis locais, que são visíveis
apenas dentro do escopo dessa cláusula.
Assert
Durante o desenvolvimento, use uma instrução assert -
assert(condition, optionalMessage) ; - para interromper a execução
normalmente se uma condição booleana for falsa. Você pode
encontrar exemplos de declarações assert ao longo deste tour. Aqui
estão mais alguns:
Para anexar uma mensagem a uma afirmação, adicione uma string
como o segundo argumento para assert (opcionalmente com uma
vírgula no final):
Throw
Aqui está um exemplo de lançamento ou aumento de uma exceção:
Catch
Capturar, ou capturar, uma exceção interrompe a propagação da
exceção (a menos que você relançar a exceção). A captura de uma
exceção dá a você a chance de lidar com ela:
Finally
Para garantir que algum código seja executado, independentemente
de uma exceção ser lançada ou não, use uma cláusula finally . Se
nenhuma cláusula catch corresponder à exceção, a exceção será
propagada após a execução da cláusula finally :
A cláusula finally é executada após qualquer cláusula catch
correspondente:
Usando construtores
Você pode criar um objeto usando um construtor. Os nomes dos
construtores podem ser ClassName ou ClassName.identifier . Por
exemplo, o código a seguir cria objetos Point usando os
construtores Point() e Point.fromJson():
Até aqui, você viu como usar as classes. O restante desta seção
mostra como implementar classes.
Variáveis de instância
Veja como você declara variáveis de instância:
Todas as variáveis de instância não inicializadas têm o valor null .
Todas as variáveis de instância geram um método getter implícito.
Variáveis de instância não finais também geram um método setter
implícito. Para obter detalhes, consulte Getters e setters.
Construtores
Declare um construtor criando uma função com o mesmo nome de
sua classe (mais, opcionalmente, um identificador adicional
conforme descrito em Construtores nomeados). A forma mais comum de
construtor, o construtor generativo, cria uma instância de uma
classe:
A palavra-chave this se refere à instância atual.
Construtores padrão
Se você não declarar um construtor, um construtor padrão será
fornecido para você. O construtor padrão não tem argumentos e
invoca o construtor sem argumento na superclasse.
Construtores não são herdados
As subclasses não herdam construtores de sua superclasse. Uma
subclasse que não declara nenhum construtor possui apenas o
construtor padrão (sem argumento, sem nome).
Construtores nomeados
Use um construtor nomeado para implementar vários construtores
para uma classe ou para fornecer clareza extra:
Lembre-se de que os construtores não são herdados, o que
significa que o construtor nomeado de uma superclasse não é
herdado por uma subclasse. Se você quiser que uma subclasse seja
criada com um construtor nomeado definido na superclasse, você
deve implementar esse construtor na subclasse.
Invocar um construtor de superclasse não padrão
Por padrão, um construtor em uma subclasse chama o construtor
sem nome e sem argumento da superclasse. O construtor da
superclasse é chamado no início do corpo do construtor. Se uma
lista de inicializadores também estiver sendo usada, ela será executada
antes de a superclasse ser chamada. Em resumo, a ordem de
execução é a seguinte:
lista de inicializadores
construtor sem arg da superclasse
construtor sem arg da classe principal
Se a superclasse não tiver um construtor sem nome e sem
argumento, você deverá chamar manualmente um dos construtores
na superclasse. Especifique o construtor da superclasse após dois
pontos ( : ), logo antes do corpo do construtor (se houver).
Como os argumentos para o construtor da superclasse são
avaliados antes de invocar o construtor, um argumento pode ser
uma expressão, como uma chamada de função:
Lista de inicializadores
Além de invocar um construtor de superclasse, você também pode
inicializar variáveis de instância antes que o corpo do construtor seja
executado. Separe os inicializadores com vírgulas.
Construtores constantes
Se sua classe produz objetos que nunca mudam, você pode fazer
esses objetos constantes de tempo de compilação. Para fazer isso,
defina um construtor const e certifique-se de que todas as variáveis
de instância sejam final .
Os construtores constantes nem sempre criam constantes. Para
obter detalhes, consulte a seção sobre como usar construtores.
Construtores de fábrica
Use a palavra-chave factory ao implementar um construtor que nem
sempre cria uma instância de sua classe. Por exemplo, um
construtor de fábrica pode retornar uma instância de um cache ou
pode retornar uma instância de um subtipo. Outro caso de uso para
construtores de fábrica é inicializar uma variável final usando uma
lógica que não pode ser tratada na lista de inicializadores.
No exemplo a seguir, o construtor Logger de fábrica retorna objetos
de um cache e o construtor Logger.fromJson de fábrica inicializa
uma variável final de um objeto JSON.
Invoque um construtor de fábrica como faria com qualquer outro
construtor:
Métodos
Métodos são funções que fornecem comportamento para um objeto.
Métodos de instância
Métodos de instância em objetos podem acessar variáveis de
instância e this . O método distanceTo() no exemplo a seguir é um
exemplo de método de instância:
Operadores
Operadores são métodos de instância com nomes especiais. O Dart
permite que você defina operadores com os seguintes nomes:
Métodos abstratos
Os métodos de instância, getter e setter podem ser abstratos,
definindo uma interface, mas deixando sua implementação para
outras classes. Os métodos abstratos só podem existir em classes
abstratas.
Para tornar um método abstrato, use um ponto-e-vírgula (;) em vez
do corpo do método:
Classes abstratas
Use o modificador abstract para definir uma classe abstrata - uma
classe que não pode ser instanciada. As classes abstratas são úteis
para definir interfaces, geralmente com alguma implementação. Se
você deseja que sua classe abstrata pareça ser instanciada, defina
um construtor de fábrica.
As classes abstratas geralmente possuem métodos abstratos. Aqui
está um exemplo de declaração de uma classe abstrata que possui
um método abstrato:
Interfaces implícitas
Cada classe define implicitamente uma interface contendo todos os
membros da instância da classe e de quaisquer interfaces que ela
implementa. Se você deseja criar uma classe A que suporte a API
da classe B sem herdar a implementação de B, a classe A deve
implementar a interface B.
Uma classe implementa uma ou mais interfaces declarando-as em
uma cláusula implements e fornecendo as APIs exigidas pelas
interfaces. Por exemplo:
Aqui está um exemplo de especificação de que uma classe
implementa várias interfaces:
noSuchMethod()
Para detectar ou reagir sempre que o código tentar usar um método
ou variável de instância inexistente, você pode substituir
noSuchMethod() :
Você não pode invocar um método não implementado, a menos
que uma das opções a seguir seja verdadeira:
O receptor é do tipo estático dynamic .
O receptor tem um tipo estático que define o método não
implementado (abstrato está OK), e o tipo dinâmico do receptor
tem uma implementação noSuchMethod() diferente daquela
da classe Object .
Para obter mais informações, consulte a especificação de
encaminhamento informal noSuchMethod.
Métodos de extensão
Os métodos de extensão, introduzidos no Dart 2.7, são uma forma
de adicionar funcionalidade às bibliotecas existentes. Você pode
usar métodos de extensão mesmo sem saber. Por exemplo, quando
você usa o autocompletar de código em um IDE, ele sugere
métodos de extensão junto com métodos regulares.
Aqui está um exemplo de uso de um método de extensão em String
nomeado parseInt() que é definido em string_apis.dart :
Tipos enumerados
Tipos enumerados, frequentemente chamados de enumerações ou
enums, são um tipo especial de classe usado para representar um
número fixo de valores constantes.
Usando enums
Declare um tipo enumerado usando a palavra-chave enum :
Métodos estáticos
Os métodos estáticos (métodos de classe) não operam em uma
instância e, portanto, não têm acesso a this . Por exemplo:
Você pode usar métodos estáticos como constantes de tempo de
compilação. Por exemplo, você pode passar um método estático
como parâmetro para um construtor de constante.
Genéricos
Se você olhar a documentação da API para o tipo de array básico,
List, verá que o tipo é realmente List<E> . A notação <…> marca List
como um tipo genérico (ou parametrizado) - um tipo que possui
parâmetros de tipo formal. Por convenção, a maioria das variáveis
de tipo têm nomes de uma única letra, como E, T, S, K e V.
Usando bibliotecas
Use import para especificar como um namespace de uma biblioteca
é usado no escopo de outra biblioteca.
Por exemplo, os aplicativos da web Dart geralmente usam a
biblioteca dart:html, que eles podem importar assim:
Implementando bibliotecas
Consulte Criar pacotes de biblioteca para obter conselhos sobre
como implementar um pacote de biblioteca, incluindo:
Como organizar o código-fonte da biblioteca.
Como usar a diretiva export .
Quando usar a diretiva part .
Quando usar a diretiva library .
Como usar importações e exportações condicionais para
implementar uma biblioteca que oferece suporte a várias
plataformas.
Suporte para assincronia
As bibliotecas Dart estão cheias de funções que retornam objetos
Future ou Stream. Essas funções são assíncronas: elas retornam após
a configuração de uma operação possivelmente demorada (como E
/ S), sem esperar que a operação seja concluída.
As palavras-chave async - await e suportam programação
assíncrona, permitindo escrever código assíncrono que se parece
com o código síncrono.
Manipulação de futuros
Quando você precisa do resultado de um Futuro concluído, você
tem duas opções:
Use async e await .
Use a API Future, conforme descrito no tour pela biblioteca.
Código que usa async e await é assíncrono, mas se parece muito
com o código síncrono. Por exemplo, aqui está um código que usa
await para esperar o resultado de uma função assíncrona:
Para usar await , o código deve estar em uma função async - uma
função marcada como async :
Use try , catch e finally para lidar com erros e limpeza no código que
usa await :
Você pode usar várias vezes await em uma função async . Por
exemplo, o código a seguir espera três vezes pelos resultados das
funções:
Se você o alterar para uma função async , por exemplo, porque uma
implementação futura consumirá muito tempo, o valor retornado é um
Futuro:
Observe que o corpo da função não precisa usar a API Future. O Dart cria
o objeto future, se necessário. Se sua função não retornar um valor útil,
faça seu tipo de retorno Future<void> .
Para obter uma introdução interativa sobre o uso de futuros async , e
await , consulte o codelab de programação assíncrona.
Manipulando streams
Quando você precisa obter valores de um fluxo, você tem duas opções:
Use async e um loop for assíncrono ( await for ).
Use a API Stream, conforme descrito no tour pela biblioteca.
Comentários multilinhas
Um comentário de várias linhas começa com /* e termina com */ . Tudo
entre /* e */ é ignorado pelo compilador Dart (a menos que o comentário
seja um comentário de documentação; consulte a próxima seção).
Comentários multilinhas podem ser aninhados.
Comentários de documentação
Comentários de documentação são comentários de várias linhas ou de
uma linha que começam com /// ou /** . Usar /// em linhas consecutivas
tem o mesmo efeito que um comentário de documento com várias linhas.
Dentro de um comentário de documentação, o compilador Dart ignora
todo o texto, a menos que esteja entre colchetes. Usando colchetes, você
pode se referir a classes, métodos, campos, variáveis de nível superior,
funções e parâmetros. Os nomes entre colchetes são resolvidos no
escopo léxico do elemento do programa documentado.
Aqui está um exemplo de comentários de documentação com referências
a outras classes e argumentos:
Este código não é seguro para o tipo porque seria então possível definir
um gato e enviá-lo após um jacaré:
Como alternativa, você pode usar var e deixar o Dart inferir o tipo:
Métodos
Ao substituir um método, as regras do produtor e do consumidor ainda se
aplicam. Por exemplo:
Números
A biblioteca Dart: core define as classes num , int e double , que possuem
alguns utilitários básicos para trabalhar com números.
Você pode converter uma string em um número inteiro ou duplo com o
parse() métodos int e double, respectivamente:
Mais Informações
Consulte a referência da API String para obter uma lista completa de
métodos. Consulte também a referência da API para StringBuffer, Pattern,
RegExp e Match.
Coleções
O Dart é fornecido com uma API de coleções básicas, que inclui classes
para listas, conjuntos e mapas.
Listas
Como mostra o tour pelo idioma, você pode usar literais para criar e
inicializar listas. Como alternativa, use um dos construtores List. A classe
List também define vários métodos para adicionar e remover itens de lista.
Use indexOf() para encontrar o índice de um objeto em uma lista:
Classifique uma lista usando o método sort() . Você pode fornecer uma
função de classificação que compare dois objetos. Esta função de
classificação deve retornar <0 para menor , 0 para o mesmo e> 0 para
maior . O exemplo a seguir usa compareTo() , que é definido por
Comparable e implementado por String.
Listas são tipos parametrizados, então você pode especificar o tipo que
uma lista deve conter:
Consulte a referência da API List para obter uma lista completa de métodos.
Conjuntos
Um conjunto no Dart é uma coleção não ordenada de itens exclusivos. Como um
conjunto não está ordenado, você não pode obter os itens de um conjunto por índice
(posição).
Mapas
Um mapa, comumente conhecido como dicionário ou hash , é uma
coleção não ordenada de pares chave-valor. Os mapas associam uma
chave a algum valor para fácil recuperação. Ao contrário do JavaScript, os
objetos Dart não são mapas.
Você pode declarar um mapa usando uma sintaxe literal concisa ou pode
usar um construtor tradicional:
Para aplicar uma função a cada item em uma lista, conjunto ou mapa,
você pode usar forEach() :
Quando você invoca forEach() em um mapa, sua função deve levar dois
argumentos (a chave e o valor):
Os iteráveis fornecem o método map() , que fornece todos os resultados
em um único objeto:
Para forçar sua função a ser chamada imediatamente em cada item, use
map() .toList() ou map() .toSet() :
URIs
A classe Uri fornece funções para codificar e decodificar strings para uso
em URIs (que você pode conhecer como URLs ). Essas funções tratam
de caracteres que são especiais para URIs, como & e = . A classe Uri
também analisa e expõe os componentes de um URI - host, porta,
esquema e assim por diante.
Codificação e decodificação de URIs totalmente
qualificados
Para codificar e descodificar caracteres exceto aqueles com significado
especial em um URI (tais como / , : , & , # ), utilizar o encodeFull() e
métodos decodeFull() . Esses métodos são bons para codificar ou
decodificar um URI totalmente qualificado, deixando os caracteres URI
especiais intactos.
Consulte a referência da API Uri para mais componentes URI que você pode
obter.
Construindo URIs
Você pode construir um URI a partir de partes individuais usando o
construtor Uri() :
Datas e horas
Um objeto DateTime é um ponto no tempo. O fuso horário é UTC ou o
fuso horário local.
Você pode criar objetos DateTime usando vários construtores:
A propriedade millisecondsSinceEpoch de uma data retorna o número de
milissegundos desde a “época Unix” —1 de janeiro de 1970, UTC:
Use a classe Duration para calcular a diferença entre duas datas e para
mudar uma data para frente ou para trás:
Para obter uma lista completa de métodos, consulte a referência da API
para DateTime e Duration.
Classes de utilidades
A biblioteca principal contém várias classes de utilitários, úteis para
classificar, mapear valores e iterar.
Comparando objetos
Implemente a interface Comparable para indicar que um objeto pode ser
comparado a outro objeto, geralmente para classificação. O método
compareTo() retorna <0 para menor , 0 para o mesmo e> 0 para maior .
Implementando chaves de mapa
Cada objeto no Dart fornece automaticamente um código hash inteiro e,
portanto, pode ser usado como uma chave em um mapa. No entanto,
você pode substituir o getter hashCode para gerar um código hash
personalizado. Se você fizer isso, também poderá substituir o operador
== . Os objetos que são iguais (via == ) devem ter códigos hash idênticos.
Um código hash não precisa ser exclusivo, mas deve ser bem distribuído.
Iteração
As classes Iterable e Iterator oferecem suporte a loops for-in. Estenda (se
possível) ou implemente Iterable sempre que criar uma classe que possa
fornecer Iteradores para uso em loops for-in. Implemente o Iterator para
definir a capacidade real de iteração.
Exceções
A biblioteca central do Dart define muitas exceções e erros comuns. As
exceções são consideradas condições que você pode planejar com
antecedência e capturar. Erros são condições que você não espera ou
planeja.
Alguns dos erros mais comuns são:
NoSuchMethodError
Lançado quando um objeto receptor (que pode ser nulo) não implementa
um método.
ArgumentError
Pode ser lançado por um método que encontra um argumento
inesperado.
Lançar uma exceção específica do aplicativo é uma maneira comum de
indicar que ocorreu um erro. Você pode definir uma exceção
personalizada implementando a interface Exception:
Para obter mais informações, consulte Exceções (no tour pelo idioma) e a
referência da API de exceção.
dart:async - Programação Assíncrona
A programação assíncrona geralmente usa funções de retorno de
chamada, mas o Dart oferece alternativas: Objetos Future e Stream. Um
futuro é como uma promessa de um resultado a ser fornecido em algum
momento no futuro. Um Stream é uma forma de obter uma sequência de
valores, como eventos. Future, Stream e muito mais estão na biblioteca
dart:async (referência de API).
Futuro
Objetos futuros aparecem em todas as bibliotecas Dart, geralmente como
o objeto retornado por um método assíncrono. Quando um futuro se
completa , seu valor está pronto para ser usado.
Usando o await
Antes de usar diretamente a API Future, considere usá-la await . O código
que usa expressões await pode ser mais fácil de entender do que o
código que usa a API Future.
Considere a seguinte função. Ele usa o método then() de future para
executar três funções assíncronas seguidas, esperando que cada uma
seja concluída antes de executar a próxima.
O código equivalente com expressões await se parece mais com o código
síncrono:
Corrente
Objetos de fluxo aparecem em todas as APIs do Dart, representando
sequências de dados. Por exemplo, eventos HTML, como cliques em
botões, são entregues por meio de fluxos. Você também pode ler um
arquivo como um fluxo.
Usando um loop for assíncrono
Às vezes, você pode usar um loop ( await for ) for assíncrono em vez de
usar a API de fluxo.
Considere a seguinte função. Ele usa o listen() método do Stream para
assinar uma lista de arquivos, passando um literal de função que pesquisa
cada arquivo ou diretório.
O código equivalente com expressões await, incluindo um loop ( await
for ) assíncrono, se parece mais com o código síncrono:
Mais Informações
Para alguns exemplos de uso do Future e Stream em aplicativos de linha
de comando, consulte o tour dart:io. Veja também estes artigos, codelabs e
tutoriais:
Programação assíncrona: futuros, assíncronos, aguardar
Futuros e tratamento de erros
Programação assíncrona: fluxos
Criação de fluxos no Dart
Programação assíncrona Dart: isola e loops de evento
dart:math - matemática e aleatório
A biblioteca dart:math (referência da API ) fornece funcionalidades comuns,
como seno e cosseno, máximo e mínimo, e constantes como pi e. A
maior parte da funcionalidade da biblioteca de matemática é
implementada como funções de nível superior.
Para usar esta biblioteca em seu aplicativo, importe dart:math.
Trigonometria
A biblioteca de matemática fornece funções trigonométricas básicas:
Máximo e mínimo
A biblioteca de matemática fornece métodos max() e min() :
Constantes matemáticas
Encontre suas constantes favoritas - pi , e mais - na biblioteca de
matemática:
Números aleatórios
Gere números aleatórios com a classe Random. Você pode opcionalmente
fornecer uma semente para o construtor Random.
Mais Informações
Consulte a referência da API de matemática para obter uma lista completa de
métodos. Consulte também a referência da API para num, int e double.
dart: convert - Decodificação E Codificação
Json, Utf-8 E Mais
A biblioteca dart:convert ( referência da API ) tem conversores para JSON e
UTF-8, bem como suporte para a criação de conversores adicionais. JSON
é um formato de texto simples para representar coleções e objetos
estruturados. UTF-8 é uma codificação comum de largura variável que
pode representar todos os caracteres no conjunto de caracteres Unicode.
Para usar esta biblioteca, importe dart:convert.
Outras funcionalidades
A biblioteca dart:convert também possui conversores para ASCII e ISO-
8859-1 (Latin1). Para obter detalhes, consulte a referência da API para a
biblioteca dart:convert.
dart: html - Aplicativos Baseados Em
Navegador
Use a biblioteca dart:html para programar o navegador, manipular objetos e
elementos no DOM e acessar APIs HTML5. DOM significa Document
Object Model , que descreve a hierarquia de uma página HTML.
Outros usos comuns de dart: html são manipular estilos (CSS), obter
dados usando solicitações HTTP e trocar dados usando WebSockets.
HTML5 (e dart: html) tem muitas APIs adicionais que esta seção não
cobre. Apenas aplicativos da web podem usar dart: html, não aplicativos
de linha de comando.
Para usar a biblioteca HTML em seu aplicativo da web, importe dart: html:
Manipulando o DOM
Para usar o DOM, você precisa saber sobre janelas , documentos ,
elementos e nós .
Um objeto Window representa a janela real do navegador da web. Cada
janela tem um objeto Documento, que aponta para o documento que está
carregado no momento. O objeto Window também tem acessadores para
várias APIs, como IndexedDB (para armazenamento de dados),
requestAnimationFrame (para animações) e muito mais. Em navegadores
com guias, cada guia tem seu próprio objeto Janela.
Com o objeto Document, você pode criar e manipular objetos Element dentro
do documento. Observe que o próprio documento é um elemento e pode
ser manipulado.
O DOM modela uma árvore de nós. Esses nós geralmente são elementos,
mas também podem ser atributos, texto, comentários e outros tipos de
DOM. Exceto pelo nó raiz, que não tem pai, cada nó no DOM tem um pai
e pode ter muitos filhos.
Encontrando elementos
Para manipular um elemento, você precisa primeiro de um objeto que o
represente. Você pode obter este objeto usando uma consulta.
Encontre um ou mais elementos usando as funções de nível superior
querySelector() e querySelectorAll() . Você pode consultar por ID, classe,
tag, nome ou qualquer combinação destes. O guia CSS Selector Specification
define os formatos dos seletores, como o uso de um prefixo # para
especificar IDs e um ponto (.) para classes.
A função querySelector() retorna o primeiro elemento que corresponde ao
seletor, enquanto querySelectorAll() retorna uma coleção de elementos
que correspondem ao seletor.
Manipulando elementos
Você pode usar propriedades para alterar o estado de um elemento. Nó e
seu subtipo Elemento definem as propriedades de todos os elementos.
Por exemplo, todos os elementos têm classes , hidden , id , style , e title
propriedades que você pode usar para estado set. As subclasses de
Element definem propriedades adicionais, como a propriedade href de
AnchorElement.
Considere este exemplo de especificação de um elemento âncora em
HTML:
Tratamento de eventos
Para responder a eventos externos, como cliques, mudanças de foco e
seleções, adicione um ouvinte de eventos. Você pode adicionar um
ouvinte de evento a qualquer elemento da página. O envio e propagação
de eventos é um assunto complicado; pesquise os detalhes se você for novo
na programação da web.
Adicione um manipulador de eventos usando
element.onEvent.listen(function) , onde é o nome do evento Eventfunction
é o manipulador de eventos.
Por exemplo, veja como você pode lidar com cliques em um botão:
Para ver todos os eventos para os quais você pode registrar um ouvinte
de evento, procure as propriedades “onEventType” nos documentos da
API para Element e suas subclasses. Alguns eventos comuns incluem:
mudança
borrão
keyDown
keyUp
mouseDown
mouseUp
Você também pode usar a API completa para lidar com casos mais
interessantes. Por exemplo, você pode definir cabeçalhos arbitrários.
O fluxo geral para usar a API completa de HttpRequest é o seguinte:
1. Crie o objeto HttpRequest.
2. Abra o URL com GET ou POST .
3. Anexe manipuladores de eventos.
4. Envie o pedido.
Por exemplo:
Enviando dados para o servidor
HttpRequest pode enviar dados para o servidor usando o método HTTP
POST. Por exemplo, você pode desejar enviar dados dinamicamente a um
manipulador de formulários. O envio de dados JSON para um serviço da
Web REST ful é outro exemplo comum.
O envio de dados a um manipulador de formulários requer que você
forneça pares nome-valor como strings codificadas por URI. (Informações
sobre a classe URI estão na seção URIs do Dart Library Tour.) Você
também deve definir o cabeçalho Content-type como application/x-www-
form-urlencode se deseja enviar dados a um manipulador de formulários.
Recebendo dados
Para receber dados no WebSocket, registre um ouvinte para eventos de
mensagem:
Arquivos e diretórios
A biblioteca de I/O permite que aplicativos de linha de comando leiam e
gravem arquivos e naveguem em diretórios. Você tem duas opções para
ler o conteúdo de um arquivo: tudo de uma vez ou streaming. Ler um
arquivo de uma vez requer memória suficiente para armazenar todo o
conteúdo do arquivo. Se o arquivo for muito grande ou se você quiser
processá-lo durante a leitura, use um Stream, conforme descrito em
Streaming de conteúdo do arquivo.
Lendo um arquivo como texto
Ao ler um arquivo de texto codificado em UTF-8, você pode ler todo o
conteúdo do arquivo com readAsString() . Quando as linhas individuais
são importantes, você pode usar readAsLines() . Em ambos os casos, um
objeto future é retornado, fornecendo o conteúdo do arquivo como uma ou
mais strings.
Lendo um arquivo como binário
O código a seguir lê um arquivo inteiro como bytes em uma lista de ints. A
chamada para readAsBytes() retorna um Future, que fornece o resultado
quando disponível.
Tratamento de erros
Para capturar erros para que eles não resultem em exceções não
detectadas, você pode registrar um manipulador catchError no Future ou
(em uma função async ) usar try-catch:
Mais Informações
Esta página mostrou como usar os principais recursos da biblioteca dart:io.
Além das APIs discutidas nesta seção, a biblioteca dart:io também fornece
APIs para processos, sockets e web sockets. Para obter mais informações
sobre o desenvolvimento de aplicativos do lado do servidor e de linha de
comando, consulte a visão geral do Dart do lado do servidor.
Para obter informações sobre outras bibliotecas dart: *, consulte o tour da
biblioteca.
Resumo
Esta página apresentou a funcionalidade mais comumente usada nas
bibliotecas integradas do Dart. Não cobriu todas as bibliotecas integradas,
no entanto. Outros que você pode querer examinar incluem dart:collection e
dart:typed_data, bem como bibliotecas específicas de plataforma, como as
bibliotecas de desenvolvimento web Dart e as bibliotecas Flutter.
Você pode obter ainda mais bibliotecas usando o gerenciador de pacotes pub.
As bibliotecas de coleção, criptografia, http, intl e teste são apenas uma amostra
do que você pode instalar usando o pub.
Para saber mais sobre a linguagem Dart, consulte o tour de idiomas.
Core Libraries: Articles: introdução à
biblioteca dart:io
Escrito por Mads Ager em março de 2012 (atualizado em setembro de 2018)
A biblioteca dart:io é voltada para o código executado no Flutter e na VM
autônoma do Dart. Neste artigo, daremos uma ideia do que atualmente é
possível com o dart:io, passando por alguns exemplos.
Observe que exitCode pode ser concluído antes que todas as linhas de
saída tenham sido processadas. Observe também que não fechamos
explicitamente o processo. Para não vazar recursos, temos que ouvir os
streams stderr e stdout. Nós usamos await for para ouvir stdout, e
stderr.drain() para ouvir (e descarte) stderr.
Em vez de imprimir a saída em stdout, podemos usar as classes de
streaming para canalizar a saída do processo para um arquivo.
Escrevendo Servidores Web
dart:io torna mais fácil escrever servidores e clientes HTTP. Para escrever
um servidor web simples, tudo que você precisa fazer é criar um
HttpServer e conectar um ouvinte (usando await for ) a seu fluxo de
HttpRequest s.
Aqui está um servidor web simples que responde 'Olá, mundo' a qualquer
solicitação.
Para ver os eventos rapidamente, você pode usar um código como este:
Como antes, você pode usar o stream retornado por timedCounter() desta
forma:
Como
Criação de pacotes
Publicação de pacotes
Referência
Dependências de pub
Variáveis de ambiente do pub
Glossário de pub
Convenções de layout de pacote de pub
Filosofia de versionamento de pub
Formato Pubspec
Comandos pub
A ferramenta pub fornece os seguintes comandos:
pub cache
pub deps
pub downgrade
pub get
pub global
pub outdated
pub publish
pub run
pub upgrade
pub uploader
Para uma visão geral de todos os comandos pub , consulte a
documentação da ferramenta pub.
Solução de problemas
A solução de problemas pub fornece soluções para problemas que você
pode encontrar ao usar o pub.
Packages: Pacotes comumente usados
Esta página lista alguns dos pacotes mais populares e úteis que os
desenvolvedores do DART publicaram. Para encontrar mais pacotes - e
pesquisar bibliotecas centrais, também - use o site pub.dev.
Os pacotes comumente usados se enquadram em três grupos:
Pacotes de uso geral
Pacotes que se expandem nas bibliotecas centrais do Dart
Pacotes especializados
Pacotes De Uso Geral
Os pacotes a seguir são úteis para uma ampla variedade de projetos.
APIs comumente
Pacote Descrição
usadas
Archive, ArchiveFile,
Codifica e decodifica vários TarEncoder,
archive formatos de arquivo e TarDecoder,
compressão. ZipEncoder,
ZipDecoder
Manipulação de string para
String.characters,
caracteres percebidos pelo
characters Characters,
usuário (clusters de grafemas
CharacterRange
Unicode).
Um conjunto de funções e
delete(), get(), post(),
http classes de alto nível que facilitam
read()
o consumo de recursos HTTP.
Facilidades de
internacionalização e localização,
Bidi, DateFormat,
com suporte para plurais e
intl MicroMoney,
gêneros, formatação e análise de
TextDirection
data e número e texto
bidirecional.
Um pacote de geração de código
fácil de usar. Para obter mais
json_serializable @JsonSerializable
informações, consulte Suporte
JSON.
Um mecanismo configurável para
LoggerHandler, Level,
logging adicionar registro de mensagens
LogRecord
ao seu aplicativo.
Uma estrutura popular para
simulação de objetos em testes.
Answering,
Especialmente útil se você estiver
mockito Expectation,
escrevendo testes para injeção de
Verification
dependência. Usado com o
pacote de teste.
path Operações comuns para absolute(),
manipular diferentes tipos de basename(),
caminhos. Para obter mais extension(), join(),
informações, consulte Unboxing normalize(), relative(),
Packages: path. split()
CountdownTimer
(quiver.async);
Utilitários que tornam o uso das MapCache
principais bibliotecas Dart mais (quiver.cache);
conveniente. Algumas das MultiMap, TreeSet
bibliotecas onde o Quiver fornece (quiver.collection);
quiver
suporte adicional incluem EnumerateIterable
assíncrono, cache, coleção, (quiver.iterables);
núcleo, iteráveis, padrões e center(),
testes. compareIgnoreCase(),
isWhiteSpace()
(quiver.strings)
Middleware de servidor da Web
para Dart. O Shelf facilita a Cascade, Pipeline,
shelf criação e composição de Request, Response,
servidores da web e partes de Server
servidores da web.
Métodos para analisar,
inspecionar e manipular
rastreamentos de pilha
produzidos pela implementação
Dart subjacente. Também fornece
funções para produzir Trace.current(),
stack_trace representações de string de Trace.format(),
rastreamentos de pilha em um Trace.from()
formato mais legível do que a
implementação StackTrace
nativa. Para obter mais
informações, consulte Unboxing
Packages: stack_trace.
Um gerador de projeto Dart. O
WebStorm e o IntelliJ usam Geralmente usado
modelos do Stagehand quando por meio de um IDE
stagehand
você cria um aplicativo, mas você ou do comando
também pode usar os modelos da stagehand .
linha de comando.
teste Uma maneira padrão de escrever expect(), group(),
e executar testes no Dart. test()
loadYaml(),
yaml Um analisador para YAML.
loadYamlStream()
Pacotes Que Se Expandem Nas Bibliotecas
Centrais Do Dart
Cada um dos pacotes a seguir se baseia em uma biblioteca central,
adicionando funcionalidade e preenchendo os recursos ausentes:
APIs comumente
Pacote Descrição
usadas
AsyncMemoizer,
Expande em dart:async, adicionando CancelableOperation,
classes de utilitário para trabalhar com FutureGroup,
async cálculos assíncronos. Para obter mais LazyStream, Result,
informações, consulte Unboxing StreamCompleter,
Packages: async part 1, part 2 e part 3. StreamGroup,
StreamSplitter
Equality,
Expande em coleção Dart, adicionando
CanonicalizedMap,
funções de utilitário e classes para tornar
MapKeySet,
collection o trabalho com coleções mais fácil. Para
MapValueSet,
obter mais informações, consulte
PriorityQueue,
Unboxing Packages: collection.
QueueList
Expande no Dart: converte, adicionando
codificadores e decodificadores para
converter entre diferentes representações
HexDecoder,
convert de dados. Uma das representações de
PercentDecoder
dados é a codificação percentual ,
também conhecida como codificação de
URL .
Contém duas bibliotecas, ansi e io, para
copyPath(),
simplificar o trabalho com arquivos, fluxos
isExecutable(),
padrão e processos. Use a biblioteca ansi
io ExitCode,
para personalizar a saída do terminal. A
ProcessManager,
biblioteca io possui APIs para lidar com
sharedStdIn
processos, stdin e duplicação de arquivos.
Pacotes Especializados
Aqui estão algumas dicas para encontrar pacotes mais especializados,
como pacotes para celular (Flutter) e desenvolvimento web.
Pacotes Flutter
O Flutter suporta o uso de pacotes compartilhados contribuídos por outros
desenvolvedores para os ecossistemas Flutter e Dart. Isso permite
construir rapidamente um aplicativo sem ter que desenvolver tudo do zero.
Os pacotes existentes permitem muitos casos de uso, por exemplo, fazer
solicitações de rede (http), navegação / manipulação de rota
personalizada (fluro), integração com APIs de dispositivo (url_launcher e
battery) e usar SDKs de plataforma de terceiros como Firebase (FlutterFire
).
Para escrever um novo pacote, consulte desenvolvimento de pacotes. Para
adicionar ativos, imagens ou fontes, sejam armazenados em arquivos ou
pacotes, consulte Adicionando ativos e imagens.
Usando pacotes
A seção a seguir descreve como usar os pacotes publicados existentes.
Procurando por pacotes
Os pacotes são publicados em pub.dev.
A página inicial do Flutter em pub.dev exibe os principais pacotes compatíveis
com o Flutter (aqueles que declaram dependências geralmente
compatíveis com o Flutter) e oferece suporte à pesquisa entre todos os
pacotes publicados.
A página Favoritos do Flutter em pub.dev lista os plug-ins e pacotes que
foram identificados como pacotes que você deve primeiro considerar o
uso ao escrever seu aplicativo. Para obter mais informações sobre o que
significa ser um favorito do Flutter, consulte o programa Favoritos do Flutter.
Você também pode navegar pelos pacotes no pub.dev filtrando por plug-ins
do Android, plug-ins do iOS, plug-ins da web ou qualquer combinação deles.
Adicionar uma dependência de pacote a um aplicativo
Para adicionar o pacote, css_colors a um aplicativo:
1. Depende disso
Abra o arquivo pubspec.yaml localizado dentro da pasta do aplicativo e
adicione css_colors: em dependencies .
2. Instale-o
Do terminal: Execute flutter pub get .
OU
No Android Studio / IntelliJ: Clique em Pacotes para entrar na faixa de
opções de ação na parte superior de pubspec.yaml .
Do VS Code: Clique em Get Packages localizado no lado direito da faixa de
ação na parte superior de pubspec.yaml .
3. Importar
Adicione uma instrução import correspondente no código Dart.
4. Pare e reinicie o aplicativo, se necessário
Se o pacote traz código específico da plataforma (Kotlin / Java para Android,
Swift / Objective-C para iOS), esse código deve ser integrado ao seu
aplicativo. O recarregamento e a reinicialização a quente atualizam apenas
o código do Dart, portanto, pode ser necessário reiniciar totalmente o
aplicativo para evitar erros, como MissingPluginException ao usar o pacote.
A guia instalando, disponível em qualquer página de pacote em pub.dev, é
uma referência útil para essas etapas.
Para um exemplo completo, veja o exemplo css_colors abaixo.
Resolução de conflitos
Suponha que você queira usar some_package e another_package em um
aplicativo, e ambos dependem url_launcher, mas em versões diferentes.
Isso causa um conflito potencial. A melhor maneira de evitar isso é os
autores do pacote usarem intervalos de versão em vez de versões
específicas ao especificar dependências.
Dependência Git
Você também pode depender de um pacote armazenado em um
repositório Git. Se o pacote estiver localizado na raiz do repo, use a
seguinte sintaxe:
Dependência do Git em um pacote em uma pasta
A ferramenta pub assume que o pacote está localizado na raiz do
repositório Git. Se não for esse o caso, especifique a localização com o
argumento path. Por exemplo:
3. Execute no terminal flutter pub get ou clique em Packages para obter no IntelliJ ou
Android Studio.
4. Abra lib/main.dart e substitua todo o seu conteúdo por:
3. Execute flutter pub get no terminal ou clique em Pacotes para obter no IntelliJ ou
Android Studio.
4. Abra lib/main.dart e substitua todo o seu conteúdo pelo seguinte:
Pacotes da web
Consulte bibliotecas e pacotes da Web. Ou use o site pub.dev para
pesquisar pacotes da web.
Arquivos importantes
Pub usa o conteúdo de alguns arquivos para criar uma página para seu
pacote em pub.dev/packages/<your_package> . Aqui estão os arquivos que
afetam a aparência da página do seu pacote:
README.md: O arquivo README.md é o conteúdo principal
apresentado na página do seu pacote. O conteúdo do arquivo é
renderizado como Markdown.
CHANGELOG.md: O arquivo CHANGELOG.md do seu pacote, se
encontrado, também é apresentado em uma guia na página do seu
pacote, para que os desenvolvedores possam lê-lo diretamente do
pub.dev. O conteúdo do arquivo é renderizado como Markdown.
O pubspec: O arquivo pubspec.yaml do seu pacote é usado para
preencher detalhes sobre o seu pacote no lado direito da página do
pacote, como sua descrição, página inicial etc.
Realizando um ensaio
Para testar como pub publish funcionará, você pode realizar uma simulação:
Publicação
Quando estiver pronto para publicar seu pacote, remova o argumento --
dry-run :
Depois que um pacote foi transferido para um editor, você pode atualizar
o pacote usando pub publish .
Após o upload do seu pacote para pub.dev com êxito, qualquer usuário do
pub pode fazer o download ou depender dele em seus projetos. Por
exemplo, se você acabou de publicar a versão 1.0.0 do seu pacote
transmogrify , outro desenvolvedor Dart pode adicioná-lo como uma
dependência em pubspec.yaml :
SDK
A origem do SDK é usada para quaisquer SDKs enviados junto com os
pacotes, que podem ser dependências. Atualmente, Flutter é o único SDK
compatível.
A sintaxe é semelhante a esta:
O identificador após sdk: indica de qual SDK o pacote vem. Se for flutter , a
dependência é satisfatória, desde que:
Pub está sendo executado no contexto do executável flutter
O Flutter SDK contém um pacote com o nome fornecido
A versão desse pacote corresponde à restrição de versão
Se for um identificador desconhecido, a dependência é sempre
considerada insatisfeita.
Um pacote com uma dependência sdk deve ter uma restrição Dart SDK
com uma versão mínima de pelo menos 1.19.0. Essa restrição garante
que as versões mais antigas do pub não instalem pacotes que tenham
dependências sdk .
Pacotes hospedados
Um pacote hospedado é aquele que pode ser baixado do site pub.dev
(ou de outro servidor HTTP que fala a mesma API). Aqui está um exemplo
de declaração de uma dependência em um pacote hospedado:
Pacotes Git
Às vezes, você vive no limite e precisa usar pacotes que ainda não foram
lançados formalmente. Talvez seu próprio pacote ainda esteja em
desenvolvimento e esteja usando outros pacotes que estão sendo
desenvolvidos ao mesmo tempo. Para tornar isso mais fácil, você pode
depender diretamente de um pacote armazenado em um repositório Git.
O git aqui diz que este pacote é encontrado usando Git, e a URL depois
disso é a URL do Git que pode ser usada para clonar o pacote.
Mesmo se o repo do pacote for privado, se você puder se conectar ao
repo usando SSH, poderá depender do pacote usando o URL SSH do
repo:
O ref pode ser qualquer coisa que o Git permitir para identificar um
commit.
Pub assume que o pacote está na raiz do repositório Git. Para especificar
um local diferente no repo, use o argumento path :
Pacotes de caminho
Às vezes, você se pega trabalhando em vários pacotes relacionados ao
mesmo tempo. Talvez você esteja criando uma estrutura enquanto
constrói um aplicativo que a usa. Nesses casos, durante o
desenvolvimento, você realmente deseja depender da versão ativa desse
pacote em seu sistema de arquivos local. Dessa forma, as alterações em
um pacote são instantaneamente detectadas por aquele que depende
dele.
Para lidar com isso, pub oferece suporte a dependências de caminho .
Como a sintaxe circunflexa foi introduzida no Dart 1.8.3, ela requer uma
restrição do SDK (usando a sintaxe tradicional) para garantir que as
versões anteriores do pub não tentem processá-la. Por exemplo:
Sintaxe tradicional
Uma restrição de versão que usa sintaxe tradicional é uma série do
seguinte:
any
A string any permite qualquer versão. Isso é equivalente a uma
restrição de versão vazia, mas é mais explícito. Embora any seja
permitido, não o recomendamos.
1.2.3
Um número de versão concreto fixa a dependência para permitir
apenas aquela versão exata . EVITAR usar isso quando puder,
porque pode causar bloqueio de versão para seus usuários e
dificultar o uso de seu pacote junto com outros pacotes que também
dependem dele.
>=1.2.3
Permite a versão fornecida ou qualquer outra superior. Você
normalmente usará isso.
>1.2.3
Permite qualquer versão maior do que a especificada, mas não a
própria versão.
<=1.2.3
Permite qualquer versão menor ou igual à especificada. Você
normalmente não vai usar isso.
<1.2.3
Permite qualquer versão inferior à especificada, mas não a própria
versão. Isso é o que você normalmente usará porque permite
especificar a versão superior que você sabe que não funciona com
o seu pacote (porque é a primeira versão a apresentar algumas
alterações importantes).
Você pode especificar as partes da versão como quiser e seus intervalos
são interceptados. Por exemplo, '>=1.2.3 <2.0.0' permite qualquer versão de
1.2.3 a se 2.0.0 excluir 2.0.0 . Uma maneira mais fácil de expressar esse
intervalo é usando a sintaxe de circunflexo ou ^1.2.3 .
Dependências Dev
Pub oferece suporte a dois tipos de dependências: dependências
regulares e dependências de desenvolvimento. As dependências de
desenvolvimento diferem das dependências regulares em que as
dependências de desenvolvimento de pacotes dos quais você depende
são ignoradas . Aqui está um exemplo:
Digamos que o pacote transmogrify use o pacote test em seus testes e
apenas em seus testes. Se alguém quiser apenas usar transmogrify —
importar suas bibliotecas — realmente não precisa test . Nesse caso, ele é
especificado test como uma dependência dev. Seu pubspec terá algo
como:
O Pub obtém todos os pacotes dos quais seu pacote depende, e tudo de
que esses pacotes dependem, transitivamente. Ele também obtém as
dependências dev do seu pacote, mas ignora as dependências dev de
quaisquer pacotes dependentes. O Pub obtém apenas as dependências
de desenvolvimento do seu pacote. Então, quando seu pacote depender,
transmogrify ele vai pegar, transmogrify, mas não vai test .
A regra para decidir entre uma dependência regular ou dev é simples: se
a dependência for importada de algo em seus diretórios lib ou bin , ela
precisa ser uma dependência regular. Se for importado apenas de test ,
example etc., pode e deve ser uma dependência dev.
Usar dependências de dev torna os gráficos de dependências menores.
Isso torna a execução pub mais rápida e torna mais fácil encontrar um
conjunto de versões de pacote que satisfaça todas as restrições.
Modificações De Dependência
Você pode usar dependency_overrides para substituir temporariamente todas
as referências a uma dependência.
Por exemplo, talvez você esteja atualizando uma cópia local do
transmogrify, um pacote de biblioteca publicado. O transmogrify é usado
por outros pacotes em seu gráfico de dependência, mas você não quer
clonar cada pacote localmente e alterar cada pubspec para testar sua
cópia local do transmogrify.
Nessa situação, você pode substituir a dependência usando
dependency_overrides para especificar o diretório que contém a cópia local do
pacote.
O pubspec seria parecido com o seguinte:
Inclua um arquivo CHANGELOG.md que tenha uma seção para cada versão
do seu pacote, com notas para ajudar os usuários na atualização do seu
pacote. Os usuários do seu pacote frequentemente revisam o changelog
para descobrir correções de bugs e novos recursos, ou para determinar
quanto esforço será necessário para atualizar para a versão mais recente
do seu pacote.
Para oferecer suporte a ferramentas de análise CHANGELOG.md , use o
seguinte formato:
Cada versão possui sua própria seção com um título.
Os títulos das versões são todos de nível 1 ou todos de nível 2.
O texto do cabeçalho da versão contém um número de versão do
pacote, opcionalmente prefixado com “v”.
Quando você enviar o seu pacote para o local pub.dev, do seu pacote de
arquivo CHANGELOG.md (se houver) aparece no Changelog guia, rendida
como Markdown.
Aqui está um exemplo de arquivo CHANGELOG.md . Como mostra o
exemplo, você pode adicionar subseções.
Diretórios Públicos
Dois diretórios em seu pacote são públicos para outros pacotes: lib e
bin . Você coloca bibliotecas públicas em lib e ferramentas públicas em
bin .
Bibliotecas públicas
A seguinte estrutura de diretório mostra a lib parte da enchilada:
Ferramentas públicas
Os scripts do DART colocados dentro do diretório bin são públicos. Se
você estiver dentro do diretório de um pacote, poderá usar pub run para
executar scripts dos diretórios bin de qualquer outro pacote do qual o
pacote dependa. De qualquer diretório, você pode usar pub global run
para executar scripts de pacotes que ativou usando pub global activate .
Se você deseja que seu pacote seja confiável e deseja que seus scripts
sejam privados para seu pacote, coloque-os no diretório tool de nível
superior. Se você não deseja que seu pacote seja dependente, você pode
deixar seus scripts em bin .
Bens Públicos
O nome que você usa aqui (neste caso enchilada ) é o nome que você
específica para o seu pacote em seu pubspec.
Arquivos Da Web
Cada pacote deve ter testes. Com o pub, a convenção é que eles vão
para um diretório test (ou algum diretório dentro dele, se preferir) e tenham
_test no final seus nomes de arquivo.
Normalmente, eles usam o pacote de teste.
Se você tem código e testes, a próxima parte que você pode querer é
uma boa documentação. Isso vai dentro de um diretório chamado doc .
Quando você executa a ferramenta dartdoc, ela coloca a documentação
da API, por padrão, em doc/api . Como a documentação da API é gerada a
partir do código-fonte, você não deve colocá-la sob controle do código-
fonte.
Além do gerado api , não temos quaisquer diretrizes sobre o formato ou
organização da documentação de sua autoria. Use o formato de
marcação de sua preferência.
Exemplos
version
Obrigatório para pacotes hospedados no site pub.dev.
description
Obrigatório para pacotes hospedados no site pub.dev.
homepage
Opcional. URL apontando para a página inicial do pacote (ou repositório de
código-fonte).
repository
Opcional. URL apontando para o repositório de código-fonte do pacote.
issue_tracker
Opcional. URL apontando para um rastreador de problemas para o pacote.
documentation
Opcional. URL apontando para a documentação do pacote.
dependencies
Pode ser omitido se seu pacote não tiver dependências.
dev_dependencies
Pode ser omitido se o seu pacote não tiver dependências de desenvolvimento.
dependency_overrides
Pode ser omitido se você não precisar substituir nenhuma dependência.
environment
Exigido a partir do Dart 2.
executables
Opcional. Usado para colocar os executáveis de um pacote em seu PATH.
publish_to
Opcional. Especifique onde publicar um pacote.
Pub ignora todos os outros campos,
Se você adicionar um campo personalizado, dê a ele um nome exclusivo
que não entre em conflito com os campos futuros do pubspec. Por
exemplo, em vez de adicionar bugs , você pode adicionar um campo
chamado my_pkg_bugs .
Exemplo
Um pubspec simples, mas completo, é parecido com o seguinte:
Detalhes
Esta seção contém mais informações sobre a maioria dos campos
pubspec.
Nome
Todo pacote precisa de um nome. É como outros pacotes se referem ao
seu e como ele aparece para o mundo, caso você o publique.
O nome deve estar todo em letras minúsculas, com sublinhados para
separar as palavras just_like_this . Use apenas letras latinas básicas e
algarismos arábicos: [a-z0-9_] . Além disso, certifique-se de que o nome
seja um identificador DART válido - que não comece com dígitos e não
seja uma palavra reservada.
Tente escolher um nome que seja claro, conciso e que ainda não esteja
em uso. Recomenda -se uma rápida pesquisa de pacotes no site pub.dev
para se certificar de que nada mais está usando seu nome.
Versão
Cada pacote possui uma versão. Um número de versão é necessário para
hospedar seu pacote no site pub.dev, mas pode ser omitido para pacotes
apenas locais. Se você o omitir, seu pacote terá versão implicitamente
0.0.0 .
O controle de versão é necessário para reutilizar o código enquanto
permite que ele evolua rapidamente. Um número de versão são três
números separados por pontos, como 0.2.43 . Ele também pode,
opcionalmente, ter uma configuração ( +1 , +2 , +hotfix.oopsie ) ou de pré-
lançamento ( -dev.4 , -alpha.12 , -beta.7 , -rc.5 ) sufixo.
Cada vez que você publica seu pacote, você o publica em uma versão
específica. Feito isso, considere-o hermeticamente fechado: você não
pode mais tocá-lo. Para fazer mais alterações, você precisará de uma
nova versão.
Ao selecionar uma versão, siga o controle de versão semântico.
Descrição
Isso é opcional para seus próprios pacotes pessoais, mas se você
pretende publicar seu pacote, você deve fornecer uma descrição, que
deve ser em inglês. A descrição deve ser relativamente curta - 60 a 180
caracteres - e dizer a um leitor casual o que ele pode querer saber sobre o
seu pacote.
Pense na descrição como o argumento de venda do seu pacote. Os
usuários veem quando procuram pacotes. A descrição é um texto simples:
sem marcação ou HTML.
Autor / autores
Descontinuada. Use um editor verificado.
Você pode ver uma seção author ou authors em pubspecs antigos. Esses
campos opcionais são uma forma de descrever o (s) autor (es) do seu
pacote e fornecer informações de contato. Cada autor pode ser um único
nome ( Natalie Weizenbaum ) ou um nome e um endereço de e-mail ( Natalie
Weizenbaum <nweiz@google.com> ). No entanto, esses valores não foram
verificados.
O site pub.dev não exibe mais os autores do pacote e (a partir do Dart
2.7) o pub publish comando exibe um aviso se o seu pubspec tiver uma
seção author ou authors .
Página inicial
Deve ser um URL apontando para o site do seu pacote. Para pacotes
hospedados, este URL está vinculado à página do pacote. Embora o
fornecimento de um homepage seja opcional, forneça -o ou repository (ou
ambos). Ajuda os usuários a entender de onde seu pacote está vindo.
Repositório
O repositor campo opcional deve conter a URL do repositório de código-
fonte do seu pacote - por exemplo https://github.com/<user>/<repository> . Se
você publicar seu pacote no site pub.dev, a página do pacote exibirá o
URL do repositório. Embora o fornecimento de um repositor seja opcional,
forneça -o ou homepage (ou ambos). Ajuda os usuários a entender de
onde seu pacote está vindo.
Rastreador de problemas
O issue_tracker campo opcional deve conter uma URL para o rastreador de
problemas do pacote, onde bugs existentes podem ser visualizados e
novos bugs podem ser arquivados. O site pub.dev tenta exibir um link para
o rastreador de problemas de cada pacote, usando o valor deste campo.
Se issue_tracker estiver faltando, mas repositor estiver presente e apontar
para o GitHub, o site pub.dev usa o rastreador de problemas padrão
( https://github.com/<user>/<repository>/issues ).
Documentação
Alguns pacotes têm um site que hospeda a documentação, separado da
página inicial principal e da referência da API gerada pelo Pub. Se o seu
pacote tiver documentação adicional, adicione um documentation: campo
com esse URL; pub mostra um link para esta documentação na página do
seu pacote.
Dependências
Dependências são a razão de ser do pubspec. Nesta seção, você lista
cada pacote de que seu pacote precisa para funcionar.
As dependências podem ser de dois tipos. As dependências regulares
estão listadas em dependencies: — estes são os pacotes que qualquer
pessoa usando seu pacote também precisará. As dependências que são
necessárias apenas na fase de desenvolvimento do próprio pacote estão
listadas em dev_dependencies .
Durante o processo de desenvolvimento, pode ser necessário substituir
temporariamente uma dependência. Você pode fazer isso usando
dependency_overrides .
Para obter mais informações, consulte Dependências de pacote.
Executáveis
Um pacote pode expor um ou mais de seus scripts como executáveis que
podem ser executados diretamente na linha de comando. Para tornar um
script disponível publicamente, liste-o no executables campo. As entradas
são listadas como pares chave / valor:
Depois que o pacote é ativado usando pub global activate , digitando slidy
executa bin/main.dart . Digitando fvm executa bin/fvm.dart . Se você não
especificar o valor, ele será inferido da chave.
Para obter mais informações, consulte pub global.
Publish_to
O padrão usa o site pub.dev. Especifique none para evitar que um pacote
seja publicado. Essa configuração pode ser usada para especificar um
servidor de pacote pub personalizado para publicar.
Restrições SDK
Um pacote pode indicar quais versões de suas dependências ele suporta,
mas os pacotes têm outra dependência implícita: a própria plataforma
Dart. A plataforma Dart evolui com o tempo, e um pacote pode funcionar
apenas com certas versões da plataforma.
Um pacote pode especificar essas versões usando uma restrição SDK .
Essa restrição vai dentro de um campo environment de nível superior
separado no pubspec e usa a mesma sintaxe de restrição de versão que
as dependências.
Por exemplo, a seguinte restrição diz que este pacote funciona com
qualquer Dart SDK versão 2.10.0 ou superior:
Esse problema pode ocorrer se uma de suas contas tiver permissão para
publicar um pacote, mas o cliente pub o registrar em outra conta.
Você pode redefinir o processo de autenticação do pub removendo o
arquivo de credenciais:
Obtendo Um Erro “Unauthorizedaccess” Ao
Publicar Um Pacote
Você recebe o seguinte erro ao executar pub publish :
UnauthorizedAccess: Unauthorized user: <username> is not allowed to upload versions
to package '<foo>'.
No Windows PowerShell:
No Windows PowerShell:
Localhost Inacessível Após O Login
Quando você executa pub publish em um contêiner ou em uma sessão
SSH, o localhost que pub está ouvindo pode ser diferente do localhost que
está acessível em seu navegador. Embora você possa entrar usando o
navegador, o navegador reclama que http://localhost:<port>?code=... não está
acessível.
Tente esta solução alternativa, que usa a linha de comando para concluir
o login:
1. Em uma janela de terminal, execute pub publish .
2. Na janela do navegador que aparece, entre. O navegador é
redirecionado para uma nova URL de host local ( http://localhost:
<port>?code=... ), mas reclama que a URL não está acessível.
3. Copie o novo URL do host local do navegador.
4. Em outra janela de terminal no mesmo contêiner ou no mesmo host
daquele em que pub publish foi chamado, use o curl comando para
concluir o login usando o novo URL de host local :
Packages: Package Reference: Editores
verificados
O selo de editor verificado pub.dev permite que você saiba que um
pacote foi publicado por um editor cuja identidade foi verificada. Por
exemplo, dart.dev é o editor verificado para pacotes que são suportados
pela equipe Dart do Google.
O emblema aparece em vários lugares no pub.dev, ao lado de pacotes
publicados por editores verificados:
Resultados da pesquisa de pacote
Páginas de detalhes do pacote
Páginas de perfil do editor
A página inicial do pub.dev
Cada editor tem uma página com uma lista de todos os pacotes
pertencentes a esse editor, além de detalhes adicionais, como o e-mail de
contato do editor. Para visitar a página do editor, clique no link de
identidade do editor (por exemplo, dart.dev ) próximo ao selo do editor
verificado .
Processo De Verificação
Para garantir que a criação de editores verificados tenha um custo baixo e
esteja disponível para todos, pub.dev depende de domínios DNS (sistema
de nomes de domínio) como um token de identificação. Escolhemos DNS
porque acreditamos que a maioria dos editores de pacotes já tem um
domínio e uma página inicial para esse domínio. Durante o processo de
criação do editor, pub.dev verifica se o usuário que está criando o editor
verificado tem acesso de administrador ao domínio associado, com base
na lógica existente no Google Search Console.
Criar Uma Conta De Editor Verificada
Se você publicar pacotes e quiser criar um editor verificado, consulte as
instruções na página de publicação.
Packages: Package Reference: Controle de
versão de pacote
Uma das principais funções do gerenciador de pacotes pub é ajudá-lo a
trabalhar com o controle de versão. Este documento explica um pouco
sobre a história do controle de versão e a abordagem do pub em relação a
ele. Considere isso como uma informação avançada. Se você quiser uma
imagem melhor de porque o pub foi projetado do jeito que é, continue
lendo. Se você quiser apenas usar o pub, os outros documentos irão
atendê-lo melhor.
O desenvolvimento de software moderno, especialmente o
desenvolvimento web, depende fortemente da reutilização de muitos e
muitos códigos existentes. Isso inclui código que você escreveu no
passado, mas também código de terceiros, desde grandes estruturas a
pequenas bibliotecas de utilitários. Não é incomum um aplicativo
depender de dezenas de pacotes e bibliotecas diferentes.
É difícil subestimar o quão poderoso isso é. Quando você vê histórias de
pequenas startups na web construindo um site que atrai milhões de
usuários em poucas semanas, a única razão pela qual eles podem fazer
isso é porque a comunidade de código aberto colocou um banquete de
software a seus pés.
Mas isso não vem de graça: há um desafio na reutilização de código,
especialmente reutilizando código que você não mantém. Quando seu
aplicativo usa código desenvolvido por outras pessoas, o que acontece
quando elas o alteram? Eles não querem quebrar seu aplicativo e você
certamente também não. Resolvemos esse problema criando versões .
Um Nome E Um Número
Quando você depende de algum código externo, não diz apenas “Meu
aplicativo usa widgets ”. Você diz: “Meu aplicativo usa widgets 2.0.5 ”. Essa
combinação de nome e número de versão identifica exclusivamente um
pedaço imutável de código. As pessoas que estão atualizando widgets
podem fazer todas as alterações que quiserem, mas prometem não mexer
em nenhuma das versões já lançadas. Eles podem ser lançados 2.0.6 ou
3.0.0 não afetarão você nem um pouco, porque a versão que você usa não
mudou.
Quando você não quiser obter essas mudanças, você sempre pode
apontar o seu aplicativo para uma versão mais recente widgets e você não
tem que coordenar com os desenvolvedores de fazê-lo. No entanto, isso
não resolve totalmente o problema.
Resolvendo Dependências Compartilhadas
Depender de versões específicas funciona bem quando seu gráfico de
dependências é na verdade apenas uma árvore de dependências. Se o
seu aplicativo depende de um monte de pacotes e essas coisas, por sua
vez, têm suas próprias dependências e assim por diante, tudo funciona
bem, desde que nenhuma dessas dependências se sobreponha.
Mas considere o seguinte exemplo:
Exemplo de código
A função a seguir usa dois inteiros como parâmetros. Faça com que ele
retorne uma string contendo ambos os inteiros separados por um espaço.
Por exemplo, stringify(2,3) deve retornar '2 3' .
Operadores Nulos
O Dart oferece alguns operadores úteis para lidar com valores que podem
ser nulos. Um é o ??= operador de atribuição, que atribui um valor a uma
variável apenas se essa variável for atualmente nula:
Exemplo de código
Experimente colocar os operadores ??= e ?? para trabalhar abaixo.
Acesso Condicional À Propriedade
Para proteger o acesso a uma propriedade ou método de um objeto que
pode ser nulo, coloque um ponto de interrogação ( ? ) antes do ponto ( . ):
Exemplo de código
Tente usar o acesso de propriedade condicional para terminar o trecho de
código abaixo.
Literais De Coleção
O Dart possui suporte integrado para listas, mapas e conjuntos. Você
pode criá-los usando literais:
Especificar tipos é útil quando você inicializa uma lista com o conteúdo de
um subtipo, mas ainda deseja que a lista seja List<BaseType> :
Exemplo de código
Tente definir as seguintes variáveis para os valores indicados.
Sintaxe De Seta
Você deve ter visto o => símbolo no código do Dart. Esta sintaxe de seta é
uma forma de definir uma função que executa a expressão à sua direita e
retorna seu valor.
Por exemplo, considere esta chamada para o método List da classe any() :
Exemplo de código
Tente terminar as seguintes instruções, que usam sintaxe de seta.
Cascades
Para realizar uma sequência de operações no mesmo objeto, use
cascades ( .. ). Todos nós vimos uma expressão como esta:
Com cascatas, o código se torna muito mais curto e você não precisa da
variável button :
Exemplo de código
Use cascatas para criar uma única instrução que define a anInt , aString , e
aList propriedades de um BigObject a 1 , 'String!' e [3.0] (respectivamente) e
em seguida, chama allDone() .
Getters E Setters
Você pode definir getters e setters sempre que precisar de mais controle
sobre uma propriedade do que um campo simples permite.
Por exemplo, você pode ter certeza de que o valor de uma propriedade é
válido:
Exemplo de código
Imagine que você tem uma classe de carrinho de compras que mantém
uma lista List<double> de preços privada. Adicione o seguinte:
Um getter chamado total que retorna a soma dos preços
Um setter que substitui a lista por uma nova, desde que a nova lista
não contenha nenhum preço negativo (neste caso, o setter deve
lançar um InvalidPriceException ).
Parâmetros Posicionais Opcionais
O Dart tem dois tipos de parâmetros de função: posicional e nomeado. Os
parâmetros posicionais são do tipo com que você provavelmente está
familiarizado:
Exemplo de código
Implemente uma função chamada joinWithCommas() que aceite de um a
cinco inteiros e, em seguida, retorne uma string desses números
separados por vírgulas. Aqui estão alguns exemplos de chamadas de
função e valores retornados:
Chamada de função Valor devolvido
joinWithCommas(1) '1'
joinWithCommas(1, 2, 3) '1,2,3'
joinWithCommas(1, 1, 1, 1, 1) '1,1,1,1,1'
Parâmetros Nomeados Opcionais
Usando uma sintaxe de chaves, você pode definir parâmetros opcionais
que possuem nomes.
Como você pode esperar, o valor desses parâmetros é nulo por padrão,
mas você pode fornecer valores padrão:
Exemplo de código
Adicione um método copyWith() de instância à classe MyDataObject . Deve
ter três parâmetros nomeados:
int newInt
String newString
double newDouble
Quando chamado, copyWith() deve retornar um novo MyDataObject baseado
na instância atual, com os dados dos parâmetros anteriores (se houver)
copiados nas propriedades do objeto. Por exemplo, se newInt não for nulo,
copie seu valor para anInt .
Exceções
O código do Dart pode lançar e capturar exceções. Em contraste com
Java, todas as exceções do Dart são exceções não verificadas. Os
métodos não declaram quais exceções podem lançar, e você não é
obrigado a capturar nenhuma exceção.
O Dart fornece os tipos Exception e Error , mas você pode lançar qualquer
objeto não nulo:
Exemplo de código
Adicione um construtor de uma linha a MyClass que usa sintaxe this. para
receber e atribuir valores para todas as três propriedades da classe.
Listas De Inicializadores
Às vezes, quando você implementa um construtor, é necessário fazer
algumas configurações antes de o corpo do construtor ser executado. Por
exemplo, os campos finais devem ter valores antes da execução do corpo
do construtor. Faça este trabalho em uma lista de inicializadores, que fica
entre a assinatura do construtor e seu corpo:
Exemplo de código
Complete o construtor FirstTwoLetters abaixo. Use uma lista de
inicializadores para atribuir os primeiros dois caracteres word às
propriedades letterOne e LetterTwo . Para crédito extra, adicione um assert
para capturar palavras com menos de dois caracteres.
Construtores Nomeados
Para permitir que as classes tenham vários construtores, o Dart oferece
suporte a construtores nomeados:
Exemplo de código
Dê à classe Color um construtor chamado Color.black que defina todas as
três propriedades como zero.
Construtores De Fábrica
O Dart oferece suporte a construtores de fábrica, que podem retornar
subtipos ou até mesmo nulos. Para criar um construtor de fábrica, use a
palavra-chave factory :
Exemplo de código
Preencha o construtor de fábrica denominado IntegerHolder.fromList ,
fazendo com que ele faça o seguinte:
Se a lista tiver um valor, crie um IntegerSingle com esse valor.
Se a lista tiver dois valores, crie um IntegerDouble com os valores em
ordem.
Se a lista tiver três valores, crie um IntegerTriple com os valores em
ordem.
Caso contrário, retorna nulo.
Redirecionando Construtores
Às vezes, o único propósito de um construtor é redirecionar para outro
construtor na mesma classe. O corpo de um construtor de
redirecionamento está vazio, com a chamada do construtor aparecendo
após dois pontos ( : ).
Exemplo de código
Lembra da classe Color de cima? Crie um construtor nomeado chamado
black , mas em vez de atribuir manualmente as propriedades, redirecione-o
para o construtor padrão com zeros como argumentos.
Construtores Const
Se sua classe produz objetos que nunca mudam, você pode fazer esses
objetos constantes de tempo de compilação. Para fazer isso, defina um
construtor const e certifique-se de que todas as variáveis de instância
sejam finais.
Exemplo de código
Modifique a classe Recipe para que suas instâncias sejam constantes e
crie um construtor constante que faça o seguinte:
Tem três parâmetros: ingredients , calories e milligramsOfSodium (nessa
ordem).
Usa sintaxe this. para atribuir automaticamente os valores dos
parâmetros às propriedades do objeto de mesmo nome.
É constante, com a palavra-chave const logo antes Recipe na
declaração do construtor.
Development: Codelabs: Coleções iteráveis
Este codelab ensina como usar coleções que implementam a classe
Iterable - por exemplo, List e Set. Iterables são blocos de construção
básicos para todos os tipos de aplicativos Dart, e provavelmente você já
os está usando, mesmo sem perceber. Este codelab ajuda você a
aproveitá-los ao máximo.
Usando os editores DartPad incorporados, você pode testar seus
conhecimentos executando códigos de exemplo e concluindo exercícios.
Para obter o máximo deste codelab, você deve ter conhecimento básico
da sintaxe do Dart.
Este codelab cobre o seguinte material:
Como ler os elementos de um Iterable.
Como verificar se os elementos de um Iterable satisfazem uma
condição.
Como filtrar o conteúdo de um Iterable.
Como mapear o conteúdo de um Iterable para um valor diferente.
O Que São Coleções?
Uma coleção é um objeto que representa um grupo de objetos, que são
chamados de elementos . Os iteráveis são uma espécie de coleção.
Uma coleção pode estar vazia ou pode conter muitos elementos.
Dependendo da finalidade, as coleções podem ter diferentes estruturas e
implementações. Estes são alguns dos tipos de coleção mais comuns:
Lista: usado para ler elementos por seus índices .
Conjunto: usado para conter elementos que podem ocorrer apenas
uma vez .
Mapa: usado para ler elementos usando uma chave.
O Que É Um Iterável?
Um Iterable é uma coleção de elementos que podem ser acessados
sequencialmente.
No Dart, a Iterable é uma classe abstrata, o que significa que você não
pode instanciá-la diretamente. No entanto, você pode criar um Iterable
criando um List ou Set .
Ambos List e Set são Iterable , portanto, eles têm os mesmos métodos e
propriedades da classe Iterable .
A Map usa uma estrutura de dados diferente internamente, dependendo de
sua implementação. Por exemplo, o HashMap usa uma tabela hash na
qual os elementos (também chamados de valores ) são obtidos por meio
de uma chave. Os elementos de um Map também podem ser lidos como
objetos Iterable usando a propriedade entries ou do mapa values .
Este exemplo mostra um List de int , que também é um Iterable de int :
A diferença com a List é que com o Iterable , você não pode garantir que a
leitura dos elementos por índice seja eficiente. Iterable , ao contrário List ,
não tem o operador [] .
Por exemplo, considere o seguinte código, que é inválido :
Por exemplo, se você deseja encontrar o primeiro String que tem mais de 5
caracteres, deve passar um predicado que retorna verdadeiro quando o
tamanho do elemento é maior que 5.
Execute o exemplo a seguir para ver como firstWhere() funciona. Você acha
que todas as funções darão o mesmo resultado?
Neste exemplo, você pode ver três maneiras diferentes de escrever um
predicado:
Como uma expressão: O código de teste possui uma linha que usa
a sintaxe de seta ( => ).
Como um bloco: O código de teste possui várias linhas entre
colchetes e uma instrução de retorno.
Como uma função: o código de teste está em uma função externa
que é passada para o método firstWhere() como um parâmetro.
Não existe jeito certo ou errado. Use a maneira que funciona melhor para
você e que torna seu código mais fácil de ler e entender.
No exemplo, firstWhereWithOrElse() chamadas firstWhere() com o parâmetro
nomeado opcional orElse , que fornece uma alternativa quando um
elemento não é encontrado. Nesse caso, o texto 'None!' é retornado porque
nenhum elemento satisfaz a condição fornecida.
Exercício: Pratique escrever um predicado de teste
O exercício a seguir é um teste de unidade com falha que contém um
trecho de código parcialmente completo. Sua tarefa é completar o
exercício escrevendo código para fazer os testes passarem. Você não
precisa implementar main() .
Este exercício apresenta singleWhere() Este método funciona de maneira
semelhante firstWhere() , mas, nesse caso, espera apenas um elemento de
Iterable para satisfazer o predicado. Se mais de um ou nenhum elemento
Iterable satisfizer a condição do predicado, o método lançará uma exceção
StateError.
Você também pode usar any() para verificar se nenhum elemento de uma
Iterable satisfaz uma determinada condição.
Neste exemplo, numbers contém um Iterable com vários valores int e where()
encontra todos os números pares.
A saída de where() é outra Iterable e você pode usá-la como tal para iterar
sobre ela ou aplicar outros métodos Iterable . No próximo exemplo, a saída
de where() é usada diretamente dentro do loop for-in .
Neste exemplo, cada elemento dos Iterable números é multiplicado por 10.
Você também pode usar map() para transformar um elemento em um
objeto diferente - por exemplo, para converter tudo int para String , como
você pode ver no exemplo a seguir.
Veja por que o exemplo não consegue imprimir o valor que fetchUserOrder()
eventualmente produz:
fetchUserOrder() é uma função assíncrona que, após um atraso,
fornece uma string que descreve o pedido do usuário: um “Large
Latte”.
Para obter o pedido do usuário, createOrderMessage() deve ligar
fetchUserOrder() e aguardar o término. Porque createOrderMessage() é
que não esperar fetchUserOrder() até ao fim, createOrderMessage() não
consegue obter o valor de cadeia que fetchUserOrder() fornece
eventualmente.
Em vez disso, createOrderMessage() obtém uma representação do
trabalho pendente a ser feito: um futuro incompleto. Você aprenderá
mais sobre o futuro na próxima seção.
Como createOrderMessage() falha em obter o valor que descreve o
pedido do usuário, o exemplo falha ao imprimir “Large Latte” no
console e, em vez disso, imprime “Seu pedido é: Instância de
'_Future'".
Nas próximas seções você aprenderá sobre futuros e como trabalhar com
futuros (usando async e await ) para poder escrever o código necessário
para fetchUserOrder() imprimir o valor desejado (“Large Latte”) no console.
O Que É Futuro?
Um futuro (minúsculo “f”) é uma instância da classe Future (maiúsculo
“F”). Um futuro representa o resultado de uma operação assíncrona e
pode ter dois estados: incompleto ou concluído.
Incompleto
Quando você chama uma função assíncrona, ela retorna um futuro
incompleto. Esse futuro está esperando que a operação assíncrona da
função termine ou gere um erro.
Concluído
Se a operação assíncrona for bem-sucedida, o futuro será concluído com
um valor. Caso contrário, termina com um erro.
Completando com um valor
Um futuro de tipo é Future<T> concluído com um valor de tipo T . Por
exemplo, um futuro com tipo Future<String> produz um valor de string. Se
um futuro não produz um valor utilizável, então o tipo do futuro é
Future<void> .
Concluindo com um erro
Se a operação assíncrona executada pela função falhar por qualquer
motivo, o futuro será concluído com um erro.
Agora que você tem uma função async , pode usar a palavra-chave await
para esperar a conclusão de um futuro:
Observe que o tempo da saída muda, agora que print('Awaiting user order')
aparece após a primeira palavra-chave await em printOrderMessage() .
Parte 1: reportUserRole()
Adicione o código à função reportUserRole() para que ela faça o seguinte:
Retorna um futuro que se completa com a seguinte string: "User role: <user role>"
Nota: Você deve usar o valor real retornado por fetchRole() ; copiar e colar o
valor de retorno de exemplo não fará o teste passar.
Valor de retorno de exemplo: "User role: tester"
Obtém a função do usuário chamando a função fornecida fetchRole() .
Parte 2: reportLogins()
Implemente uma função async reportLogins() para que ela faça o seguinte:
Retorna a string "Total number of logins: <# of logins>" .
Nota: Você deve usar o valor real retornado por fetchLoginAmount() ; copiar
e colar o valor de retorno de exemplo não fará o teste passar.
Exemplo de valor de retorno de reportLogins() : "Total number of logins: 57"
Obtém o número de logins chamando a função fornecida fetchLoginAmount() .
Tratamento De Erros
Para lidar com erros em uma função async , use try-catch :
Escreva o seguinte:
Parte 1: addHello()
Escreva uma função addHello() que receba um único argumento String.
addHello() retorna seu argumento String precedido por 'Hello'.
Exemplo: addHello('Jon') retorna 'Hello Jon' .
Parte 2: greetUser()
Escreva uma função greetUser() que não receba argumentos.
Para obter o nome de usuário, greetUser() chama a função assíncrona fornecida
fetchUsername() .
greetUser() cria uma saudação para o usuário chamando addHello() , passando o
nome de usuário e retornando o resultado.
Exemplo: se fetchUsername() retorna 'Jenny' , então greetUser() retorna 'Hello
Jenny' .
Parte 3: sayGoodbye()
Escreva uma função sayGoodbye() que faça o seguinte:
Não aceita argumentos.
Captura todos os erros.
Chama a função assíncrona fornecida logoutUser() .
Se logoutUser() falhar, sayGoodbye() retorna qualquer string que você quiser.
Se logoutUser() for bem-sucedido, sayGoodbye() retorna a string '<result> Thanks,
see you next time' , onde <result> é o valor da String retornado pela chamada
logoutUser() .
Qual É O Próximo?
Parabéns, você terminou o codelab! Se quiser saber mais, aqui estão
algumas sugestões sobre o que fazer a seguir:
Brinque com o DartPad.
Experimente outro codelab .
Saiba mais sobre futuros e assincronia:
Tutorial do Streams : Aprenda como trabalhar com uma sequência de
eventos assíncronos.
Vídeos Dart do Google: assista a um ou mais dos vídeos sobre codificação
assíncrona. Ou, se preferir, leia os artigos que se baseiam nesses vídeos.
(Comece com isolados e loops de eventos. )
Obtenha o SDK do Dart .
Se você estiver interessado em usar DartPads incorporados, como este
codelab faz, consulte as práticas recomendadas para usar DartPad em
tutoriais.
Development: Interoperability:
Interoperabilidade C usando dart: ffi
Aplicativos móveis, de linha de comando e de servidor Dart em execução
na plataforma Dart Native podem usar a biblioteca dart: ffi para chamar
APIs C nativas. FFI significa interface de função estrangeira. Outros termos
para funcionalidade semelhante incluem interface nativa e ligações de idioma.
Arquivos
O exemplo hello_world tem os seguintes arquivos:
Arquivo fonte Descrição
hello.darte Um arquivo Dart que usa a hello_world() função de
uma biblioteca C.
pubspec.yaml O pubspec Dart usual, com limites inferiores no SDK
de pelo menos 2,5.
hello_library / Declara a hello_world() função.
hello.h
hello_library / Arquivo AC que importa hello.h e define a
hello.c hello_world() função.
hello_library / Um arquivo de construção CMake para compilar o
CMakeLists.txt código C em uma biblioteca dinâmica.
A construção da biblioteca C cria vários arquivos, incluindo um arquivo de
biblioteca dinâmica denominado libhello.dylib (macOS), libhello.dll
(Windows) ou libhello.so (Linux).
Construindo e funcionando
Aqui está um exemplo de construção da biblioteca dinâmica e execução
do aplicativo Dart:
Transmitir streams
O outro tipo de fluxo é destinado a mensagens individuais que
podem ser tratadas uma de cada vez. Esse tipo de fluxo pode ser
usado para eventos de mouse em um navegador, por exemplo.
Você pode começar a ouvir esse tipo de transmissão a qualquer
momento e obter os eventos que são disparados enquanto você
ouve. Mais de um ouvinte pode ouvir ao mesmo tempo, e você pode
ouvir novamente depois de cancelar uma assinatura anterior.
Métodos que processam um fluxo
Os seguintes métodos em Stream <T> processam o stream e
retornam um resultado:
reder.weyers@icloud.com