前端学习-Dart官方文档学习-003-模式匹配

官方文档链接

简介

匹配和解构

// 匹配
const a = 'a';
const b = 'b';
switch (obj) {
  // List pattern [a, b] matches obj first if obj is a list with two fields,
  // then if its fields match the constant subpatterns 'a' and 'b'.
  case [a, b]:
    print('$a, $b');
}

// 解构
var numList = [1, 2, 3];
// List pattern [a, b, c] destructures the three elements from numList...
var [a, b, c] = numList;
// ...and assigns them to new variables.
print(a + b + c);

变量赋值

使用变量赋值模式交换两个变量的值,而不声明第三个临时变量:

var (a, b) = ('left', 'right');
(b, a) = (a, b); // Swap.
print('$a $b'); // Prints "right left".

Switch

switch (obj) {
  // Matches if 1 == obj.
  case 1:
    print('one');

  // Matches if the value of obj is between the
  // constant values of 'first' and 'last'.
  case >= first && <= last:
    print('in range');

  // Matches if obj is a record with two fields,
  // then assigns the fields to 'a' and 'b'.
  case (var a, var b):
    print('a = $a, b = $b');

  default:
}

// 逻辑或在switch比较常见
var isPrimary = switch (color) {
  Color.red || Color.yellow || Color.blue => true,
  _ => false
};

// Switch 中的条件
switch (pair) {
  case (int a, int b):
    if (a > b) print('First element greater');
  // If false, prints nothing and exits the switch.
  case (int a, int b) when a > b:
    // If false, prints nothing but proceeds to next case.
    print('First element greater');
  case (int a, int b):
    print('First element not greater');
}

For and for-in loops

Map<String, int> hist = {
  'a': 23,
  'b': 100,
};

for (var MapEntry(key: key, value: count) in hist.entries) {
  print('$key occurred $count times');
}
key: key 可简写为 :key
for (var MapEntry(:key, value: count) in hist.entries) {
  print('$key occurred $count times');
}

在 Dart 中,MapEntry是Map中的一个内部类,它表示Map中的一个键值对

Map<String, int> myMap = {
  'a': 1,
  'b': 2,
  'c': 3,
};

// 获取 Map 中的第一个键值对
MapEntry<String, int> firstEntry = myMap.entries.first;

// 访问键和值
String key = firstEntry.key;
int value = firstEntry.value;

// 修改值
firstEntry.value = 4;

// 打印修改后的 Map
print(myMap); 

Algebraic data types(没懂

sealed class Shape {}

class Square implements Shape {
  final double length;
  Square(this.length);
}

class Circle implements Shape {
  final double radius;
  Circle(this.radius);
}

double calculateArea(Shape shape) => switch (shape) {
      Square(length: var l) => l * l,
      Circle(radius: var r) => math.pi * r * r
    };

Validating incoming JSON

当知道JSON结构时

var json = {
  'user': ['Lily', 13]
};
var {'user': [name, age]} = json;

当JSON来自外部(如网络),需要先进行验证

// 普通写法
if (json is Map<String, Object?> &&
    json.length == 1 &&
    json.containsKey('user')) {
  var user = json['user'];
  if (user is List<Object> &&
      user.length == 2 &&
      user[0] is String &&
      user[1] is int) {
    var name = user[0] as String;
    var age = user[1] as int;
    print('User $name is $age years old.');
  }
}
// pattern写法
if (json case {'user': [String name, int age]}) {
  print('User $name is $age years old.');
}

Pattern types 模式匹配类型

优先级 precedence

  • 低优先级:Logical-or < logical-and < relational
  • 中优先级:cast(强制转换), null-check, and null-assert 优先级相同
  • 高优先级:Collection-type (record, list, and map) and Object patterns

Logical-or < logical-and < relational

Logical-or
var isPrimary = switch (color) {
  Color.red || Color.yellow || Color.blue => true,
  _ => false
};
logical-and

Subpatterns in a logical-and pattern can bind variables, but the variables in each subpattern must not overlap, because they will both be bound if the pattern matches:

switch ((1, 2)) {
  // Error, both subpatterns attempt to bind 'b'.
  case (var a, var b) && (var b, var c): // ...
}
relational ==, !=, <, >, <=, and >=.
String asciiCharType(int char) {
  const space = 32;
  const zero = 48;
  const nine = 57;

  return switch (char) {
    < space => 'control',
    == space => 'space',
    > space && < zero => 'punctuation',
    >= zero && <= nine => 'digit',
    _ => ''
  };
}

cast(强制转换), null-check, and null-assert

cast(强制转换)

foo as String

(num, Object) record = (1, 's');
var (i as int, s as String) = record;
null-check

subpattern?
没太懂

String? maybeString = 'nullable with base type String';
switch (maybeString) {
  case var s?:
  // 's' has type non-nullable String here.
}
null-assert

subpattern!

(int?, int?) position = (2, 3);

var (x!, y!) = position;

Collection-type (record, list, and map) and Object patterns

list

[subpattern1, subpattern2]

const a = 'a';
const b = 'b';
switch (obj) {
  // List pattern [a, b] matches obj first if obj is a list with two fields,
  // then if its fields match the constant subpatterns 'a' and 'b'.
  case [a, b]:
    print('$a, $b');
}

// List patterns can contain one rest element (...) which allows matching lists of arbitrary lengths.
var [a, b, ..., c, d] = [1, 2, 3, 4, 5, 6, 7];
// Prints "1 2 6 7".
print('$a $b $c $d');
Map

{"key": subpattern1, someConst: subpattern2}

Record

(subpattern1, subpattern2)

(x: subpattern1, y: subpattern2)

var (myString: foo, myNumber: bar) = (myString: 'string', myNumber: 1);

// Record pattern with variable subpatterns:
var (untyped: untyped, typed: int typed) = record;
var (:untyped, :int typed) = record;

switch (record) {
  case (untyped: var untyped, typed: int typed): // ...
  case (:var untyped, :int typed): // ...
}

// Record pattern with null-check and null-assert subpatterns:
switch (record) {
  case (checked: var checked?, asserted: var asserted!): // ...
  case (:var checked?, :var asserted!): // ...
}

// Record pattern with cast subpattern:
var (untyped: untyped as int, typed: typed as String) = record;
var (:untyped as int, :typed as String) = record;
Object

SomeClass(x: subpattern1, y: subpattern2)

switch (shape) {
  // Matches if shape is of type Rect, and then against the properties of Rect.
  case Rect(width: var w, height: var h): // ...
}

通配符Wildcard _

通配符可以用于在类型注解中表示未知或不特定的类型。以下是一些常见的使用场景:

List<_> myList = [1, 2, 3];  // 在使用泛型时,通配符可以用于表示未知的类型参数

void myFunction(_ myParameter) {
  // 通配符可以用于表示函数参数的类型不特定;在这里处理 myParameter
}

It's useful as a placeholder in places where you need a subpattern in order to destructure later positional values:

var list = [1, 2, 3];
var [_, two, _] = list;

A wildcard name with a type annotation is useful when you want to test a value's type but not bind the value to a name:

switch (record) {
  case (int _, String _):
    print('First field is int and second is String.');
}
posted @   ayubene  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 易语言 —— 开山篇
点击右上角即可分享
微信分享提示