【开发经验】Flutter中对 Function/嵌套Map 安全取值

Dart的空值判断

Dart语言已经提供了很多语法糖来改善判断空值的写法,但是还是有两种情况不容易判断:

判断function是否为空

此时需要这样往往需要这样写代码:

问题代码

Function(String) filter;
// 一定要写一个if,其实很不优雅
if(filter != null){
    filter('some string');
}

解决方案:使用?.call()调用

Function(String) filter;
// 一行判断function是否为空,并执行function
filter?.call('some string');

对Map连续取值时,在过程中报错,无法安全取值

例如有Map如下:

Map map = {
      'id': 3,
      'tag': 'user',
      'info': {
        'name': 'Jerry',
        //'age': 5,
      }
    };

如果取值就很容易报错:

问题代码

map['info']; // 取出map
map['info']['name']; // 取出'Jerry'
map['info2']['remark']; // 取不存在的key,再取值就回报错

// 我在项目中的代码,查询Accu的天气详情,这样会非常不稳定
source['Wind']['Speed']['Metric']['Value']

因为有时调用的Api并不完全可靠,我们当然不希望云端的json结构变化就直接导致我们整个程序报错。如果堆叠很多个if判断,会让程序难以阅读。

Tips: javascript中可以使用 map?.['info']进行取值。

解决方案:封装SafeMap类,使其可以一直取值

思路很简单,重载[]操作符即可
完整代码:GitHub仓库地址


class SafeMap {
  SafeMap(this.value);

  final dynamic value;

  SafeMap operator [](dynamic key) {
    if (value is Map) return SafeMap(value[key]);
    if (value is List) {
      List _list = value;
      int max = _list.length - 1;
      if (key is int && key < max) return SafeMap(value[key]);
    }
    return SafeMap(null);
  }

  dynamic get v => value;
  String get string => value is String ? value as String : null;
  num get number => value is num ? value as num : null;
  Map get map => value is Map ? value as Map : null;
  List get list => value is List ? value as List : null;
  bool get boolean => value is bool ? value as bool : false;

  bool isEmpty() {
    if (this.v == null) return true;
    if (this.string == '') return true;
    if (this.number == 0) return true;
    if (this.map?.keys?.length == 0) return true;
    if (this.list?.length == 0) return true;
    if (this.boolean == false) return true;
    return false;
  }

  @override
  String toString() => '';
}

使用:


void main() {
  test('get value from safemap', () {
    // source map
    Map map = {
      'id': 3,
      'tag': 'student',
      'info': {
        'name': 'Jerry',
      },
      'class': [
        {
          "name": 'class 1',
          'tag': '',
        },
        {},
      ],
    };
    SafeMap safeMap = SafeMap(map);

    // 取值,错误的类型会返回SafeMap(null)
    assert(safeMap['id'].value == 3);
    assert(safeMap['id'].string == null);

    // 错误的下标也会返回SafeMap(null)
    assert(safeMap['tag'].value == 'student');
    assert(safeMap['tag12345'].value == null);

    // 连续取值,可以一直安全取值,只会返回SafeMap(null).
    assert(safeMap['info']['name'].value == 'Jerry');
    assert(safeMap['a']['b']['b']['b']['b']['b'].value == null);

    // 取出数组,也可以通过数组下标继续取值
    assert(safeMap['class'].list.length == 2);
    assert(safeMap['class'][0]['name'].value == 'class 1');

    // {},[],0,'',null 都会被判断为空
    assert(safeMap['class'][0]['tag'].isEmpty());
    assert(safeMap['class'][1].isEmpty());

    // 越界也会返回SafeMap(null),判断isEmpty为true
    assert(safeMap['class'][2].isEmpty());
  });
}

End

你可能感兴趣的:(dartlang,flutter)