likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 0

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

if-case-when

Dart3 if-case-when的一些奇妙用法 上面的是官方的解释,嗯...我们还是自己动手试试吧。

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

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则可以这样:

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...]这样赋值也太累了。答案当然是可以的。

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,还有isEmptyfirst等,只要类型里有写getter方法的都能用。

AsyncData(:final value)

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

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

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(),
      },
    );
  },
);

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

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

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

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

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

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

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

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;
    }
  }
}

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

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优化一下:

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都省略掉:

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为例:

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这种新玩意了,与时俱进学点新东西不是挺好的吗?