Dart

[Dart] Dart Docs - Generics

  • -
728x90

다른 언어에도(JAVA, Typescript, ...) 존재하는 제네릭이 Dart에도 존재한다.

일반적인 제네릭의 정의는 아래와 같다.

 

제네릭은 데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있는 기술에 중점을 두어 재사용성을 높일 수 있는 방식이다.

 

Why use generics?

제네릭은 자주 타입보장이 필요할 때 사용되지만 코드가 실행가능하도록 많은 이점을 가지고 있다.

  • 제네릭타입을 적절하게 지정하면 코드가 더 잘 생성된다.
  • 제네릭을 사용하여 코드 중복을 줄일 수 있다.

 

예를들어 객체에 대한 캐시용 인터페이스를 생성해보자.

abstract class ObjectCache {
  Object getByKey(String key);
  void setByKey(String key, Object value);
}

 

사용하다보니 객체가 아닌 다른 타입용 인터페이스가 필요해지면 아래와 같이 타입에 맞추어 다른 인터페이스를 생성해야한다.

 

abstract class StringCache {
  String getByKey(String key);
  void setByKey(String key, String value);
}

abstract class NumberCache {
  Number getByKey(String key);
  void setByKey(String key, Number value);
}

...

 

이럴 때 제네릭은 이 모든 인터페이스 생성에 대한 문제를 해결해준다.

abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}

 

 

Using collection literals

리스트, 세트, 맵 리터럴은 매개변수화 되어있다. 무슨 뜻인지 잘 모르겠다. 예시로 알아보자.

void main() {
  /// 타입을 지정하지 않고 선언을 하면 
  /// 런타임 시점에 타입추론을 통해서
  /// Object타입의 배열로 정의된다.
  final coll1 = ["hi", 1, 2, true]; // JSArray<Object>
  
  /// 아래와 같이 선언시, 문자열 배열이기 때문에
  /// 에러가 발생한다.
  /// The element type 'int' can't be assigned to the list type 'String'.
  final coll2 = <String>["hi","hello", 1];
  final coll3 = <String>["say", "yes"]; // JSArray<String>
  final coll4 = <String>{'say', 'yes'}; // _LinkedHashSet<String>
  final coll5 = <String, String>{       // JsLinkedHashMap<String, String>
    'name': 'womillism',
    'hi': 'hello',
  };
}

 

 

다음과 같이 생성자에 매개변수화된 타입을 사용할 수도 있다.

var nameSet = Set<String>.from(names);
var views = Map<int, View>();

 

 

Restricting the parameterized type

제네릭 타입을 구현할 때 인자로 제공되는 타입에 대한 제한을 하고 특정 타입의 하위 타입만 가능하도록 하고 싶을 수 있다.

이때 extends 키워드를 사용하여 할 수 있다.

class Foo<T extends Object> {
  // T에 어느 타입이든 가능하지만 null이 아니어야 합니다.
}

class Foo<T extends SomeBaseClass> {
  // 구현은 여기서...
  String toString() => "Instance of 'Foo<$T>'";
}

var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<Extender>();

 

메소드와 함수에서도 마찬가지로 제네릭을 사용할 수 있다.

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;
}
  • 함수의 반환 타입 (T)
  • 인자의 타입 (List<T>)
  • 로컬 변수의 타입 (T map)
728x90
300x250
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.