Dart Collection

1. Dart’s Three Built-in Collection Types

Dart ships with three native collection types: List, Set, and Map.

Generic type constraints can be applied to restrict the data types stored inside each collection via Generics.

Collection TypeCore FeaturesLiteral Syntax
ListOrdered, allows duplicate entries, index-based access[]
SetUnordered, unique values only, no index access{} (explicit generic annotation required to create a Set)
MapKey-value storage, unique keys, duplicate values permitted{key: value}

2. List (Ordered Arrays)

1. Basic Definition & Type Inference

  • Arrays in Dart are implemented as List objects, instantiated with the [] literal syntax;
  • Types are inferred automatically. For example: var list = [1,2,3] resolves to List<int>; inserting non-integer values will throw a compile error;
  • Trailing commas are fully supported without breaking syntax, which reduces copy-paste bugs: var list = ['Car', 'Boat', 'Plane',];

2. Core Operations

  1. Index rules: Indexes start at 0; the last element’s index is list.length - 1;
  2. Read / update elements: list[index], list[index] = newValue;
  3. Retrieve total element count: .length property;

Example

void main() {
	var list = [1,2,3];
	print(list.length);// Prints total element count: 3
	print(list[1]);// Outputs 2
	list[1] = 9; // Update the second element to 9
	print(list[1]);// Outputs updated value: 9
}Code language: Dart (dart)

3. Constant Lists (Compile-Time Immutable)

Prefix the literal with const to create an immutable list; elements cannot be added, removed or modified at runtime:

void main() {
	var constantList = const [1,2,3];
	constantList[1] = 100; // Throws compile error
}Code language: Dart (dart)
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
Unsupported operation: Cannot modify an unmodifiable list
#0      UnmodifiableListMixin.[]= (dart:_internal/list.dart:89:5)
#1      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:4:14)
#2      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#3      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)

3. Set Collections

Unordered collection with unique values only

1. Core Set Characteristics

  • Unordered storage: No fixed index positions; values cannot be read or updated via bracket indexing [index]
  • Automatic value uniqueness: Duplicate entries are silently discarded; no runtime error is thrown when adding duplicates
  • Literal syntax: Curly braces {}
  • Generic type restrictions: Lock storage to a single data type; inserting mismatched types triggers compile or runtime errors

Differentiating empty Set vs empty Map (Common Pitfall)

Bare {} defaults to a Map. To create an empty Set you must explicitly declare the generic type parameter.

void main() {
	// Empty Set<String>
	var names = <String>{};
	Set<String> names2 = {}; // Equivalent declaration

	// No generic annotation; Dart infers Map<dynamic, dynamic>
	var names3 = {};
}Code language: Dart (dart)
Type Inference Rules
void main() {
	// Automatically inferred as Set<String>
	var halogens = {'dog', 'cat', 'horse'};

	// Automatically inferred as Set<int>
	var nums = {1, 2, 6, 2}; // Duplicate value 2 is deduplicated, final set: {1,2,6}

	// Mixed value types inferred as Set<Object> (not recommended, disables strict type checking)
	var mix = {1, "apple"};
}Code language: JavaScript (javascript)

Once the type is inferred, inserting values of a different type will throw an error.

void main() {
  // All literal values are strings, inferred as Set<String>
  var animals = {'dog'};
  print(animals.runtimeType); // _CompactLinkedHashSet<String>

  // Adding matching string values works with no errors
  animals.add('cat');
  animals.add('pig');
  print(animals); // {dog, cat, pig}
  
  // Error: Cannot pass int to add(), which expects a String argument
  animals.add(1); 
}Code language: Dart (dart)

2. Add, Remove & Length

  • Add single element: .add();
  • Bulk add multiple elements: .addAll();
  • Get total element count: .length;
var elements = <String>{};
elements.add('fluorine');
elements.addAll({'chlorine', 'bromine'});
print(elements.length); //3Code language: PHP (php)

3. Constant Sets

Prefix the literal with const to create a read-only Set; no new elements can be added or removed:

final constantSet = const {'fluorine', 'chlorine'};
// constantSet.add('helium'); // Throws errorCode language: PHP (php)

4. Map (Key-Value Mappings)

1. Base Features
  • Stores paired Key-Value data entries;
  • Keys are globally unique, duplicate values are allowed;
  • Keys and Values support any object type;
  • Literal format: {key: value};
  • Automatic type inference:
void main() {
	var gifts = {'first': 'partridge'}; // Inferred Map<String, String> 
	
	var nobleGases = {2: 'helium'}; // Inferred Map<int, String>
}Code language: Dart (dart)
2. Two Map Initialization Styles
  • Literal initialization
var gifts = {'first': 'partridge'};  Code language: Dart (dart)
  • Map constructor syntax (the new keyword is optional)
// Constructor initialization
var gifts = Map<String, String>();
gifts['first'] = 'partridge';Code language: JavaScript (javascript)
3. Insert, Lookup & Length
  1. Add or overwrite key-value pairs: map[key] = value;
  2. Retrieve value by Key: map[key]; returns null if the key does not exist;
  3. Get total key-value entry count: .length;
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // Insert new entry
print(gifts['first']); // Lookup value
print(gifts['fifth']);// Lookup non-existent key
print(gifts.length); // Get total entry count Code language: PHP (php)
4. Constant Maps

Prefix the literal with const to lock the map; key-value pairs cannot be modified:

final constantMap = const {2: 'helium', 10: 'neon'};
// constantMap[2] = 'Helium'; // Throws errorCode language: Dart (dart)

5. Enhanced Collection Literal Syntax

Collection literals support multiple special syntax forms, split into two categories: base leaf elements and control flow elements, which simplify building complex collections inline.

  1. Base leaf elements: Single expressions, Map key-value pairs, null-safe optional entries
  2. Control flow elements: Spread operators, conditional if blocks, for loops, and nested combinations

1. Standard Expression Elements

The most basic syntax: write raw expressions directly; their evaluated results are inserted into the collection. In the sample below, the second element is calculated via 2 * 3, producing the final list [1, 6, “text”].

void main() {
	var list = [1, 2 * 3, 'text'];
	print(list); //[1, 6, text]
}Code language: PHP (php)

2. Key-Value Elements

Exclusive to Map literals, formatted as keyExpression : valueExpression. The example below uses dynamic expressions to generate both the first entry’s key and value.

void main() {
	var map = {1+1: 3*8, 'name': 'apple'};
	print(map); //{2: 24, name: apple}
}Code language: Dart (dart)

3. Null-Safe Optional Elements (Dart ≥3.8)

Syntax: ?expression. The entry is only inserted if the expression evaluates to non-null; null values are silently discarded.

Usage inside List: variable a is null so it is omitted from the final list, no runtime error occurs.

int? a = null;
int? b = 3;
var items = [1, ?a, ?b, 5]; // [1, 3, 5]Code language: JavaScript (javascript)

Usage inside Map (both keys and values support the ? operator)

String? k = null;
int? v = null;
var m = {?k: ?v}; // If either key or value is null, the entire pair is dropped
Code language: JavaScript (javascript)

4. Spread Elements

① Standard Spread ...

Flattens all items from an iterable collection and inserts them inline; cannot spread null collections

var a = [1,2,3];
var items = [0, ...a, 4]; // [0,1,2,3,4]Code language: JavaScript (javascript)
② Null-Safe Spread ...?

Safely handles nullable collections: if the source collection is null, the spread is ignored with no error;

If the collection itself is non-null but holds null values internally, those null entries remain preserved.

List<int>? a = null;
var b = [1, null, 3];
var items = [0, ...?a, ...?b, 4]; // [0, 1, null, 3, 4]Code language: PHP (php)

Coding convention: Always use ...? for nullable iterables, otherwise a compile error will be thrown.

5. If Conditional Elements

Inline if branches directly inside collection literals; entries are only injected when the condition evaluates true. Supports boolean checks, if-case pattern matching, and else clauses.

Basic Boolean Conditions
void main() {
	bool flag = true;
    var list = [0, if(flag) 1 else 99, 2];
	print(list); //[0, 1, 2]
}Code language: Dart (dart)
if-case Pattern Matching (Type & List Destructuring)
void main() {
	Object data = 123;
	var info = [
	  if(data case int i) 'Number: $i',
	  if(data case String s) 'Text: $s'
	];
	print(info); //['Number: 123']
}Code language: Dart (dart)

Since data is an integer, only the “Number: 123” entry is added; the text branch is skipped entirely.

6. For Loop Elements

Inline for loops inside collection literals to generate multiple entries dynamically; both for-in and standard three-segment for loops are supported.

var nums = [2,3,4];

// for-in iteration
var list1 = [1, for(var n in nums) n*n, 7]; // [1,4,9,16,7]

// Traditional three-part for loop
var list2 = [1, for(var x=5; x>2; x--) x, 7]; // [1,5,4,3,7]Code language: JavaScript (javascript)

7. Nested Control Flow

if statements, for loops, and spread operators can be nested arbitrarily deep, offering functionality equivalent to list comprehensions found in other languages.

Example: Filter to retain only even numbers

var numbers = [1,2,3,4,5,6];
var items = [
  0,
  for(var n in numbers)
    if(n.isEven) n,
  8
]; // [0,2,4,6,8]Code language: JavaScript (javascript)

Example: Nested for + if + spread operator combination

void main() {
	var ys = [1,2,3];
	var nest = [
	  ...[
		for(var x=0;x<2;x++)
		  for(var y in ys)
			if(x<y) x+y*10
	  ]
	];
	print(nest); //[10, 20, 30, 21, 31]
}Code language: Dart (dart)

Previous:

Leave a Reply

Your email address will not be published. Required fields are marked *