본문 바로가기
Dart, Flutter for App

Dart - 컬렉션(List, Map, Set)+Dynamic 타입

by Oliver J 2024. 2. 7.
반응형

데이터 구조에 따른 대표적인 컬렉션으로 List, Map, Set이 있습다.

  1. List 는 아이템의 중복을 허용하는 구조로서, 순서를 가질 수 있습니다.
  2. Map 은 키(key)와 값(value)의 쌍으로 저장되는 구조로서 키의 중복은 불가합니다.
  3. Set은 순서가 없는 집합으로서 중복이 불가합니다. 혹시라도 중복된 값을 여러 개 추가할 경우에는 해당 값은 한 개만 남아있게 됩니다.
  final List<String> strList = ['홍길동', '홍당무', '한석봉'];

  for(int i=0; i<strList.length;i++){
    print(strList[i]);
  }

  for (String name in strList) {
    print(name);
  }

	strList.forEach((name) {
    print(name);
  });

  personList.forEach(print);

 

만약에 위와 같이 List 에 String을 담았을 경우, List 내부의 데이터를 탐색하는 방법이 여러가지 있습니다.

 

Map은 아래와 같이 키와 값의 쌍으로 저장되는 구조이며, keys, values, entries로 각각 데이터에 접근이 가능하며, 특히 key값으로 해당 key의 value에 접근이 가능합니다.

Map<String, dynamic> student = {
    'name': '학생A',
    'id': 0,
    'class': 'A-1',
  };

  print(student.entries);
  print(student.values);
  print(student.keys);
  print(student['name']);

 

그리고 자주 사용되어지는 방식으로 데이터가 많을 때에는 List를 Map위에 감싸서 사용합니다.

List<Map<String, dynamic>> studentList = [{
    'name': '학생A',
    'id': 0,
    'class': 'A-1',
  },{
    'name': '학생B',
    'id': 1,
    'class': 'B-2',
  }];

 

위에서 사용된 dynamic타입은 아래의 예시와 같이 모든 타입의 변수를 다 받아들일 수 있는 최상위 타입으로서, Map의 경우 편리하게 사용할 수 있지만, 타입의 안전성 측면에서 여러모로 사용에 주의하여야 합니다.

반응형
// anti-pattern
final numbers = [];
final List<int> numbers2 = [];

numbers.add(1);
numbers.add("2");
numbers.add(true);
numbers.add(null);
print(numbers);

 

타입을 명시적으로 사용하지 않을 경우나 dynamic 타입을 무분별하게 사용하게 될 경우, 코드를 읽기도 어려울 뿐더러 어떠한 값도 들어갈 수 있게 되기 때문에 차후 어떠한 상황이 나타날지 알 수 없게 됩니다.

 

dynamic a = 10;
print(a.runtimeType); // result : int
print(a + true); // 런타임 시점에 오류를 알 수 있음. 실행전에는 No Error

 

특히 위의 코드 중 하단 부분을 보면 알 수 있듯이, dynamic타입으로 선언한 a의 경우 int 타입과 bool타입의 true 도 더하기가 가능한 것으로 보이지만 런타임 시점에 에러를 보여줍니다. 이는 정말 위험한 상황을 초래할 수 있습니다. 이러한 상황은 메서드에서 return타입을 설정하지 않고 사용했을 때에도 동일한 결과를 초래하게 됩니다.

 

아래와 같이 Object의 경우에는 컴파일 시점에 오류를 알 수 있으므로, 코드의 안전성 측면에서 dynamic보다 좋다고 볼 수도 있습니다.

Object a = 10;
print(a.runtimeType);
print(a + true); // Error. 컴파일 시점에 오류를 알 수 있음
final Set<int> lottoSet = {1, 2, 4, 6, 8, 43};

print(lottoSet.contains(3)); // false
print(lottoSet.contains(43)); // true

 

중복 값을 허용하지 않는 Set 의 경우에는 별도의 get()메서드를 제공하지 않으며, 인덱스를 제공하지 않기에 위의 for 문에서 strList[i] 같은 방식으로 접근이 불가능합니다. 하지만 List 의 contains에 비하여 Set의 contains는 굉장히 빠른 속도를 자랑하기에 인덱싱이 필요없으나 빈번한 데이터 호출이 필요할 경우 유용하게 활용할 수 있습니다.

또한, 아래와 같이 순서를 보장하지 않더라도 데이터에 접근이 가능합니다. Set을 iterator로 변환하여 moveNext 와 iterator.current 로 데이터를 빼내는 방법도 있습니다.

for(int numb in lottoSet){
    print(numb);
  }

final iterator = lottoSet.iterator;
  while (iterator.moveNext()) {
    print(iterator.current);
  }

 

그리고 indexed 함수를 통하여 IndexedIterable 로 데이터에 접근할 수 있습니다.

728x90
반응형