一、 从头审视 switch 要害字
众所周知, switch 要害字用于流程控制: 能够依据一个目标进行匹配,并经过 case 要害字产生分支句子,进行不同的逻辑处理。其间有一个十分值得留意,使用者很容易忽略的一点:
Dart3.0 之前: 分支中的 case 要害字后的目标有必要是
常量
。
1. Dart 3.0 之前的 switch 要害字
在日常开发中,switch 匹配的目标,一般是 int/double/String/enum
。 比如下面的 foo1 办法中,对 int 型的变量经过 switch 进行匹配,依据 case 状况,进行不同对应的逻辑处理:
void foo1(int value) {
switch (value) {
case 0:
print("=====零=====");
break;
case 1:
print("=====壹=====");
break;
default:
print("=====無=====");
}
}
在 Dart3.0 之前,case 后就能够放置任何类型的 常量
,比如下面界说的 Number
类型。只不过这种写法并不是很常用,Dart 3.0 之前的 switch 语法点也就停步于此:
void foo2(Number value) {
// switch 在 Dart 3.0.0 之前就一向能够匹配任何目标
switch (value) {
case const Number(0):
print("=====零=====");
break;
case const Number(1):
print("=====壹=====");
break;
default:
print("=====無=====");
}
}
class Number {
final int value;
const Number(this.value);
}
2. Dart 3.0 之后的 switch 要害字
在 Dart 3.0 之后引进了形式匹配 Patterns ,而本质上来说 switch 要害字的效果就是在进行匹配校验。所以 Patterns 的引进,极大加强了 switch 的语法特性。下面经过一个小例子领会一下:
比如今日是 2023 年 6 月 9 日,现在想要拓展一下 DateTime
类型,给一个 describe
办法用于输出 DateTime 目标和今日的天数差值状况。比如 6 月 12 日输出 3 天后
; 6 月 8 号输出 昨日
:
void main() {
DateTime(2023, 6, 5).describe();
DateTime(2023, 6, 8).describe();
DateTime(2023, 6, 9).describe();
DateTime(2023, 6, 12).describe();
}
--->[日志输出]----
2023/6/5 是 4 天前
2023/6/8 是 昨日
2023/6/9 是 今日
2023/6/12 是 3 天后
如下所示,对 DateTime 类进行拓展,添加了一个 describe 办法,用于处理输出逻辑。其间用到了 switch + 形式匹配的特性:
extension DescribeDate on DateTime {
void describe() {
DateTime now = DateTime.now();
Duration diff = this.difference(DateTime(now.year, now.month, now.day));
String result = switch (diff) {
Duration(inDays: -1 ) => '昨日',
Duration(inDays: 0 ) => '今日',
Duration(inDays: 1 ) => '明天',
Duration(inDays: int d) => d < 0 ? '${d.abs()} 天前' : '$d 天后',
};
print("$year/$month/$day 是 $result");
}
}
一个很明显的特征是: switch 要害字的分支句子能够作为返回值。而且分支由 形式匹配 Patterns
进行创立,还不了解 Patterns 的朋友,能够转到上一篇 《 Dart 3.0 语法新特性 | 形式匹配 Patterns》 。 下面红框中的 =>
左边的部分是对普通目标的形式匹配,其间 inDays 是 Duration 的 get 办法,所以支持对 inDays 名称的形式匹配:
二、从 switch 来看 Patterns 的种类
在上一篇,咱们了解了支持 Patterns 形式匹配的几种类型 (Type)。 但形式匹配并不只止于此,下面将经过 switch 句子来看一下其他的 Patterns 的种类:
1. 常量与解构变量
在本篇一开始时就介绍了 switch 的分支句子是对 常量
的匹配, 已然能够被 switch 匹配,就能够视为 Patterns 形式, 这就不过多赘述了。
如下所示, foo2 中传入一个 dynamic 类型的值,在 switch 中能够进行匹配:在 case 中解构 value 值,这样就能够依据变量类型匹配,进入不同的分支进行处理:
void main(){
foo2((1,1)); // 打印 int+int
foo2((1,"hello")); // 打印 int+String
foo2(5); // 打印 default
}
// 变量 Patterns
void foo2(dynamic value){
switch (value) {
case (int a, String b):
print("int+String");
break;
case (int a, int b):
print("int+int");
break;
default:
print("default");
}
}
2. 符号与要害字的 Patterns 形式匹配
除了类型之外,符号和某些要害字也能够对若干个子形式进行衔接,形成新的 Patterns 形式。 这很像正则表达式,若干个子正则能够经过符号衔接成新正则。 衔接符包含:
逻辑运算符: 或 || 、 与 &&
int age = 12;
var isAllow = switch (age) {
16 || 17 || 18 => true,
_ => false,
};
联系运算符: > 、>= 、< 、<= 、 == 、!=
int score = 69;
var info = switch (score) {
>=40 && < 60 => 'D',
== 100 => 'A+',
>= 90 && < 100 => 'A',
>= 80 && < 90 => 'B',
>= 70 && < 80 => 'C',
_ => 'E',
};
注: _
能够表明其他未匹配的状况,相当于 default
分支的效果。
强制类型转换
as
、object?
、object!
这三者简略了解一下,也能够作为 Patterns 加入匹配规矩体系:
(num, Object) record = (1, 's');
var (i as int, s as String) = record;
print("========($i,$s)=========");
switch (value) {
case var s?:
print('s 非空类型:$s');
default:
print('default');
}
(int?, int?) position = (2, 3);
var (x!, y!) = position;
print("========($x,$y)=========");
三、从 switch 和 Patterns 为咱们带来了什么
可能很多人看着 Patterns 匹配感觉很迷茫,这是什么玩意,感觉花里胡哨,感觉挺凶猛又没什么大用的姿态。这可能是你并没有了解 Patterns 是干什么用的,简略来说 Patterns 是界说了一套语法级的匹配规矩。
下面拿出介绍密封类时的那个小事例,了解一些: 登陆界面的认证状况AuthState
,有如下三种子状况
- 认证中 AuthLoading
- 认证成功 AuthSuccess
- 认证失利 AuthFailure
sealed class AuthState{} //创立密封类
class AuthLoading extends AuthState{}
class AuthSuccess extends AuthState{
final String user;
final String token;
AuthSuccess(this.user, this.token);
}
class AuthFailure extends AuthState{
final String error;
AuthFailure(this.error);
}
如下是依据 AuthState
目标构建界面的逻辑:其间使用了 switch
进行匹配,并将其作为返回值;每个分支的左边是 Patterns ,当 state 目标匹配时进入对应分支返回结果。
留意: 这儿的 AuthLoading() 并不是构造目标,而是一般类型的 Patterns 语法。匹配到对应类型,就能够访问对应子类型的数据。
String buildByAuthState(AuthState state){
return switch(state){
AuthLoading()=> 'AuthLoading View',
AuthSuccess()=> 'AuthSuccess View:${state.user}',
AuthFailure()=> 'AuthFailure View:${state.error}',
};
}
如下也能够经过 变量 Patterns
进行匹配:
String buildByAuthState3(AuthState state){
return switch(state){
AuthLoading loading => 'AuthLoading View',
AuthSuccess success => 'AuthSuccess View:${success.user}',
AuthFailure fail => 'AuthFailure View:${fail.error}',
};
}
或许将变量经过 _
进行匿名处理:
String buildByAuthState1(AuthState state){
return switch(state){
AuthLoading _ => 'AuthLoading View',
AuthSuccess _ => 'AuthSuccess View:${state.user}',
AuthFailure _ => 'AuthFailure View:${state.error}',
};
}
就像不同的正则表达式,能够完成相同的匹配目的。合理地运用匹配规矩,能够便利咱们便捷地处理逻辑。否则上面的代码逻辑就需要用 if 分支句子处理,会增加很多无意义的代码。所以面对一个新事物,应该去考虑它存在的必要性,是为了处理什么问题而呈现的,而不是拘泥于语法点,而死记硬背。
Dart 3.0 的新语法点就介绍差不多了,这儿收拾一下相关文章。那本文就到这了。谢谢观看~
- 《Dart 3.0 语法新特性 | Records 记载类型 (元组)》
- 《Dart 3.0 语法新特性 | 类型修饰符 Class modifiers》
- 《Dart 3.0 语法新特性 | 形式匹配 Patterns》
- 《Dart 3.0 语法新特性 | switch 匹配加强》 本文