제네릭 (generic)

ssh·2023년 12월 10일
0

dart

목록 보기
12/22

개요

제네릭이란?

  • 제네릭(generics)은 Dart에서 사용되는 강력한 기능 중 하나이다.
  • Collection을 정의할 때 많이 활용된다.
    • < ... > 괄호를 활용하여 그 안에 타입을 지정하는 것을 제네릭이라고 한다.
      (정식 유형 매개 변수가있는 타입)
    • 관례상 대부분의 타입 변수는 E, T, S, K, V 같은 single-letter 이름을 가진다.
    • List 혹은 List 이렇게 사용하면서 리스트에 String 타입만 담을 것인지 , int 타입만 담을 것인지를 정할 수 있는데 여기서 이미 제네릭을 사용한 것이다.
    • List, Set, Map 같은 collection 선언시에도 Generics 표현에 의해 타입이 명확해 진다.
      • 코드
        // List : [] -> <type>[]
        // Set : {} -> <type>{}
        // Map : { : } -> <type, type>{ : }
        
        var names = <String>['Seth', 'Kathy', 'Lars'];
        var uniqueNames = <String>{'Seth', 'Kathy', 'Lars'};
        var pages = <String, String>{
          'index.html': 'Homepage',
          'robots.txt': 'Hints for web robots',
          'humans.txt': 'We are people, not machines'
        };

사용이유

  • 제네릭은 코드의 재사용성과 가독성을 향상시키고 타입 안정성(Type Safety)보장하는 데 도움을 준다.
  • 따라서 Dart에서는 제네릭을 사용하여 유연하고 안전한 코드를 작성할 수 있다.
  • 제네릭은 함수나 클래스의 인수, 반환 값, 변수의 타입을 일반화(generalize)하는 방법을 제공한다.
  • 일반적인 데이터 타입 대신에 타입 매개변수(type parameter)를 사용하여 여러 위치에서 동일한 코드를 재사용할 수 있다.
  • 제네릭을 사용하면 데이터 타입에 대한 추상화를 가능하게 한다.
    • 예를 들어, List를 생각해보면, 제네릭을 사용하지 않을 경우 다양한 데이터 타입을 담을 수 없다. 하지만 제네릭을 사용하면 다양한 타입의 리스트를 생성할 수 있다.
    • 이렇게 제네릭을 사용하면 컴파일러가 타입 체크를 수행하므로 타입 안정성을 보장할 수 있다.
    • 여러가지 데이터 타입에 대해 동일한 동작을 해야 하는 코드가 있다면, 데이터 타입별로 코드를 생성할 필요 없게되어 코드를 줄일 수 있다.
      • 코드
        // Object specific class
        abstract class ObjectCache {
          Object getByKey(String key);
          void setByKey(String key, Object value);
        }
        // String specific class
        abstract class StringCache {
          String getByKey(String key);
          void setByKey(String key, String value);
        }
        // Generic type
        abstract class Cache<T> {
          T getByKey(String key);
          void setByKey(String key, T value);
        }
  • 성능적인 이유
    • 데이터 타입에 따라 컴퓨터가 할당하는 메모리 용량에는 차이가 있다.
    • 데이터 타입을 지정하지 않고 코딩한다면 컴퓨터가 타입을 지정했을때보다 많은 메모리를 할당해야하고 프로그램의 질 하락으로 이어질 가능성도 부정할 수는 없다고 봐야한다.

사용방법

  • Dart에서 제네릭을 사용하려면 클래스나 함수를 정의할 때 타입 매개변수를 사용해야 한다.
  • 타입 매개변수는 일반적으로 대문자로 표시되며, 함수나 클래스 내부에서 해당 타입을 사용할 수 있다.
  • 여러 타입의 값을 파라미터로 받는 constructor 를 하나의 함수로 구현할 수 있다.
    • 코드1
      Set<E>.from(Iterable elements) constructorvar nameSet = Set<String>.from(names);
      var ageSet = Set<int>.from(ages);
    • 코드2
      Map<K, V>() constructorvar views = Map<int, View>(); // integer keys and values of type View
      var views = Map<double, String>(); // double keys and string value
  • generic 타입을 적용할 때 클래스의 파라미터의 타입을 제한할 수 있다.
    • extends 를 사용해 제한하는 방법
      • 코드
        class Foo<T extends Object> {
          // null을 제외한 모든 타입은 Object를 상속하기에 null 제외하기 위해 Object 상속
        }
        
        class SomeBaseClass {}
        
        class Boo<T extends SomeBaseClass> {}
        
        class Extender extends SomeBaseClass {}
        
        var someBaseClassFoo = Foo<SomeBaseClass>();
        var extenderFoo = Foo<Extender>(); // 하위 클래스
        
        var foo = Foo();
        print(foo); // Instance of 'Foo<SomeBaseClass>'
  • generic은 method, function 의 파라미터에도 적용할 수 있다.
    • 함수의 리턴타입, argument 의 타입, 내부 변수의 타입에 generic type 이 쓰였다.
      • 코드
        T first<T>(List<T> ts) {
          // Do some initial work or error checking, then...
          T tmp = ts[0];
          // Do some additional checking or processing...
          return tmp;
        }

주의점

  • dynamic같은 어떤 형태나 올 수 있는 제네릭은 지양하는 것이 좋다.
    • 들어오는 데이터가 정리가 제대로 안되어 dynamic말고는 해결책이 없는 상황에서만 사용하는 것이 좋다.

기타

  • Dart의 generic타입들은 Java 와 다르게 런타임 동안 타입의 정보가 없어지지 않는다.
    • 코드
      var names = List<String>();
      names.addAll(['Seth', 'Kathy', 'Lars']);
      print(names is List<String>); // true

예제

void main() {
Lecture<String, String> lecture1 = Lecture(
  '123',
  'lecture1',
);

lecture1.printIdType();

Lecture<int, String> lecture2 = Lecture(
  123,
  'lecture2',
);

lecture2.printIdType();
}

// generic - 타입을 외부에서 받을때 사용
class Lecture<T, X> {
final T id;
final String name;

Lecture(
  this.id,
  this.name,
);

void printIdType() {
  print(id.runtimeType);
}
}

0개의 댓글

관련 채용 정보