Summary

  • 셋 모두 Iterable object를 동일한 element를 가진 새 List로 copy할 때 사용할 수 있다.
  • toList()List.of의 short-hand method로 서로 같다.
  • List.from은 original Iterable의 element들을 runtime에 result type으로 casting하고, casting에 실패하면 runtime error를 발생시킨다.
  • List.of는 original Iterable의 element들이 result type과 같거나 하위 type인지 compile-time에 check하고, type이 호환되지 않으면 compile-time error를 발생시킨다.
  • List.from은 original Iterable을 down casting할 때 사용할 수 있고, List.of는 up casting할 때 사용할 수 있다.
  • Copy 할 때 original type을 지켜야 한다면 toList() 또는 List.of를 사용하고, type을 변경할 때만 List.from을 사용하자.

List.from(elements)

  • elementsIterable type을 전달하여 새로운 List 생성
  • Definition
    external factory List.from(Iterable elements, {bool growable = true});
    
  • elements의 item type을 고려하지 않기 때문에 새로 생성하는 list의 item type을 지정하지 않으면 List<dynamic>으로 생성됨
    final nums = [1, 2, 3]; // List<int>
    final dynamicList = List.from(nums);
    print(dynamicList.runtimeType); // List<dynamic>
    
  • 새로 생성하는 list의 item type을 지정하면 elements의 item type이 type casting됨
    final nums = [1, 2, 3]; // List<int>
    final numList = List<num>.from(nums);
    print(numList.runtimeType); // List<num>
    
  • 새로 생성하는 list의 item type이 runtime에 결정된다. 즉, compile-time에 type check를 하지 않는다.
    • String type인 "3"int로 직접 type casting 할 수 없으므로 type error가 발생한다.
      final nums = [1, 2, "3"]; // List<Object>
      // TypeError: "3": type 'String' is not a subtype of type 'int'
      final intList = List<int>.from(nums);
      
    • double type인 3.0int로 casting 가능하므로 runtime error가 발생하지 않지만, 여전히 compile time에는 알 수 없다.
      final nums = [1, 2, 3.0]; // List<num>
      final intList = List<int>.from(nums);
      print(intList.runtimeType); // List<int>
      

List.of(elements)

  • elementsIterable type을 전달하여 새로운 List 생성 => 역할은 List.from과 같음
  • Definition
    external factory List.of(Iterable<E> elements, {bool growable = true});
    
  • elements의 item type과 새로 생성하는 list의 item type이 같으므로, 생성하는 list의 item type을 지정하지 않으면 elements의 item type을 따라간다.
    final nums = [1, 2, 3]; // List<int>
    final  = List.of(nums);
    print(intList.runtimeType); // List<int>
    
  • 새로 생성하는 list의 item type을 지정하면 elements의 item type도 같은 type이어야 한다. elements에 다른 item type을 가진 list를 전달하면 compile error가 발생한다.
    final nums = <num>[1, 2, 3]; // List<int>
    // Error: The argument type 'List<num>' can't be assigned to the parameter type 'Iterable<int>'.
    final intList = List<int>.of(nums);
    
  • 단, 새로 생성하는 list의 item type이 elements item type의 상위 type이라면 up casting 될 수 있다.
    final nums = [1, 2, 3]; // List<int>
    final  = List<num>.of(nums);
    print(intList.runtimeType); // List<num>
    

.toList()

List<E> toList({bool growable = true}) => List<E>.of(this, growable: growable);
  • List.of의 shortcut method
  • List.of로 감싸는 대신 toList()를 사용하는게 더 간단하다.

Don’t use List.from unless you intent to change the type of the result

  • Effective Dart 문서에서는 result type을 의도적으로 바꾸고 싶을 때만 List.from을 사용하도록 제한한다.
  • 이외에 original Iterable과 result List의 element type이 같은 경우에는 List.of 또는 toList()를 사용한다.
  • List.of도 공통된 상위 type으로 up casting이 가능하지만, original type을 유지하지 않는 경우에는 모두 List.from을 사용하는게 일관성을 지킬 수 있을 것 같다.