Flutter開發之Dart的資料型別02

RunTitan發表於2019-03-01

dart-logo

Map

  • key-value鍵值對(可以使用相關聯的key檢索value值)的集合, 即傳說中的字典
  • Mapkey的數量是有限的,每個key正好有一個相關的value
  • Map、以及它的鍵和值,都是可以迭代的, 迭代的順序由Map不同的型別定義
    • HashMap是無序的,這意味著它迭代的順序是不確定的
    • LinkedHashMapkey的插入順序進行迭代
    • SplayTreeMapkey的排序順序進行迭代
  • Map的一個操作正在執行的時候,通常不允許修改Map(新增或刪除key

建立Map

Map()
// 建立一個Map例項,預設實現是LinkedHashMap。

Map.from(Map other)
// 建立一個LinkedHashMap例項,包含other的所有鍵值對。

Map.fromIterable(Iterable iterable, {K key(element), V value(element)})
// 建立一個Map例項,其中Key和Value由iterable的元素計算得到。

Map.fromIterables(Iterable<K> keys, Iterable<V> values)
// 將指定的keys和values關聯,建立一個Map例項。

Map.identity()
// 使用預設實現LinkedHashMap建立一個嚴格的Map。

Map.unmodifiable(Map other)
// 建立一個不可修改、基於雜湊值的Map,包含other所有的項
複製程式碼

每一種建立方式的具體使用

  // 建立一個Map例項, 插入順序進行排列
  var dic = new Map();
  print(dic);  // {}

  // 根據一個Map建立一個新的Map, 插入順序進行排列
  var dic1 = new Map.from({'name': 'titan'});
  print(dic1);  // {name: titan}

  // 根據List建立Map, 插入順序進行排列
  List<int> list = [1, 2, 3];
  // 使用預設方式, key和value都是陣列對應的元素
  var dic2 = new Map.fromIterable(list);
  print(dic2);  // {1: 1, 2: 2, 3: 3}
  // 設定key和value的值
  var dic3 = new Map.fromIterable(list, key: (item) => item.toString(), value: (item) => item * item);
  print(dic3);  // {1: 1, 2: 4, 3: 9}

  // 兩個陣列對映一個字典, 插入順序進行排列
  List<String> keys = ['name', 'age'];
  var values = ['jun', 20];
  // 如果有相同的key值, 後面的值會覆蓋前面的值
  var dic4 = new Map.fromIterables(keys, values);
  print(dic4);  // {name: jun, age: 20}

  // 建立一個空的Map, Map允許null作為key
  var dic5 = new Map.identity();
  print(dic5);  //{}

  // 建立一個不可修改、基於雜湊值的Map
  var dic6 = new Map.unmodifiable({'name': 'titan'});
  print(dic6);
複製程式碼

相關屬性

Map中相關屬性和一些常用屬性的操作如下:

  var map1 = {'name': 'titan', 'age': 20};
  // 雜湊值
  print(map1.hashCode); 

  // 執行時型別
  print(map1.runtimeType);  //_InternalLinkedHashMap<String, Object>

  // 是否為空, null不能判斷, 會報錯
  print(map1.isEmpty);  // false

  // 是否不為空
  print(map1.isNotEmpty);  // true

  // 鍵值對個數
  print(map1.length);   // 2

  // 所有的key值, 返回Iterable<K>型別
  print(map1.keys.toList());  // [name, age]

  // 所有的value值, 返回Iterable<K>型別
  print(map1.values.toList());   // [titan, 20]

  // 根據key取值
  print(map1['name'] ?? '');   // titan

  // 根據key賦值
  map1['age'] = 30;
  print(map1);   // {name: titan, age: 30}
複製程式碼

相關函式

  var map2 = {'name': 'titan', 'age': 20};

  // 新增一個map
  map2.addAll({'blog': 'titanjun'});
  print(map2);
  // {name: titan, age: 20, blog: titanjun}

  // 判斷是否包含指定的key
  print(map2.containsKey('age'));  //

  // 判斷是否包含指定的value
  print(map2.containsValue('titan'));

  // 操作每個鍵值對
  map2.forEach((key, value) {
    print('key = $key, value = $value');
  });

  // 查詢key對應的value,或新增一個新的值為key.length的value
  for (var key in ['name', 'age', 'king']) {
    // 函式的返回值為查詢到的對應的value值
    print(map2.putIfAbsent(key, () => key.length));
  }
  print(map2);
  // {name: titan, age: 20, blog: titanjun, king: 4}

  // 轉成字串
  print(map2.toString());

  // 刪除鍵值對, 返回刪除key對應的value值, 沒有則返回null
  print(map2.remove('blog'));  //titanjun
  print(map2.remove('coder'));  //null
  print(map2);

  // 刪除所有的鍵值對
  map2.clear();
  print(map2);  //{}
複製程式碼

Iterable

  • 按順序訪問的值或元素的集合, List集合也是繼承於Iterable
  • ListSet也是Iterabledart:collection庫中同樣有很多
  • 部分Iterable集合可以被修改
    • ListSet新增元素將改變物件所有包含的元素。
    • 向Map新增新的Key會改變所有Map.keys的元素。
    • 在集合改變後,建立的迭代器將提供新的所有元素,並且可能會保持目前元素的順序, 也可能不會

建立方式

  // 建立空的可迭代物件
  var ite = Iterable.empty();
  print(ite);   // ()
  
  // 建立一個Iterable,通過序列來動態生成元素
  var ite1 = Iterable.generate(5);
  print(ite1);  // (0, 1, 2, 3, 4)
複製程式碼

至於Iterable的所有屬性和函式的介紹和使用, 在上篇文章Flutter開發之Dart的資料型別01中的List模組中已經詳細介紹了, 因為List是繼承於Iterable的, 所以Iterable有的屬性和方法List中都有

Runes

  • Dart中,Runes代表字串的UTF-32字符集, 另一種Strings
  • Unicode為每一個字元、標點符號、表情符號等都定義了 一個唯一的數值
  • 由於Dart字串是UTF-16的字元序列,所以在字串中表達32的字元序列就需要新的語法了
  • 通常使用\uXXXX的方式來表示, 這裡的XXXX是4個16進位制的數, 如,心形符號(♥)\u2665
  • 對於非4個數值的情況,把編碼值放到大括號中即可, 如,笑臉emoji (?) 是\u{1f600}
  • String類有一些屬性可以提取rune資訊
    • codeUnitAtcodeUnit屬性返回16為字元
    • 使用runes屬性來獲取字串的runes資訊
  var clapping = '\u{1f44f}';
  print(clapping);  // ?
  print(clapping.codeUnits);  // [55357, 56399]
  print(clapping.runes.toList());  // [128079]
複製程式碼

簡單使用

  // 根據字串建立
  Runes runes = new Runes('\u2665, \u{1f605}, \u{1f60e}');
  print(runes);
  // (9829, 44, 32, 128517, 44, 32, 128526)
  // 輸出特殊字元的字串
  print(new String.fromCharCodes(runes));
  // ♥, ?, ?
複製程式碼

由於Runes也是繼承於Iterable, 所以Runes中的屬性和方法的使用也和Iterable一樣, 詳情參考RunesFlutter開發之Dart的資料型別01中的介紹

Symbols

  • 一個Symbol物件代表Dart程式中宣告的操作符或者識別符號
  • 也許不會用到Symbol,但是該功能對於通過名字來引用識別符號的情況 是非常有價值的,特別是混淆後的程式碼,識別符號的名字被混淆了,但是Symbol的名字不會改變
  • 使用Symbol字面量來獲取識別符號的symbol物件,也就是在識別符號前面新增一個 # 符號
  // 獲取symbol 物件
  var sym1 = Symbol('name');
  print(sym1);   // Symbol("name")

  // #號建立
  var sym2 = #titan;
  print(sym2);   // Symbol("titan")
複製程式碼

Set

  • 物件的集合,其中每個物件只能出現一次, List中一個物件可以出現多次
  • 迭代Set中的元素時,某些時候有可能是無序的,也有可能是有序的。例如:
    • HashSet是無序的,這意味著它迭代的順序是不確定的
    • LinkedHashSet按元素的插入順序進行迭代
    • SplayTreeSet按排序順序迭代元素
  • Set除建立方式和List不同, 其他屬性和方法基本一樣

建立Set

  // 建立一個空的Set。
  var set1 = Set();
  print(set1);   // {}

  // 建立一個包含所有elements的Set
  var set2 = Set.from([1, 2, 3]);
  print(set2);   // {1, 2, 3}

  // 建立一個空的,元素嚴格相等的Set
  var set3 = Set.identity();
  print(set3);   // {}
複製程式碼

方法

  // set2 = {1, 2, 3}
  //返回一個新的Set,它是this和other的交集
  var set4 = Set.from([2, 3, 5, 6]);
  print(set2.intersection(set4));  //{2, 3}

  // 返回一個新的Set,它包含this和other的所有元素(並集)
  print(set2.union(set4));  // {1, 2, 3, 5, 6}

  // 檢查Set中是否包含object, 有則返回該object, 沒有則返回null
  print(set4.lookup(5));   // 5
  print(set4.lookup(21));  // null
複製程式碼

其他更多屬性參考SetFlutter開發之Dart的資料型別01中的介紹

Duration

  • Duration表示從一個時間點到另一個時間點的時間差
  • 如果是一個較晚的時間點和一個較早的時間點,Duration可能是負數

建立Duration

// 唯一的建構函式建立Duration物件
Duration({int days: 0, int hours: 0, int minutes: 0, int seconds: 0, int milliseconds: 0, int microseconds: 0})

// 可以使用其中的一個或者幾個引數建立
// 只是用其中的一個引數
Duration ration = Duration(days: 1);
print(ration);  //24:00:00.000000
Duration ration1 = Duration(hours: 10);
print(ration1);  //10:00:00.000000

// 只是用其中的兩個引數
Duration ration2 = Duration(days: 1, hours: 3);
print(ration2);  //27:00:00.000000

// 使用所有的引數
Duration ration3 = Duration(days: 2, hours: 2, minutes: 23, seconds: 34, milliseconds: 56, microseconds: 89);
print(ration3);  //50:23:34.056089
複製程式碼

相關運算

  Duration time1 = Duration(days: 1, hours: 1, minutes: 1, seconds: 1, milliseconds: 1, microseconds: 1);
  Duration time2 = Duration(days: 2, hours: 2, minutes: 2, seconds: 2, milliseconds: 2, microseconds: 2);
  print(time1);  //25:01:01.001001
  print(time2);  //50:02:02.002002

  // 加
  print(time1 + time2);  //75:03:03.003003
  // 減
  print(time1 - time2);  //-25:01:01.001001
  // 乘
  print(time1 * 2);    //50:02:02.002002
  // 除(取整)
  print(time2 ~/ 3);  //16:40:40.667334

  // 比較
  print(time1 > time2);  //false
  print(time1 >= time2);  //false
  print(time1 == time2);  //false
  print(time1 < time2);  //true
  print(time1 <= time2); //true

  // 取相反值
  print(-time1);  //-25:01:01.001001
  print(-(time1 - time2));  //25:01:01.001001
複製程式碼

相關函式

  Duration time3 = -Duration(days: 1, hours: 1, minutes: 1, seconds: 1, milliseconds: 1, microseconds: 1);
  print(time3);  //-25:01:01.001001

  // 取絕對值
  print(time3.abs());  //25:01:01.001001

  // 比較, 返回值, 0: 相等, -1: time1 < time2, 1: time1 > time2
  print(time1.compareTo(time2));  //-1

  // 字串形式
  print(time1.toString());
複製程式碼

DateTime

  • 表示一個時間點
  • 通過建構函式或解析格式化的字串建立DateTime物件,並且符合ISO 8601標準的子集,小時是24小時制,範圍在0-23之間
  • DateTime物件建立之後,將是固定不變的, 不可被修改
  • DateTime物件預設使用的是本地時區,除非顯示地指定UTC時區

建立時間點

  // 當前時間
  var date1 = new DateTime.now();
  print(date1);  //2019-02-23 16:43:15.505305

  // 構造一個指定為本地時區的DateTime
  //DateTime(int year, [int month = 1, int day = 1, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0])
  var date2 = new DateTime(2018, 10, 3, 12, 23, 34, 562, 1002);
  print(date2);  //2018-10-03 12:23:34.563002

  // 用微秒建立
  var date3 = new DateTime.fromMicrosecondsSinceEpoch(1000222);
  // isUtc: true: UTC時區, 預設false
  var date31 =  new DateTime.fromMicrosecondsSinceEpoch(1000222, isUtc: true);
  print(date3);  //1970-01-01 08:00:01.000222

  // 用毫秒建立
  var date4 = new DateTime.fromMillisecondsSinceEpoch(1000222);
  // isUtc: true: UTC時區, 預設false
  var date41 = new DateTime.fromMillisecondsSinceEpoch(1000222, isUtc: true);
  print(date4);  //1970-01-01 08:16:40.222
  
  // 指定為UTC時區的時間
  var date5 = new DateTime.utc(1969, 7, 20, 20, 18, 04);
  print(date5);  //1969-07-20 20:18:04.000Z
複製程式碼

parse

DateTime parse(String formattedString)
複製程式碼
  • 基於時間字串, 建立DateTime
  • 如果輸入的字串無法解析,將丟擲異常
  • 當前接受的字串為:
    • 日期:一個有正負號之分的4-6位數的年份,2位數的月份,2位數的號數
      • 年、月、日相互間可選-進行分割
      • 例如:"19700101","-0004-12-24","81030-04-01"
    • 時間部分為可選項,從日期處以T或一個空格分開
      • 對於時間部分,包括2位數的小時,然後2位數的分鐘值可選,然後2位數的秒鐘值可選, 然後 . 加1-6位數的秒數可選
      • 分和秒可以用:分隔
      • 如:"12","12:30:24.124","123010.50"
    • 時區偏移量為可選項,可能用空格與之前的部分分隔開
      • 時區是zZ,或者是一個有正負之分的2位數的小時部分,和可選的2位數的分鐘部分
      • 符號必須是+-,並且不能省略
      • 分鐘和小時可能用:分隔
  • 接受的字串例子:
    • "2012-02-27 13:27:00"
    • "2012-02-27 13:27:00.123456z"
    • "20120227 13:27:00"
    • "20120227T132700"
    • "20120227"
    • "+20120227"
    • "2012-02-27T14Z"
    • "2012-02-27T14+00:00"
    • "-123450101 00:00:00 Z":年份為-12345
    • "2002-02-27T14:00:00-0500": 與"2002-02-27T19:00:00Z"相同
  // 格式化時間字串
  var date6 = DateTime.parse("2012-02-27 13:27:00");
  var date7 = DateTime.parse('20120227T132700');
  print(date6);  // 2012-02-27 13:27:00.000
  print(date7);  // 2012-02-27 13:27:00.000
複製程式碼

屬性值

  var time = DateTime.parse("2019-02-25 13:27:04");
  // 獲取年-月-日-周幾
  print(time.year);   //2019
  print(time.month);  //2
  print(time.day);    //25
  print(time.weekday);//1

  // 獲取時-分-秒-毫秒-微秒
  print(time.hour);       //13
  print(time.minute);     //27
  print(time.second);     //4
  print(time.millisecond);//0
  print(time.microsecond);//0

  // 是不是utc時區
  print(time.isUtc);
  
  //1970-01-01T00:00:00Z (UTC)開始經過的微秒數
  print(time.microsecondsSinceEpoch);

  //1970-01-01T00:00:00Z (UTC)開始經過的毫秒數
  print(time.millisecondsSinceEpoch);
  
  //平臺提供的時區名稱
  print(time.timeZoneName);

  //時區偏移量,即本地時間和UTC之間的時間差
  print(time.timeZoneOffset);
複製程式碼

相關函式

  // 獲取當前時間
  DateTime today = new DateTime.now();
  print(today);  //2019-02-28 11:18:16.198088

  //加上duration,返回一個新的DateTime例項
  DateTime newDay = today.add(new Duration(days: 60));
  print(newDay);  //2019-04-29 11:18:16.198088

  //減去duration,返回一個新的DateTime例項
  DateTime newDay1 = today.subtract(new Duration(days: 60));
  print(newDay1);  //2018-12-30 11:25:31.741382

  // 比較兩個時間值的大小, 0: 相等, -1: 前值<後值, 1: 前值>後值
  var isCom = today.compareTo(newDay);
  print(isCom);  // -1

  // 計算兩個時間的差值
  Duration duration = today.difference(newDay);
  print(duration);  //-1440:00:00.000000

  // 比較兩個時間
  print(today.isAfter(newDay));  // false
  print(today.isBefore(newDay)); // true

  // 比較是否是同一時刻
  print(today.isAtSameMomentAs(newDay));  //false

  // 返回此DateTime在本地時區的值
  print(today.toLocal());  //2019-02-28 11:30:51.713069
複製程式碼

參考文獻


相關文章