Menu
Coddy logo textTech

Covariant 키워드

Coddy Dart 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 110개 중 61번째.

서브클래스에서 메서드를 오버라이드할 때, Dart는 보통 매개변수 타입이 정확히 일치할 것을 요구합니다. 하지만 때로는 서브클래스 메서드가 부모보다 더 구체적인 타입을 받아들이도록 하고 싶을 때가 있습니다. covariant 키워드는 이를 가능하게 합니다.

Animal 클래스가 다른 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');
  }
}

covariant가 없으면, Dart는 DogAnimal과 같은 타입이 아니라고 오류를 발생시킬 것입니다. 매개변수 앞에 covariant를 추가함으로써, Dart에게 "이것이 더 구체적이라는 것을 알고 있으며, 올바른 타입만 전달되도록 보장하겠습니다"라고 알려주는 것입니다.

이는 하위 클래스가 논리적으로 자신의 종류와만 작업해야 할 때 유용합니다:

void main() {
  Dog dog1 = Dog();
  Dog dog2 = Dog();
  
  dog1.chase(dog2);  // 작동함: 다른 개를 쫓는 개
}

하지만 주의하세요 - covariant를 사용하면 타입 안전성이 런타임으로 옮겨집니다. 잘못된 타입의 부모 참조를 통해 메서드를 호출하면 컴파일 타임 에러 대신 런타임 에러가 발생하게 됩니다. 전달되는 타입에 대해 확신이 있을 때만 사용하세요.

challenge icon

챌린지

쉬움

covariant 키워드를 사용하여 반려동물이 자신의 종하고만 놀 수 있도록 보장하는 반려동물 호환성 시스템을 구축해 보겠습니다. 각 유형이 동일한 유형의 반려동물만 허용하는 playWith 메서드를 갖는 반려동물 계층 구조를 만들 것입니다.

코드를 두 개의 파일로 구성합니다:

  • pets.dart: 여기에 반려동물 계층 구조를 정의합니다:
    • String name 속성과 생성자를 가진 Pet 클래스. [name] plays with [other.name]을 출력하는 playWith(Pet other) 메서드를 포함합니다.
    • Pet을 상속받고 covariant 키워드를 사용하여 Cat만 허용하도록 playWith를 오버라이드하는 Cat 클래스. [name] and [other.name] chase yarn together를 출력해야 합니다.
    • Pet을 상속받고 covariant 키워드를 사용하여 Dog만 허용하도록 playWith를 오버라이드하는 Dog 클래스. [name] and [other.name] fetch the ball together를 출력해야 합니다.
    • Pet을 상속받고 covariant 키워드를 사용하여 Rabbit만 허용하도록 playWith를 오버라이드하는 Rabbit 클래스. [name] and [other.name] hop around together를 출력해야 합니다.
  • main.dart: 반려동물 파일을 임포트하고 각 반려동물 유형이 자신의 종하고만 노는 방식을 보여줍니다:
    • 'Whiskers''Mittens'라는 이름의 두 Cat 객체를 생성한 다음, Whiskers가 Mittens와 놀게 합니다.
    • 'Buddy''Max'라는 이름의 두 Dog 객체를 생성한 다음, Buddy가 Max와 놀게 합니다.
    • 'Flopsy''Cotton'이라는 이름의 두 Rabbit 객체를 생성한 다음, Flopsy가 Cotton과 놀게 합니다.

covariant 키워드를 사용하면 각 서브클래스가 매개변수 유형을 Pet에서 특정 유형으로 좁힐 수 있어, 동일한 종류의 반려동물 간의 유형 안전(type-safe) 상호작용을 보장할 수 있습니다.

예상 출력:

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

치트 시트

covariant 키워드를 사용하면 서브클래스에서 부모 클래스보다 더 구체적인 매개변수 타입을 사용하여 메서드를 오버라이드할 수 있습니다.

covariant가 없으면 Dart는 메서드를 오버라이드할 때 매개변수 타입이 정확히 일치해야 합니다. covariant를 사용하면 서브클래스에서 매개변수 타입을 좁힐 수 있습니다:

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');
  }
}

이는 서브클래스가 자신의 타입하고만 작동해야 할 때 유용합니다:

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

중요: covariant를 사용하면 타입 안전성이 컴파일 타임에서 런타임으로 이동합니다. 부모 참조를 통해 잘못된 타입으로 메서드를 호출하면 컴파일 타임 에러 대신 런타임 에러가 발생합니다.

직접 해보기

import 'pets.dart';

void main() {
  // TODO: 'Whiskers'와 'Mittens'라는 이름의 Cat 객체 두 개를 생성하세요
  // 그 다음 Whiskers가 Mittens와 놀게 하세요
  
  
  // TODO: 'Buddy'와 'Max'라는 이름의 Dog 객체 두 개를 생성하세요
  // 그 다음 Buddy가 Max와 놀게 하세요
  
  
  // TODO: 'Flopsy'와 'Cotton'이라는 이름의 Rabbit 객체 두 개를 생성하세요
  // 그 다음 Flopsy가 Cotton과 놀게 하세요
  
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨