Android学Dart学习笔记第九节 Patterns

是什么

Patterns are a syntactic category in the Dart language, like statements and expressions. A pattern represents the shape of a set of values that it may match against actual values

译文:模式是Dart语言中的一个句法范畴,就像语句和表达式一样。模式表示一组值的形状,它可以与实际值匹配

What patterns do 模式的作用

In general, a pattern may match a value, destructure a value, or both, depending on the context and shape of the pattern.

First, pattern matching allows you to check whether a given value:

Has a certain shape.

Is a certain constant.

Is equal to something else.

Has a certain type.

Then, pattern destructuring provides you with a convenient declarative syntax to break that value into its constituent parts. The same pattern can also let you bind variables to some or all of those parts in the process.

译文:一般来说,模式可以匹配一个值,解构一个值,或者两者兼而有之,这取决于模式的上下文和结构。

首先,模式匹配允许你检查给定的值是否:

有一定的形状。

是一个确定的常数。

等于另一个东西。

有特定的类型。

然后,模式解构为你提供了一种方便的声明性语法,将值分解为其组成部分。同样的模式还可以让您将变量绑定到流程中的某些或所有部分。

Matching

A pattern always tests against a value to determine if the value has the form you expect. In other words, you are checking if the value matches the pattern.

译文:模式总是对值进行测试,以确定该值是否符合预期的形式。换句话说,你正在检查值是否与模式匹配。

上例子,看看就明白了

dart 复制代码
void main() {
  var a = 1;
  var b = '2';
  print(isNum(a));//true
  print(isOne(a));//true
  print(isNum(b));//false
  print(isOne(b));//false

}

bool isNum(dynamic input ) => input is int;
bool isOne(dynamic input) => input == 1;

在上面的例子中,我们分别对于输入参数做了两次匹配,isNum是匹配input是否是int类型,isOne是匹配input是否是数字1

那么pattern就是这么简单吗?接着往下看

Many patterns make use of subpatterns, sometimes called outer and inner patterns, respectively. Patterns match recursively on their subpatterns.

译文:许多模式使用子模式,有时分别称为外部模式和内部模式。模式在子模式上递归匹配。

如下,任何集合类型模式的单个字段都可以是变量模式或常量模式。

dart 复制代码
  const a = 1;
  const b = '2';
  var input = [a, b];
  switch(input) {
    case [a, b]:
      print('a is $a, b is $b');
      break;
    default:
      print('default');
  }

在上面的例子中,input必须是个list,且只有a,b两个元素,且a必须是1,b必须是'2',且顺序不能颠倒

功能非常强大,看起来有点像正则,但更方便

下面是一些常见用法:

dart 复制代码
case [_, a, ...]:
      print('input是列表,第二个元素是$a');
      break;
 case[a, ...,]:
      print('input是列表,第一个元素是$a');
      break;
 case [..., a]:
      print('input是列表,最后一个元素是$a');
      break;

_的专业名词叫Wildcard, ...的专业名词叫Rest element,需要的同学可以自行学习。

Destructuring

When an object and pattern match, the pattern can then access the object's data and extract it in parts

译文:当对象和模式匹配时,模式就可以访问对象的数据并将其提取出来

dart 复制代码
 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');//1 2 3

我们也可以在条件语句中这样使用:

dart 复制代码
  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'); //1 2 3
  switch (numList) {
    case [1 || 2, _, var c]:
      print(c);//3
  }

这句话的含义是,共3个元素,第一个1或2,任意一个,后面的元素赋值给c。

Places patterns can appear

模式可以出现的位置

Variable declaration 变量声明

You can use a pattern variable declaration anywhere Dart allows local variable declaration. The pattern matches against the value on the right of the declaration

译文:你可以在Dart允许局部变量声明的任何地方使用模式变量声明。该模式匹配声明右侧的值

dart 复制代码
var (a, [b, c]) = ('str', [1, 2]);

A pattern variable declaration must start with either var or final, followed by a pattern.

译文:模式变量的声明必须以var或final开头,然后是模式。

就是const不可以,var、final都允许。

Variable assignment 变量赋值

A variable assignment pattern falls on the left side of an assignment. First, it destructures the matched object. Then it assigns the values to existing variables, instead of binding new ones.

译文:变量赋值模式位于赋值语句的左侧。首先,解构匹配的对象。然后,它将值赋给现有变量,而不是绑定新变量。

Use a variable assignment pattern to swap the values of two variables without declaring a third temporary one

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

dart 复制代码
var (a, b) = ('left', 'right');
(b, a) = (a, b); // Swap.
print('$a $b'); // Prints "right left".

很新奇的写法,非常便捷。

Switch statements and expressions

Switch语句和表达式

Every case clause contains a pattern. This applies to switch statements and expressions, as well as if-case statements. You can use any kind of pattern in a case

.Case patterns are refutable. They allow control flow to either:

Match and destructure the object being switched on.

Continue execution if the object doesn't match.

译文每个case子句都包含一个模式。这适用于switch语句、表达式以及if-case语句。在case中可以使用任何类型的模式。

案例模式是可以反驳的。它们允许以下任意一种控制流:

匹配并解构正在打开的对象。

如果对象不匹配,继续执行。

dart 复制代码
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:
}

同时支持多个模式

dart 复制代码
var isPrimary = switch (color) {
  Color.red || Color.yellow || Color.blue => true,
  _ => false,
};

Switch statements can have multiple cases share a body without using logical-or patterns, but they are still uniquely useful for allowing multiple cases to share a guard:

译文:传统的switch语句中,可以通过让多个case标签指向同一个代码块来实现共享逻辑,而逻辑或模式(|| 模式) 它允许将多个模式组合在一起,并为整个组合应用同一个when守卫条件,这是传统case标签无法做到的

逻辑或模式指的就是||, dart 中允许使用||时同时为这些模式提供一个守护,看下面的例子:

dart 复制代码
switch (shape) {
  case Square(size: var s) || Circle(size: var s) when s > 0:
    print('Non-empty symmetric shape');
}

when(s > 0),同时对前面的两个模式生效。

Guard clauses evaluate an arbitrary condition as part of a case, without exiting the switch if the condition is false (like using an if statement in the case body would cause).

Guard子句作为case语句的一部分对任意条件进行计算,如果条件为false,则不退出switch(就像在case主体中使用if语句一样)。

看下面的代码,演示了guard子句的作用:

dart 复制代码
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

是的,在for循环中自然也可以使用

dart 复制代码
 Map<String, int> hist = {'a': 23, 'b': 100};

  for(var entry in hist.entries){
    print('${entry.key} occurred ${entry.value} times');
  }
  下面使用了模式解构
  for (var MapEntry(key: key, value: count) in hist.entries) {
    print('$key occurred $count times');
  }

Binding the result of a getter call to a variable of the same name is a common use case, so object patterns can also infer the getter name from the variable subpattern. This allows you to simplify the variable pattern from something redundant like key: key to just 🔑

将getter调用的结果绑定到同名变量是一种常见的用例,因此对象模式也可以从变量subpattern中推断出getter的名称。这允许你将变量模式从key: key这样的冗余简化为仅:key:

dart 复制代码
 Map<String, int> hist = {'a': 23, 'b': 100};
  for (var MapEntry(:key, value: count) in hist.entries) {//这里使用了getter简化
    print('$key occurred $count times');
  }

Use cases for patterns 使用案例

Destructuring multiple returns 通过结构返回多个值

dart 复制代码
var info = userInfo(json);
var name = info.$1;
var age = info.$2;

var (name, age) = userInfo(json);


final (:name, :age) =
    getData(); 

Destructuring class instances

解构类实例

dart 复制代码
final Foo myFoo = Foo(one: 'one', two: 2);
var Foo(:one, :two) = myFoo;
print('one $one, two $two');

Algebraic data types

dart 复制代码
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

dart 复制代码
var data = {
  'user': ['Lily', 13],
};
var {'user': [name, age]} = data;

验证格式是否合法,当不匹配时会出现下面错误

dart 复制代码
Unhandled exception:
Bad state: Pattern matching error

下面是一个传统格式验证的代码

dart 复制代码
if (data is Map<String, Object?> &&
    data.length == 1 &&
    data.containsKey('user')) {
  var user = data['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.');
  }
}

简化后如下:

dart 复制代码
if (data case {'user': [String name, int age]}) {
  print('User $name is $age years old.');
}

总结

新东西有点多,但是代码就是条条大路通罗马,不求掌握,但求看到的时候能想到,ai帮你优化之后你能看懂。

相关推荐
AllBlue1 小时前
unity导出成安卓工程,集成到安卓显示
android·unity·游戏引擎
代码游侠1 小时前
学习笔记——栈
开发语言·数据结构·笔记·学习·算法
光头程序员2 小时前
学习笔记——vite 打包构建优化之tree shaking
笔记·学习
QQ_4376643142 小时前
常见题目及答案
android·java·开发语言
菜鸟小九2 小时前
mysql运维(主从复制)
android·运维·mysql
安得权2 小时前
Office365 SSO Azure的配置笔记
笔记·flask·azure
晚霞的不甘2 小时前
跨端一致性与体验统一:构建面向全场景的 Flutter UI 自适应架构
flutter·ui·架构
走在路上的菜鸟2 小时前
Android学Dart学习笔记第十一节 分支
android·笔记·学习·flutter
克喵的水银蛇2 小时前
Flutter 自定义 Widget 实战:封装通用按钮 + 下拉刷新列表
前端·javascript·flutter