Novos recursos no Dart 3.0
Neste artigo, escreverei sobre novos recursos impressionantes na linguagem Dart.
Conteudo
Patterns
De acordo com a documentação:
Em geral, um pattern pode corresponder a um valor, desestruturar um valor ou ambos, dependendo do contexto e da forma do padrão.
O que podemos fazer com Patterns? Vamos nos aprofundar nos exemplos.
1. Podemos obter elementos da lista:
void main() { final list = [10, 20, 30, 40, 50]; final [a, b, c, d, e] = list; print('$a $b $c $d $e'); // ele imprimirá 10 20 30 40 50 }
2. Podemos escrever patterns mais complexos e casos destruidores no switch:
/// este exemplo primeiro verifica se o primeiro elemento da lista é a ou b /// então ele destrói o segundo elemento da lista switch (list) { case ['a' || 'b', var c]: print(c); } void main() { check(1); // it is equal to 1 check(7); // it is between 5 and 10 check(20); // it is 20 } void check(int a) { switch(a) { case 1: print('it is equal to 1'); break; case >= 5 && <= 10: print('it is between 5 and 10'); break; default: print('it is $a'); } }
3. Podemos validar o json de forma mais legível:
void main() { final json = <String, dynamic>{ 'name': 'Kanan', 'age': 24, }; final (name, age) = getNameAndAge(json); print('$name: $age'); } (String, int) getNameAndAge(Map<String, dynamic> json) { if(json case {'name': 'Kanan', 'age': 24}) { return (json['name'], json['age']); } throw Exception('it is not valid!'); }
4. Podemos usar padrões em loops for e for-in:
void main() { final personList = <Person>[ Person(name: 'Kanan', age: 24), Person(name: 'Zahra', age: 23) ]; for(var Person(name: name, age: age) in personList) { print('name: $name, age: $age'); } /// it will print // name: Kanan, age: 24 // name: Zahra, age: 23 } class Person { const Person({ required this.name, required this.age, }); final String name; final int age; }
Para obter mais informações, consulte os documentos.
Records (podemos dizer tuplas)
Em alguns casos, podemos encontrar o caso em que queremos retornar vários resultados do método ou queremos analisar o JSON para apenas dois ou mais campos. Nesses casos, podemos usar registros. Vejamos os exemplos a seguir.
Podemos simplesmente definir tuplas com parâmetros opcionais ou nomeados e acessar com seu nome ou $index+1 caminho.
void main() { var person = (name: 'Kanan', surname: 'Yusubov', age: 24); var person2 = ('Kanan', 'Yusubov', 24); print(person.age); print(person.surname); print(person2.$2); }
Podemos usar registros e parâmetros de função e valores de retorno:
void main() { final swappedValues = swap((10, 20)); print('${swappedValues.$1} e ${swappedValues.$2}'); } (int, int) swap((int, int) values) { final (a, b) = values; return (b, a); }
Podemos usar registros e parâmetros de função e valores de retorno:
void main() { final swappedValues = swap((a: 10, b: 20)); print('${swappedValues.first} e ${swappedValues.second}'); } (int first, int second) swap((int a, int b) values) { return (first: values.b, second: values.a); }
Você pode usá-lo para analisar alguns membros do JSON:
void main() { final json = <String, dynamic>{ 'name': 'Kanan', 'surname': 'Yusubov', 'age': 24, 'livesIn': 'Baku', 'worksAt': ' Nasimi Bazari' }; final (name, age) = getNameAndAge(json); print('$name: $age'); } (String, int) getNameAndAge(Map<String, dynamic> json) { return (json['name'], json['age']); }
Para mais informações, verifique os documentos.
Modificadores de classe
Final modificador
Usando esta palavra-chave na declaração da classe, garantirá:
- Outras classes não podem estender ou implementar sua classe
- Outras classes não podem usar esta classe como um mixin
Observe o seguinte exemplo:
final class A {} class B extends A {} class C implements A {} mixin D on A {} class E with A {}
Todos os exemplos acima darão o erro de sintaxe. Ele garante que:
- Você pode adicionar com segurança novas alterações à sua biblioteca e API com mais segurança
- Você pode usar a classe final de qualquer outra biblioteca com segurança porque garante que ela não pode ser estendida ou implementada em nenhuma outra biblioteca.
Mas lembre-se de que você pode estender e implementar sua classe final na mesma biblioteca. Para isso, você pode definir a classe do subtipo como base
, final
ou sealed
.
final class A {} final class B extends A {} base class C implements A {} sealed class D extends A {}
Modificador de interface
Se você desenvolver a nova biblioteca, pacote e outras coisas, dentro da mesma biblioteca, podemos usar a classe de interface estendida e implementada. Mas se usarmos essa biblioteca em outra biblioteca, a classe de interface nos permitirá apenas implementá-la.
Então, usando este modificador:
- Sua biblioteca chamará com segurança a mesma implementação de métodos de instância dentro da mesma biblioteca.
- Outras bibliotecas não podem modificar a definição de classe base para seus métodos de instância. Isso reduzirá o risco de problema de classe base frágil.
// Library a.dart interface class A { void greet() { ... } } // Library b.dart import 'a.dart'; var instanceOfA = A(); // Can be constructed class B extends A { // ERROR: Cannot be inherited int instanceMember; // ... } class C implements A { // Can be implemented @override void greet() { ... } }
Modificador base
O modificador de base garante:
- O construtor da classe base é chamado sempre que uma instância de um subtipo da classe é criada.
- Todos os membros privados implementados existem em subtipos.
- Um membro implementado recentemente em uma classe base não quebra os subtipos, pois todos os subtipos herdam o novo membro.
- Isso é verdadeiro, a menos que o subtipo já declare um membro com o mesmo nome e uma assinatura incompatível.
Vamos explorar o seguinte exemplo:
base class Person { void greet() { print('Hi!'); } } class Programmer extends Person { }
Vai dar o erro como o seguinte:
O tipo ‘Programmer’ deve ser ‘base’, ‘final’ ou ‘sealed’ porque o supertipo ‘Pessoa’ é ‘base’.
O modificador base funciona como uma versão reversa da palavra-chave interface. Você só pode estender sua classe base em outra biblioteca. Mas lembre-se de que, se você deseja estender a classe base, sua subclasse deve ser definida como uma classe base ou final.
Modificador Sealed
Ele nos permite criar um conjunto enumerável de subtipos. Usando o novo recurso de verificação exaustiva Podemos usar classes de subtipo em switch e expressões switch em qualquer lugar com sintaxe mais amigável.
O modificador sealed
impede que uma classe seja estendida ou implementada fora de sua biblioteca.
As classes Sealed não podem ser instanciadas, mas podem conter construtores de fábrica. Portanto, é implicitamente abstrato.
void main() { final developer = Developer(); final programmer = Programmer(); print(getTitle(developer)); print(getTitle(programmer)); } String getTitle(Person p) { return switch(p) { Developer() => 'Developer', Programmer() => 'Programmer', }; } sealed class Person {} class Developer extends Person {} class Programmer extends Person {}
Você pode usar classes sealed para lidar com diferentes estados em soluções de gerenciamento de estado (como Bloc, Riverpod, etc) de uma forma mais legível:
void main() { final initial = Initial(); final inProgress = InProgress(); final failure = Failure('something went wrong!'); final success = Success(10); print(handleState(initial)); print(handleState(inProgress)); print(handleState(failure)); print(handleState(success)); } String handleState(DataState state) { return switch(state) { Initial() => 'this is initial state', InProgress() => 'this is in progress state', Failure(message: var m) => 'error occured: $m', Success(data: var s) => 'success with $s', }; } sealed class DataState {} class Initial extends DataState {} class InProgress extends DataState {} class Failure extends DataState { Failure([this.message]); final String? message; } class Success extends DataState { Success(this.data); final int data; }
Combinando modificadores
Você pode seguir a seguinte ordem para adicionar modificadores de classe:
- em primeiro lugar, você pode adicionar a palavra-chave
abstract
, mas é opcional, permitirá que a classe adicione alguns membros abstratos e bloqueará a classe para instanciar. - Em seguida, você pode adicionar uma das seguintes palavras-chave interface,
final
,base
esealed
para adicionar mais regras para subclasses em outras bibliotecas. (também é opcional) - Pela ordem, você pode adicionar uma palavra-chave
mixin
para adicionar a capacidade de outras classes se misturarem. (opcional) - e é necessário adicionar a própria palavra-chave
class
.
Para alguns tipos, você não pode combinar. Tenha em mente que:
- Você não pode combinar classes
sealed
eabstract
, porque a classesealed
é implicitamente abstrata. - Você não pode usar
mixin
comfinal
,interface
esealed
, porque eles não podem permitir que outras bibliotecas os usem comomixin
.
Espero que seja um artigo informativo para você.