develop

Dart list.from .of 리스트를 복사하여 사용하는 함수

방뎁 2024. 11. 19. 16:09

List.from 함수는 기존 리스트를 복사하여 새로운 리스트를 생성할 때 사용 되는데,
이 함수는 기존 리스트를 얕은 복사(shallow copy)하거나
필터링 또는 변환을 하여 새로운 리스트를 만들 수 있음


기본 문법

List.from(
  Iterable elements, // 원본 요소들 (필수)
  {bool growable = true} // 새 리스트의 크기 변경 가능 여부 (기본값: true)
)
  • elements: 복사할 원본 Iterable. 일반적으로 리스트를 전달
  • growable: 새 리스트가 가변적(true)인지 고정적(false)인지 결정

사용 사례

1. 리스트 복사

void main() {
  var original = [1, 2, 3];
  var copied = List.from(original);

  print(copied); // [1, 2, 3]

  // 원본과 복사본은 독립적
  copied[0] = 100;
  print(original); // [1, 2, 3]
  print(copied); // [100, 2, 3]
}
  • 얕은 복사이므로 리스트 안에 참조 타입(예: 객체)이 있으면 참조를 공유

2. 고정 크기 리스트 생성

growable 옵션을 false로 설정하면 크기가 고정된 리스트를 생성

void main() {
  var original = [1, 2, 3];
  var fixedList = List.from(original, growable: false);

  print(fixedList); // [1, 2, 3]

  // 고정 리스트는 요소 추가/삭제 불가
  // fixedList.add(4); // 오류 발생: Unsupported operation
}

3. 필터링 및 변환

List.fromIterable을 사용하기 때문에 필터링 및 변환을 쉽게 결합 가능

void main() {
  var numbers = [1, 2, 3, 4, 5];

  // 필터링된 리스트 복사
  var evenNumbers = List.from(numbers.where((n) => n.isEven));
  print(evenNumbers); // [2, 4]

  // 변환된 리스트 복사
  var doubled = List.from(numbers.map((n) => n * 2));
  print(doubled); // [2, 4, 6, 8, 10]
}

4. 중첩 리스트 복사 (얕은 복사)

List.from은 기본적으로 얕은 복사를 수행 -> 첩 리스트 내부의 요소는 원본과 참조를 공유

void main() {
  var original = [
    [1, 2],
    [3, 4]
  ];
  var copied = List.from(original);

  copied[0][0] = 100;

  print(original); // [[100, 2], [3, 4]]
  print(copied); // [[100, 2], [3, 4]]
}

List.from과 다른 복사 방법 비교

Dart에서 리스트 복사는 여러 방법으로 가능하기 때문에 각각 상황에 맞는 복사 방법 선택 할 수 있음

방법 설명 깊은 복사 지원 여부
List.from 기존 리스트를 기반으로 새 리스트 생성 ❌ (얕은 복사)
.toList() Iterable를 리스트로 변환 ❌ (얕은 복사)
List.of Iterable를 기반으로 리스트 생성 ❌ (얕은 복사)
수동 복사 (for) 각 요소를 새 리스트로 직접 추가 ✅ (깊은 복사 가능)

깊은 복사

깊은 복사는 수동으로 요소를 복사해야 합니다.

void main() {
  var original = [
    [1, 2],
    [3, 4]
  ];

  var deepCopied = original.map((innerList) => List.from(innerList)).toList();

  deepCopied[0][0] = 100;

  print(original); // [[1, 2], [3, 4]]
  print(deepCopied); // [[100, 2], [3, 4]]
}

List.from 사용 시 주의점

  1. 얕은 복사:
    • 리스트 내부에 객체(참조 타입)가 있으면 복사된 리스트와 원본 리스트가 같은 객체를 참조
    • 독립적인 데이터가 필요하면 깊은 복사를 고려해야 
  2. growable 옵션:
    • 기본적으로 가변적(true)으로 설정되지만, 고정 크기 리스트를 원하면 growable: false로 설정하면됨
  3. 성능:
    • 리스트가 매우 크거나 중첩 구조가 복잡하다면 복사 비용 즉 메모리 소모 혹은 뻗을 가능성 있음

결론

얕은 복사로 인해 참조 공유 문제가 발생할 수 있으므로, 필요한 경우 수동으로 깊은 복사를 구현해야 함
for문이 마냥 나쁜것이 아니다~.