๐ŸŽ“ A1Learner
๐Ÿ”
0 of 24 lessons completed

Dart Object Patterns

An object pattern matches a value by its type. It reads named fields of the object into new variables at the same time.

An object pattern in a switch

The first case needs a Point with x equal to 0 and binds its y field to top. The general Point case below it catches the other points.

class Point {
  final int x;
  final int y;

  Point(this.x, this.y);
}

void main() {
  Object value = Point(0, 7);
  switch (value) {
    case Point(x: 0, y: var top):
      print('on axis, y $top');
    case Point(x: var px, y: var py):
      print('point $px $py');
    case _:
      print('not a point');
  }
}

Destructuring an object in a declaration

The declaration pattern binds the two fields to new names. The print adds the renamed fields.

class Point {
  final int x;
  final int y;

  Point(this.x, this.y);
}

void main() {
  var point = Point(3, 4);
  var Point(x: px, y: py) = point;
  print('$px and $py');
  print(px + py);
}

An object pattern with a guard

The guard compares the two bound fields. Equal fields take the first case, and unequal fields move on to the plain Point case.

class Point {
  final int x;
  final int y;

  Point(this.x, this.y);
}

void main() {
  var points = [Point(3, 3), Point(2, 5)];
  for (var point in points) {
    switch (point) {
      case Point(x: var a, y: var b) when a == b:
        print('level at $a');
      case Point(x: var a, y: var b):
        print('point $a $b');
      case _:
        print('not a point');
    }
  }
}

Naming only one field

This pattern names only the x field, so only x is checked. The y value 99 takes no part in the match.

class Point {
  final int x;
  final int y;

  Point(this.x, this.y);
}

void main() {
  Object value = Point(5, 99);
  switch (value) {
    case Point(x: 5):
      print('x is five');
    case Point(x: var px):
      print('x is $px');
    case _:
      print('not a point');
  }
}

Example

class Circle {
  final int radius;

  Circle(this.radius);
}

class Square {
  final int side;

  Square(this.side);
}

void main() {
  var shapes = [Circle(2), Square(3), 'plain'];
  for (var shape in shapes) {
    var label = switch (shape) {
      Circle(radius: var r) => 'circle radius $r',
      Square(side: var s) => 'square side $s',
      _ => 'other shape',
    };
    print(label);
  }
}

Key points

  • An object pattern starts with a class name and lists field patterns in round brackets.
  • A constant in a field position, such as x: 0, must match that exact value.
  • A variable in a field position, such as y: var top, binds the field value to a new variable.
  • Only the fields named in the pattern are read, and fields left out take no part in the match.
  • An object pattern can destructure an object in a declaration, binding its fields to new names.
  • A guard can follow an object pattern and test the values it bound.

In this example, each arm of the switch is an object pattern for one class. The Circle arm binds the radius field and the Square arm binds the side field. The text value matches neither class, so it reaches the wildcard arm.

Note

The pattern checks the type first, so a value of another type moves on to a later case.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท DartPad

Exercise

The pattern Point(x: var px, y: var py) matches Point(3, 4). What do px and py hold?