Menu
Coddy logo textTech

Palavra-chave Covariant

Parte da seção Programação Orientada a Objetos do Journey de Dart da Coddy — lição 61 de 110.

Quando você sobrescreve um método em uma subclasse, o Dart normalmente exige que os tipos dos parâmetros correspondam exatamente. Mas às vezes você quer que um método de subclasse aceite um tipo mais específico do que o pai. A palavra-chave covariant permite isso.

Considere um cenário onde uma classe Animal possui um método que aceita outro Animal:

class Animal {
  void chase(Animal other) {
    print('Chasing an animal');
  }
}

class Dog extends Animal {
  @override
  void chase(covariant Dog other) {
    print('Dog chasing another dog');
  }
}

Sem o covariant, o Dart reclamaria que Dog não é o mesmo tipo que Animal. Ao adicionar covariant antes do parâmetro, você diz ao Dart: "Eu sei que isso é mais específico, e eu garantirei que apenas o tipo correto seja passado."

Isso é útil quando as subclasses logicamente devem funcionar apenas com seu próprio tipo:

void main() {
  Dog dog1 = Dog();
  Dog dog2 = Dog();
  
  dog1.chase(dog2);  // Funciona: Cachorro perseguindo outro cachorro
}

Tenha cuidado, no entanto — usar covariant desloca a segurança de tipos para o tempo de execução. Se você chamar o método por meio de uma referência de pai com o tipo errado, você receberá um erro de tempo de execução em vez de um erro de tempo de compilação. Use-o quando estiver confiante sobre os tipos que estão sendo passados.

challenge icon

Desafio

Fácil

Vamos construir um sistema de compatibilidade de animais de estimação que utiliza a palavra-chave covariant para garantir que os animais só possam brincar com os de sua própria espécie. Você criará uma hierarquia de animais de estimação onde cada tipo possui um método playWith que aceita apenas o mesmo tipo de animal.

Você organizará seu código em dois arquivos:

  • pets.dart: Defina sua hierarquia de animais de estimação aqui:
    • Uma classe Pet com uma propriedade String name e um construtor. Inclua um método playWith(Pet other) que imprime '$name plays with ${other.name}'
    • Uma classe Cat que estende Pet e sobrescreve playWith usando a palavra-chave covariant para aceitar apenas um Cat. Ela deve imprimir '$name and ${other.name} chase yarn together'
    • Uma classe Dog que estende Pet e sobrescreve playWith usando a palavra-chave covariant para aceitar apenas um Dog. Ela deve imprimir '$name and ${other.name} fetch the ball together'
    • Uma classe Rabbit que estende Pet e sobrescreve playWith usando a palavra-chave covariant para aceitar apenas um Rabbit. Ela deve imprimir '$name and ${other.name} hop around together'
  • main.dart: Importe seu arquivo de animais de estimação e demonstre como cada tipo de animal brinca exclusivamente com sua própria espécie:
    • Crie dois objetos Cat chamados 'Whiskers' e 'Mittens', então faça Whiskers brincar com Mittens
    • Crie dois objetos Dog chamados 'Buddy' e 'Max', então faça Buddy brincar com Max
    • Crie dois objetos Rabbit chamados 'Flopsy' e 'Cotton', então faça Flopsy brincar com Cotton

A palavra-chave covariant permite que cada subclasse restrinja o tipo do parâmetro de Pet para seu tipo específico, garantindo interações seguras quanto ao tipo entre animais da mesma espécie.

Saída esperada:

Whiskers and Mittens chase yarn together
Buddy and Max fetch the ball together
Flopsy and Cotton hop around together

Folha de consulta

A palavra-chave covariant permite que uma subclasse substitua um método com um tipo de parâmetro mais específico do que a classe pai.

Sem o covariant, o Dart exige que os tipos de parâmetros correspondam exatamente ao substituir métodos. Com o covariant, você pode restringir o tipo de parâmetro na subclasse:

class Animal {
  void chase(Animal other) {
    print('Chasing an animal');
  }
}

class Dog extends Animal {
  @override
  void chase(covariant Dog other) {
    print('Dog chasing another dog');
  }
}

Isso é útil quando as subclasses devem trabalhar apenas com seu próprio tipo:

void main() {
  Dog dog1 = Dog();
  Dog dog2 = Dog();
  
  dog1.chase(dog2);  // Funciona: Dog chasing another dog
}

Importante: O uso de covariant desloca a segurança de tipo do tempo de compilação para o tempo de execução. Se você chamar o método por meio de uma referência de pai com o tipo errado, receberá um erro de tempo de execução em vez de um erro de tempo de compilação.

Experimente você mesmo

import 'pets.dart';

void main() {
  // TODO: Criar dois objetos Cat chamados 'Whiskers' e 'Mittens'
  // Depois fazer Whiskers brincar com Mittens
  
  
  // TODO: Criar dois objetos Dog chamados 'Buddy' e 'Max'
  // Depois fazer Buddy brincar com Max
  
  
  // TODO: Criar dois objetos Rabbit chamados 'Flopsy' e 'Cotton'
  // Depois fazer Flopsy brincar com Cotton
  
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos