【開發經驗】Flutter中對 Function/嵌套Map 安全取值

Dart的空值判斷

Dart語言已經提供了不少語法糖來改善判斷空值的寫法,可是仍是有兩種狀況不容易判斷:javascript

判斷function是否爲空

此時須要這樣每每須要這樣寫代碼:java

問題代碼

Function(String) filter;
// 必定要寫一個if,其實很不優雅
if(filter != null){
    filter('some string');
}

解決方案:使用?.call()調用

Function(String) filter;
// 一行判斷function是否爲空,並執行function
filter?.call('some string');

對Map連續取值時,在過程當中報錯,沒法安全取值

例若有Map以下:git

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

若是取值就很容易報錯:github

問題代碼

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

// 我在項目中的代碼,查詢Accu的天氣詳情,這樣會很是不穩定
source['Wind']['Speed']['Metric']['Value']

由於有時調用的Api並不徹底可靠,咱們固然不但願雲端的json結構變化就直接致使咱們整個程序報錯。若是堆疊不少個if判斷,會讓程序難以閱讀。json

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() => '<SafeMap:$value>';
}

使用:安全

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

相關文章
相關標籤/搜索