Dart3 if-case-when的一些奇妙用法

昨天看群友发了一张这样代码图: 里面有两点让我感到很疑惑:AsyncData(:final value)是什么东西?if (value.data?.topics case final topic?)又是个啥?这真的还是dart代码吗? 于是上网一查,原来还真有这样的东西,该更新一下大脑补一下课了。

if-case-when

上面的是官方的解释,嗯...我们还是自己动手试试吧。

在以前,如果判断一个值是否为数组且该数组长度为2且该数组里的元素都大于0,可以这样写:

javascript 复制代码
void checkTypeOld(dynamic value) {
  if (value is List && value.length == 2 && value.every((e) => e > 0)) {
    print('value.type is list and value.length == 2 and all element of value is bigger than 0');
  }
}

用dart3则可以这样:

csharp 复制代码
void checkTypeNew(dynamic value) {
  if (value case [int x, int y] when x > 0 && y > 0) {
    print('value.type is list and value.length == 2 and all element of value is bigger than 0');
  }
}

看起来dart3更简洁?它一句case [int x, int y]就做了前两个判断同时取值出来方便下一步计算。

那么能不能再更简洁一点呢?假设这里要判断的长度不是2,而是20,[int x, int y...]这样赋值也太累了。答案当然是可以的。

csharp 复制代码
void checkTypeNew(dynamic value) {
  if (value case List(length: 20) when value.every((e) => e > 0)) {
    print('value.type is list and value.length == 20 and all element of value is bigger than 0');
  }
}

List()能用的不仅有length,还有isEmpty,first等,只要类型里有写getter方法的都能用。

AsyncData(:final value)

AsyncData是riverpod自定义的class,继承于AsyncValue。通过观察上述的代码能够判断出hotList应该是一个AsyncValue类型的变量,然后在这里通过switch判断具体的类型来显示不同的UI。明白了代码的作用后就该看看那个:final value是啥了。

这里我跟着riverpod的教程弄了一下,其中Activity是自定义的类,里面只有一个final String key。

scss 复制代码
Consumer(
  builder: (context, ref, child) {
    final AsyncValue<Activity> activity = ref.watch(activityProvider);
    return Center(
      child: switch (activity) {
        AsyncData(:Activity value) => Text('Activity: ${value.key}'),
        AsyncError() => const Text('Oops, something unexpected happened'),
        _ => const CircularProgressIndicator(),
      },
    );
  },
);

这样就可以明确看出activity和value的类型,那么根据AsyncData的源码,不难看出:Activity value就是取出AsyncData里的值的意思。

那么如果我不喜欢value,可以把它改成item或者其他的变量吗?

并不可以!会报出以下错误The getter 'item' isn't defined for the type 'AsyncData<Activity>'.

又是getter!再深入进去看一眼AsyncValue的实现,发现它其实是这样的:

综上所述,如果想要使用:final value这种语法,也是要求类有提供getter方法。那么我自己也实现一个试试。

dart 复制代码
class Item {
  Item._(this._id);

  factory Item.from(String id) => Item._(id);

  String _id;

  String get id => _id;

  set id(String value) {
    if (value != id) {
      _id = value;
    }
  }
}

把它也加到上面判断类型的函数里那就会是这样:

csharp 复制代码
void checkTypeNew(dynamic value) {
  if (value case List(length: 20) when value.every((e) => e > 0)) {
    print('value.type is list and value.length == 20 and all element of value is bigger than 0');
  } else if (value case Item(:final id) when id.isNotEmpty) {
    print('value.type is Item and value.id is not empty');
  }
}

再把这堆if-else优化一下:

scss 复制代码
void checkTypeNew(dynamic value) {
  switch(value) {
    case List(length: 20) when value.every((e) => e > 0):
      print('value.type is list and value.length == 20 and all element of value is bigger than 0');
    case Item(:final id) when id.isNotEmpty:
      print('value.type is Item and value.id is not empty');
  }
}

当然也可以这样写,连case都省略掉:

dart 复制代码
String checkTypeNew(dynamic value) {
  return switch (value) {
    List(length: 20) when value.every((e) => e > 0) =>
      'value.type is list and value.length == 20 and all element of value is bigger than 0',
    Item(:final id) when id.isNotEmpty =>
      'value.type is Item and value.id is not empty',
    _ => 'undefined'
  };
}

// 这样调用
print(checkTypeNew(***));

同时,括号里不仅可以获取一个getter,而是可以获取多个getter,以list为例:

vbnet 复制代码
String checkTypeNew(dynamic value) {
  return switch (value) {
    List(length: 20, :final last)
        when value.every((e) => e > 0) && last > 10 =>
      'value.type is list and value.length == 20 and all element of value > 0 and last element > 10',
    Item(:final id) when id.isNotEmpty =>
      'value.type is Item and value.id is not empty',
    String string when string.isNotEmpty =>
      'value is String and value is not empty',
    _ => 'undefined'
  };
}

最后

这篇文章也只是一个抛砖引玉,我只知道这些东西该怎么用,并不知道这些东西的原理,只能感觉这些都是dart3改新swtich的时候改出来的新特性,具体原理要是能有高手补充一下原理就好了。 dart3这套新switch总是可以把代码写得更简洁,还蛮好用的,虽然不用也没问题,但是你都用flutter这种新玩意了,与时俱进学点新东西不是挺好的吗?

相关推荐
大龄秃头程序员13 小时前
Riverpod 深度解析:从响应式本质到最小可运行闭环
flutter
曹小强wxx15 小时前
让 AI 写代码不“翻车”:用 Claude Code + Codex 给 Flutter 项目搭一套工程规范
flutter·ai编程·claude
西西学代码18 小时前
像素和颜色之间的转换(Flutter)
前端·javascript·flutter
曹小强wxx18 小时前
Flutter 局域网设备发现:UDP 广播 + mDNS 双路合并,以及靠谱的在线判定与断线重连
物联网·网络协议·flutter
FungLeo20 小时前
成为全栈·Flutter App 篇·移动端错误与限流:429、重试和写请求边界
flutter·限流·dart·dio·错误处理·成为全栈
恋猫de小郭21 小时前
Kotlin Toolchain 0.13,JetBrains 推荐 KMP 都切换到到全新工具链
android·前端·flutter
m0_7381858221 小时前
Flutter 鸿蒙化实战:rive 适配 OpenHarmony,Rive 动画
flutter·华为·harmonyos·鸿蒙
Geek_Vison1 天前
保险APP已经用了Flutter,还能接入小程序吗?
flutter·小程序·uni-app·mpaas·小程序容器
FungLeo1 天前
成为全栈·Flutter App 篇·go_router 与四 Tab App Shell:保留导航状态、深链和登录回跳
flutter·移动开发·成为全栈·go_router·路由设计·深链接
m0_738185821 天前
Flutter 鸿蒙化实战:screen_protector 适配 OpenHarmony,防截屏/防泄露
flutter·华为·harmonyos·鸿蒙