Flutter Study Day 8 Dart Generic

정정원·2023년 12월 8일
0

Flutter Study

목록 보기
10/17

generics

기본 배열 타입의 API 문서를 보면, List 타입이 List<E>로 표기되어 있는 걸 볼 수 있습니다. <…> 표시는 List를 형식 타입 매개변수를 가지는 제네릭 (또는 매개변수화된) 타입으로 지정합니다. 관례상 대부분의 타입 변수는 E, T, S, K, V 같은 single-letter 이름을 가집니다.

제네릭은 보통 타입 세이프티 때문에 사용하지만, 사실 더 많은 기능을 수행한다.

  • 제네릭 타입을 적절하게 명시한 코드는 잘 작성된 코드다.
  • 코드 중복을 줄이기 위해 제네릭을 사용한다.

리스트가 문자열 값만 가지게 하고 싶다면, List<String>으로 리스트 선언하면 된다. 이렇게 하면 협업 할 경우 문자열 이외의 값은 리스트에 추가 될 수 없음을 바로 알 수 있다.

// X static analysis: error/warning
var names = <String>[];
names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // Error

제네릭을 사용하는 또 다른 이유는 코드 중복을 줄이기 위함이다. 제네릭은 정적인 분석의 이점을 챙기면서, 많은 타입들이 단일 인터페이스와 구현을 공유할 수 있게 한다.

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

제네릭 타입은 위처럼 모든 인터페이스를 생성해야하는 문제를 해결해준다. 타입 매개변수를 가지는 하나의 단일 인터페이스만을 구현하면 된다.

//T는 대체 타입으로 개발자가 추후에 타입을 마음대로 지정할 수 있게 해주는 플레이스 홀더입니다.
abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}

컬렉션 리터럴 사용하기

List,set 그리고 map 리터럴은 매개변수화 될 수 있다. 매개변수화된 리터럴은 list, settype 또는 map<keyType, valueType>를 시작 괄호에 추가하는 것만 빼면, 일반적으로 사용하는 리터럴과 비슷하게 생겼다.

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

생성자에 매개변수화된 타입 사용

var nameSet = Set<String>.from(names);
//정수와 View타입의 값을 가지는 map
var views = Map<int, View>();

제네릭 컬렉션

제네릭 타입은 구체화 되어있다. 제네릭 타입은 런타임에 타입들에 대한 정보를 가져온다.

var names = <String>[];
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true

매개변수화된 타입 제한

제네릭 타입을 구현할 때, 인자로 제공되는 타입을 제한해서 인자가 특정타입의 서브타입이 되게해야할 경우가 발생한다. 이럴경우 extends를 사용하면 된다.

Non-nullalbe인 것을 보장하기 위해, 디폴트인 Object?대신 Object의 서브타입으로 만들 때 자주 사용된다.

class Foo<T extends Object> {
  // Foo에게 제공되는 T 타입은 반드시 non-nullable 입니다.
}

Object 이외의 타입들과 함께 extends를 사용 할 수있다. 다음은 SomeBaseClass를 확장하는 예로, SomeBaseClass의 멤버들은 타입 T의 객체로 볼 수 있다.

class Foo<T extends SomeBaseClass> {
  // 클래스 구현 ...
  String toString() => "Instance of 'Foo<$T>'";
}

class Extender extends SomeBaseClass {...}

SomeBaseClass나 서브타입을 제네릭 인자로 사용하는 것도 가능하다.

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

제네릭 인자를 특정하지 않는 것도 가능하다.

var foo = Foo();
print(foo); // 'Foo<SomeBaseClass>'의 인스턴스

Non-SomeBaseClass 타입으로 특정하는 것은 에러를 발생시킨다.

var foo = Foo<Object>();

제네릭 메서드 사용하기

메서드와 함수에도 타입 인자를 사용할 수 있다.

T first<T>(List<T> ts) {
  // 초기 작업 또는 에러 확인, 그리고 ...
  T tmp = ts[0];
  // 추가적인 확인 또는 프로세싱 ...
  return tmp;
}

first ()에 있는 제네릭 타입 매개변수로 여러 위치에서 타입 인자인 T를 사용할 수 있다.

  • 함수의 반환 타입 (T).
  • 인자의 타입 (List).
  • 지역 변수의 타입 (T tmp).

0개의 댓글