IMCAT.DEV
로그인 가입
Dart 중급 자료구조

Dart 제네릭 사용법

Dart 제네릭 사용법 — 중급

제네릭 사용법

1. 도입 (왜 배워야 하는가)

제네릭(Generic)은 코드의 재사용성을 높이고, 타입 안정성을 강화하는 중요한 개념입니다. 실무에서 데이터 구조나 알고리즘을 작성할 때, 다양한 타입의 데이터를 다루어야 하는 경우가 많습니다. 제네릭을 사용하지 않으면 매번 특정 타입에 맞는 코드를 작성해야 하므로 코드의 중복이 발생하고 유지보수가 어려워질 수 있습니다.

예를 들어, 리스트를 다룰 때 int 리스트와 String 리스트를 각각 따로 작성해야 한다면, 비슷한 로직을 여러 번 작성해야 하는 불편함이 생깁니다. 제네릭을 활용하면 한 번의 코드로 다양한 타입의 리스트를 다룰 수 있습니다.

제네릭을 모르면 코드가 반복되고, 가독성이 떨어지며, 나중에 타입 오류가 발생할 가능성이 커집니다. 따라서 제네릭은 현대 프로그래밍에서 매우 중요합니다.

2. 핵심 개념 설명

제네릭은 클래스나 메서드를 정의할 때, 특정 타입을 고정하지 않고 타입 매개변수를 사용하는 방법입니다. 이를 통해 다양한 데이터 타입을 처리할 수 있습니다.

비유

제네릭을 주방의 조리 도구에 비유할 수 있습니다. 여러 요리를 할 때, 각 요리에 맞는 도구를 사용해야 하지만, 다용도 도구를 사용하면 여러 요리를 쉽게 만들 수 있습니다. 제네릭은 이 다용도 도구와 같습니다.

관련 용어 정리

용어정의
타입 매개변수제네릭에서 사용되는 placeholder로, 실제 타입이 아닌 변수처럼 사용됨
제네릭 클래스하나 이상의 타입 매개변수를 가지는 클래스
제네릭 메서드제네릭 클래스와 유사하게, 타입 매개변수를 가지는 메서드

3. 기본 코드 예제

제네릭을 사용하는 가장 기본적인 예제를 살펴보겠습니다. 여기서는 제네릭 클래스를 정의하고 사용하는 방법을 보여줍니다.

class Box<T> {
  T content;

  Box(this.content);
  
  T getContent() {
    return content;
  }
}

void main() {
  var intBox = Box<int>(123);
  var stringBox = Box<String>("Hello, Dart!");

  print(intBox.getContent()); // 123
  print(stringBox.getContent()); // Hello, Dart!
}

실행 결과

123
Hello, Dart!

코드 한 줄씩 동작 설명

  • class Box<T>: T라는 타입 매개변수를 가진 제네릭 클래스를 정의합니다.
  • T content;: T 타입의 content 변수를 선언합니다.
  • Box(this.content);: 생성자에서 content를 초기화합니다.
  • T getContent(): 제네릭 타입 T를 반환하는 메서드를 정의합니다.
  • var intBox = Box<int>(123);: int 타입을 가지는 Box 객체를 생성합니다.
  • var stringBox = Box<String>("Hello, Dart!");: String 타입을 가지는 Box 객체를 생성합니다.
  • print(intBox.getContent());: intBox의 내용을 출력합니다.
  • print(stringBox.getContent());: stringBox의 내용을 출력합니다.
  • 4. 실전 활용 예제

    예제 1: 쇼핑몰에서 장바구니 구현

    장바구니에 다양한 타입의 상품을 담기 위해 제네릭 클래스를 사용할 수 있습니다.

    class CartItem<T> {
      T item;
      int quantity;
    
      CartItem(this.item, this.quantity);
    }
    
    void main() {
      var apple = CartItem<String>("사과", 2);
      var milk = CartItem<String>("우유", 1);
      
      print('${apple.quantity} x ${apple.item}'); // 2 x 사과
      print('${milk.quantity} x ${milk.item}'); // 1 x 우유
    }

    예제 2: API 응답 처리

    API에서 다양한 데이터 구조를 처리할 때 제네릭을 활용할 수 있습니다.

    class ApiResponse<T> {
      bool success;
      T data;
    
      ApiResponse(this.success, this.data);
    }
    
    void main() {
      var response = ApiResponse<List<String>>(true, ["Apple", "Banana"]);
      
      if (response.success) {
        print('Data: ${response.data}'); // Data: [Apple, Banana]
      }
    }

    5. 흔한 실수와 주의사항

    실수 1: 타입 매개변수를 잘못 사용하기

    잘못된 코드:

    var intBox = Box("Hello"); // 타입 매개변수를 지정하지 않음

    올바른 코드:

    var intBox = Box<int>(123); // 타입 매개변수를 명시적으로 지정

    실수 2: 제네릭 타입을 잘못 추론하기

    잘못된 코드:

    var box = Box(123); // 타입이 int로 자동 추론되지 않음

    올바른 코드:

    var box = Box<int>(123); // 타입을 명시적으로 지정

    6. 정리

  • 제네릭을 사용하면 코드의 재사용성과 타입 안전성을 높일 수 있다.
  • 다양한 타입을 다룰 수 있는 제네릭 클래스와 메서드를 활용할 수 있다.
  • 실생활 비유로 이해하면 제네릭의 개념을 쉽게 받아들일 수 있다.
  • 다음에 학습하면 좋은 주제

  • 제네릭의 제약(Constraints) 사용법
  • 다형성과 제네릭의 관계
  • 제네릭을 활용한 데이터 구조 설계