제네릭 제약 사항
Coddy Dart 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 110개 중 67번째.
때때로 제네릭 타입이 특정 기능을 갖추어야 할 필요가 있습니다. 예를 들어, 항목을 비교하거나 특정 속성에 접근하려는 경우, 제한이 없는 T는 이러한 기능이 존재함을 보장하지 않습니다. 제네릭 제약 조건(Generic constraints)을 사용하면 타입 매개변수를 특정 타입이나 그 하위 클래스로 제한할 수 있습니다.
extends 키워드를 사용하여 타입 매개변수를 제약하세요:
class NumberBox<T extends num> {
T value;
NumberBox(this.value);
T doubled() => (value * 2) as T;
}
void main() {
var intBox = NumberBox<int>(5);
var doubleBox = NumberBox<double>(3.5);
print(intBox.doubled()); // 10
print(doubleBox.doubled()); // 7.0
// var stringBox = NumberBox<String>('hi'); // 오류!
}T extends num이기 때문에, 컴파일러는 value가 곱셈과 같은 숫자 연산을 지원한다는 것을 알 수 있습니다. 이러한 제약 조건이 없으면, value * 2를 호출하는 것은 실패하게 됩니다.
제약 조건은 직접 만든 클래스 계층 구조와도 함께 작동합니다:
abstract class Animal {
String get name;
}
class Dog extends Animal {
String get name => 'Dog';
}
class Shelter<T extends Animal> {
List<T> animals = [];
void add(T animal) => animals.add(animal);
void printNames() {
for (var animal in animals) {
print(animal.name); // 안전함: T는 'name'이 존재함을 보장함
}
}
}제네릭 제약 조건은 제네릭의 유연성과 해당 타입에서 어떤 연산을 사용할 수 있는지 알 수 있는 안전성을 결합합니다.
챌린지
쉬움숫자 타입에만 작동하는 통계 계산기를 만들어 봅시다! 숫자에만 사용할 수 있도록 보장하는 제약 조건이 있는 제네릭 클래스를 생성하여, 저장된 값에 대해 안전하게 수학적 연산을 수행할 수 있도록 할 것입니다.
코드를 두 개의 파일로 구성합니다:
stats.dart: 숫자 값 리스트를 관리하는 제네릭Stats<T extends num>클래스를 생성합니다:- 숫자를 저장하기 위한
values라는 이름의List<T> - 제공된 값으로 리스트를 초기화하는 생성자
- 모든 값의 합계를
num타입으로 반환하는sum()메서드 - 가장 작은 값을
T타입으로 반환하는min()메서드 - 가장 큰 값을
T타입으로 반환하는max()메서드 - 통계를 형식에 맞춰 표시하는
printStats()메서드
- 숫자를 저장하기 위한
main.dart: stats 파일을 임포트하고 서로 다른 숫자 타입을 사용하여 제약이 있는 제네릭 클래스를 시연합니다:[10, 25, 5, 30, 15]값을 가진Stats<int>를 생성하고printStats()를 호출합니다- 빈 줄을 하나 출력합니다
[3.5, 1.2, 4.8, 2.1]값을 가진Stats<double>를 생성하고printStats()를 호출합니다
printStats() 메서드는 합계, 최솟값, 최댓값을 보여주는 세 줄을 출력해야 합니다. T extends num이기 때문에, 제약이 없는 제네릭 타입에서는 불가능했던 비교 연산자와 산술 연산을 값들에 대해 안전하게 사용할 수 있습니다.
예상 출력:
Sum: 85
Min: 5
Max: 30
Sum: 11.6
Min: 1.2
Max: 4.8치트 시트
제네릭 제약 조건은 extends 키워드를 사용하여 타입 매개변수를 특정 타입이나 그 하위 클래스로 제한합니다:
class NumberBox<T extends num> {
T value;
NumberBox(this.value);
T doubled() => (value * 2) as T;
}T extends num을 사용하면, 컴파일러는 value가 곱셈과 같은 숫자 연산을 지원한다는 것을 알게 됩니다.
제약 조건은 사용자 정의 클래스 계층 구조에서도 작동합니다:
abstract class Animal {
String get name;
}
class Shelter<T extends Animal> {
List<T> animals = [];
void printNames() {
for (var animal in animals) {
print(animal.name); // 안전함: T는 'name'이 존재함을 보장합니다
}
}
}제네릭 제약 조건은 타입 안전성과 사용 가능한 연산을 보장하면서 유연성을 제공합니다.
직접 해보기
import 'stats.dart';
void main() {
// TODO: [10, 25, 5, 30, 15] 값을 가진 Stats<int>를 생성하고
// printStats()를 호출하세요.
// TODO: 빈 줄을 출력하세요.
// TODO: [3.5, 1.2, 4.8, 2.1] 값을 가진 Stats<double>을 생성하고
// printStats()를 호출하세요.
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.