Dart/testData/parsing/Patterns.dart (425 lines of code) (raw):
main() {
final (a as A || b? && c! || == d && != e << f >>> g >> h & i ^ j | k-- + ~l++ - !m * +n / -o % ++p ~/ --r ) = null;
@foo() final (lat, long) = geoCode('Aarhus');
final ((a, b) && record) = (1, 2); // Parentheses.
var [a, b] = [1, 2]; // List.
var {1: a, 2: b} = {1: 2}; // Map.
var (a, b, x: x) = (1, 2, x: 3); // Record.
var Point(x: x, y: y) = Point(1, 2); // Object.
for (@foo final (lat, long) in bar) {}
for (@foo final ((a, b) && record) in bar) {}
for (@foo var [a, b] in bar) {}
for (var [a, b] in bar) {}
for (var {1: a} in bar) {}
for (var (a, b, x: x) in bar) {}
for (var Point.a(x: x, y: y) in bar) {}
(notFinal, unassignedFinal, lateFinal) = ('a', 'b', 'c');
((a, b) && record) = 1;
(a && a) = 2;
[a, b] = [a, b];
{1: a, 2: b} = {1: 2};
Point(x: x, y: y) = Point(1, 2);
}
foo() {
switch (shape) {
case Square(size: var s) || Circle(size: var s) when s > 0:
print('Non-empty symmetric shape');
case Square() || Circle():
print('Empty symmetric shape');
default:
print('Asymmetric shape');
}
switch (list) {
case ['a' || 'b', var c]:
case {1: a, 2: b} when 1 == 2:
case (a as A || b? && c! || == d && != e << f >>> g >> h & i ^ j | k-- + ~l++ - !m * +n / -o % ++p ~/ --r):
case 5 + 5 * 2:
case a + a:
case -a:
case (a, b, x: x):
case (5 + 5 * 2):
case const [a, b]:
case SomeClass(1, 2):
case const SomeClass(1, 2):
case const (A + A):
case const (A + 'b'):
case const (-ER):
case const (List<RPChoice>):
case const (720 * 1280):
case a when b:
case a when b > c:
case var s?: foo();
}
}
bar() {
var [...] = [1, 2];
var [...x] = [1, 2];
var [int a, num b] = [1, 2];
var <int>[a, b] = <num>[1, 2]; // List<int> (and compile error).
var [a, b] = <num>[1, 2]; // List<num>, a is num, b is num.
var [int a, b] = <num>[1, 2]; // List<num>.
var (int a, int b) = null;
var (int? a, int? b) = (null, null);
switch ((1, 2)) {
case Square(size: var s) || Circle(size: var s) when s > 0:
case (int a, int b) when a > b:
// case (int a, int b) foo:
print('First element greater');
break;
case (int a, int b):
print('Other order');
break;
case [int a, int n] when n > 0:
case {"a": int a}:
}
switch (n) {}
var a = switch (n) {} //error
}
iff() {
if (json case [int x, int y]);
if (json case [int x, int y] when x == y);
if (x case int(isEven: true));
switch (n) {
1 => a,
2 =>> recover,
_ => c
}
}
// Define multiple returns
(double, double) geoCode(String city) {
var lat = city == 'Aarhus' ? 56.1629 : 0.0;
var long = city == 'Aarhus' ? 10.2039 : 0.0;
return (lat, long);
}
void f00() {
{
// Use multiple returns
final (lat, long) = geoCode('Aarhus');
print('Location lat:$lat, long:$long');
}
{
// Destructure list
var list = [1, 2, 3];
var [a, b, c] = list;
print(a + b + c); // 6.
}
{
// Destructure map
var map = {'first': 1, 'second': 2};
var {'first': a, 'second': b} = map;
print(a + b); // 3.
}
{
// Destructure and assign to existing variables
var (a, b) = ('left', 'right');
(b, a) = (a, b); // Swap!
print('$a $b'); // Prints "right left".
}
}
abstract class Shape {
double get size;
}
class Square implements Shape {
final double length;
const Square(this.length);
@override
double get size => length;
}
class Circle implements Shape {
final double radius;
Circle(this.radius);
@override
double get size => radius;
}
double calculateArea(Shape shape) =>
// Switch wth object patterns, from algebraic datatype example
switch (shape) {
Square(length: var l) => l * l,
Circle(radius: var r) => math.pi * r * r
};
late Color color;
var isPrimary = switch (color) {
// Simple logical-or pattern
Colors.red || Colors.yellow || Colors.blue => true,
_ => false
};
void describeShape(Shape shape) {
// Logical-or pattern where multiple patterns share a guard
switch (shape) {
case Square(size: var s) || Circle(size: var s) when s > 0:
print('Non-empty symmetric shape');
case Square() || Circle():
print('Empty symmetric shape');
default:
print('Asymmetric shape');
}
}
String? describeList(List<String> list) {
// Destructuring logical-or pattern in switch statement
switch(list) {
case ['a' || 'b', var c]:
return 'a or b and $c';
default:
return null;
}
}
bool isAorBandAnother(List<String?> list) {
// Destructuring logical-or pattern in switch expression
return switch(list) {
['a' || 'b', var c] => c != null,
_ => false
};
}
String asciiCharType(int char) {
const space = 32;
const zero = 48;
const nine = 57;
// Relational pattern
return switch(char) {
== space => 'space', // Analyzer reports all below is dead code. 6Feb23
< space => 'control',
> space && < zero => 'punctuation',
>= zero && <= nine => 'digit'
// Etc...
};
}
void f01() {
// Cast pattern
(num, Object) record = (1, 's');
var (i as int, s as String) = record;
print('$i $s');
// Null-check pattern
String? maybeString = describeList([]);
switch (maybeString) {
case var s?:
// s has type non-nullable String here.
geoCode(s);
}
(int?, int?) getPair(String s) => s.length > 2 ? (1,2) : (null, null);
// Null-assert pattern
var pair = getPair('test');
var (lat!, long!) = pair;
print('Location lat:$lat, long:$long');
List<String?> row = ['user', 'Abe'];
switch (row) {
case ['user', var name!]:
// name is a non-nullable string here.
geoCode(name);
}
}
String f02(Object selector) {
// Constant patterns
switch (selector) {
case true || false : return 'bool';
case 1 || -1 : return 'one';
case math.pi : return 'qualified name';
case ['a', 'b'] : return 'list literal';
case const Square(3) : return 'constructor';
case const (3 + 4) : return 'const expr';
}
return '';
}
void f03(Object record) {
// Variable patterns
switch ((1, 2)) {
case (var a, var b): print('$a $b');
}
switch (record) {
case (int x, String s):
print('First field is int $x and second is String $s.');
case (String _, int _):
print('First field is String and second is int');
case (var n, final m):
print('$n $m');
}
}
// Parenthesized patterns
void f05(List<String> l) {
switch (l) {
case ('a' || 'b'): break;
}
}
// Rest elements and type annotations
void f06() {
var [a, b, ...rest, c, d] = <int>[1, 2, 3, 4, 5, 6, 7];
print('$a $b $rest $c $d'); // Prints "1 2 [3, 4, 5] 6 7".
var map = <String, int>{'first': 1, 'second': 2, 'third': 3};
var {'first': x, 'second': y, ...} = map;
print(x + y);
}
// Record patterns
void f07() {
// Variable:
var (untyped: untyped1, typed: int typed1) = (untyped: 0, typed: 1);
var (: untyped, :int typed) = (untyped: 0, typed: 1);
print('$untyped1 $untyped $typed1 $typed');
var obj = (untyped: 1, typed: 2);
switch (obj) {
case (untyped: var untyped, typed: int typed):
// ignore: dead_code, unreachable_switch_case
case (:var untyped, :int typed): print('$untyped $typed');
}
// Null-check and null-assert:
switch (obj) {
case (checked: var checked?, asserted: var asserted!):
case (:var checked?, :var asserted!): print('$checked $asserted');
}
// Cast:
var (field: field1 as int) = (field: 1.0);
var (:field as int) = (field: 1.0);
print('$field1 $field');
}
// Object pattern with getter omitted
void f08(Shape shape) {
switch (shape) {
case Square(: var size) : print(size);
}
}
void f09() {
var Point(x: x, y: y) = const Point(1, 2);
print('$x $y');
// Destructure while binding entire record
var ((a, b) && record) = (1, 2);
print('$a $b $record'); // Prints "1 2 (1, 2)"
}
// For-loop parts
void fibonacciTheHardWay() {
var fns = <Function()>[];
for (var (a, b) = (0, 1); a <= 13; (a, b) = (b, a + b)) {
fns.add(() {
print(a);
});
}
for (var fn in fns) {
fn();
}
}
// from "pattern assignment"
void test(int parameter) {
String notFinal;
final String unassignedFinal;
late final String lateFinal;
if (isAorBandAnother([])) lateFinal = 'maybe assigned';
(notFinal, unassignedFinal, lateFinal) = ('a', 'b', 'c');
print('$notFinal $unassignedFinal $lateFinal');
}
void f10() {
var map = {'a': 1, 'b': 2};
int a, b;
{'a': a, 'b': b} = map;
print('$a $b');
}
void f11() {
const a = 1;
const b = 2;
var obj = [1, 2]; // Not const.
switch (obj) {
case [a, b]: print('match'); // new
default: print('no match'); // old
}
}
class Rect {
final double width, height;
Rect(this.width, this.height);
}
void display(Object obj) {
switch (obj) {
// Object pattern with getter name omitted
case Rect(:var width, :var height): print('Rect $width x $height');
default: print(obj);
}
}
void f12() {
// pattern variable declaration
var (a, [b, c]) = ('str', [1, 2]);
print('$a $b $c');
}
void f13(Object pair) {
// guard clauses
switch (pair) {
case (int a, int b) when a > b:
print('First element greater');
case F when a == b:
print('Both elements equal');
case (int a, int b) when a < b:
print('Second element greater');
}
}
// switch expression precedence
void f14(int n, Future<int> a, Future<int> b, Future<int> c) async {
await switch (n) {
1 => a,
2 => b,
_ => c
};
}
void f15(int n, Object a, Object b, Object c) {
var x = switch (n) {
2 => b,
q when a > b => a,
_ => c
}.toString();
print(x);
}
// guard expression that ends in a function expression
void f16(Object obj, bool b, int c) {
var x = switch (obj) {
_ when ((a) => b)(null) => c
};
print(x);
}
// if-case
void f17(List<int> json) {
if (json case [int x, int y]) {
print('$x $y');
} else {
throw const FormatException('Invalid JSON');
}
if (json case [int x, int y] when x == y) {
print('Was on coordinate x-y intercept');
} else {
throw const FormatException('Invalid JSON.');
}
var list = [if (json case [int x, int y] when x == y) 3];
print(list);
}
// type substitution and rest elements
void f18() {
T id<T>(T t) => t;
(T Function<T>(T), dynamic) record = (id, 'str');
var (int Function<int>(int) f, String s) = record;
var [...] = [1, 2];
var [...x] = [1, 2];
print('$f $s $x');
}
// constant patterns for user-defined types; error in old Dart
class A {}
class B { const B(); }
void f19(A a) {
switch (A()) {
case const B(): print('hi');
}
}
// coercions only in irrefutable contexts
void f20() {
dynamic d = 1;
if (d case String s) print('then $s'); else print('else');
}
// shared case scope
void f21(Object obj) {
switch (obj) {
case [int a, int n] when n > 0:
case {'a': int a}:
print(a.abs()); // OK.
}
}
String f22() {
late Function captured;
bool capture(Function closure) {
captured = closure;
return true;
}
switch (['before']) {
case [String a] when capture(() => print(a)):
case [_, String a]:
a = 'after';
captured();
return a;
}
return '';
}
void f23(Object obj) {
switch (obj) {
case [var a, int n] when n > 1:
case [var a, double n] when n > 1.0:
case [var a, String s] when s.isNotEmpty:
print(a);
}
if (xhr.responseHeaders['content-length'] case final contentLengthHeader
when contentLengthHeader != null &&
!_digitRegex.hasMatch(contentLengthHeader)) {
completer.completeError(ClientException(
'Invalid content-length header [$contentLengthHeader].',
request.url,
));
return;
}
}
void f24() {
var list = [1, 2];
switch (list) {
case [1, _] && [_, < 4]: print('first');
case [int(isEven: true), var a]: print('second $a');
}
}
enum SomeEnum {foo}
String enumSwitchCase(SomeEnum someEnum) {
// from https://github.com/dart-lang/sdk/issues/51320
return switch (someEnum) { SomeEnum.foo => 'foo'};
}
class Color {
const Color();
}
class Colors {
static const red = Color();
static const yellow = Color();
static const blue = Color();
}