Dart語言之常用數據類型

目錄

前言

一、Dart概述

二、Dart常用數據類型

2.1、Dart知識體系

2.2、數字類型(num、int和double)

2.3、字符串(String)

2.4、布爾

2.5、集合之List

2.6、集合之Map

2.7、dynamic、var和Object的區別


前言

又有一段時間沒有寫東西了,很長時間不寫,表明了兩個點,一個是說明了自己的惰性,另一個就是說明了自己這段時間沒有任何的提升,所以下午的時候我就在想晚上一定得寫點東西,要麼做技術覆盤,要麼寫點新東西,然後就一直醞釀晚上回去該寫點什麼?最終決定寫點基礎的。因爲現在市面上有些公司開始招聘Flutter開發相關的技術人員了,結合我之前寫過的一篇《Flutter入門:開發環境與開發工具的準備》,那麼當你環境準備好之後那肯定是要攻克開發語言了,所以接下來的幾篇文章我會在我的Dart專欄裏面跟大家分享一些Dart語言的基礎知識,有了這些基礎知識,你就可以去好好研究Flutter SDK了。

一、Dart概述

針對Dart語言的特點做以下幾點說明:

1、Dart2.0:強類型的靜態類型(編譯時已知變量的類型)的語言,和Java、C#等比較類似,所有類型的檢查都可以通過編譯器來完成;

2、面向對象(OOP):這個特點類似的語言比較多:有Python、C++、Objective-C、Java、Kotlin、Swift、C#等等;

3、JIT&AOT:JIT(Just in Time)優點:即時編譯,開發期間更快編譯,更快的重載;缺點:在運行時將代碼編譯成機器碼,給用戶最直接的感受就是慢;AOT(Ahead Of Time)事前編譯,release期間更快更流暢,典型的例子就是C和C++,它能夠直接編譯機器碼即二進制代碼,所以它的加載和執行速度是非常快的。你會發現在開發期間安裝Flutter的時候會有一些卡頓,但是在release就是發佈之後會變好,這種模式使得APP在發佈之後能夠以更快的速度運行。

二、Dart常用數據類型

2.1、Dart知識體系

這裏用一張思維導圖來展示Dart的整個知識體系

2.2、數字類型(num、int和double)

1、num:

Dart數字類型的父類,它既接受浮點類型,也接受整數類型。

num num1 = -1.0; //num是數字類型的父類
num num2 = 2; //num是數字類型的父類

2、int、double

num有兩個子類,一個是int,一個是double,int類型只能接收整數,double類型是雙精度

int int1 = 3; //子類一 int類型 只能接收整數
double d1 = 2.22; //子類二 雙精度

在dart中數字類型如何進行類型轉換呢?可以通過toInt()、toDouble等方法,還有一些常用的api,比如abs()、round()等等,我們通過一段代碼來看一下它的運行結果:

///數字類型
  void _numType() {
    num num1 = -1.0; //num是數字類型的父類
    num num2 = 2; //num是數字類型的父類
    int int1 = 3; //子類一 int類型 只能接收整數
    double d1 = 2.22; //子類二 雙精度
    print("num:$num1 num2:$num2 int1:$int1 d1:$d1");
    print(num1.abs()); //求絕對值
    print(num1.toInt()); //轉換成int類型
    print(num1.toDouble()); //轉成Double類型
    print(num1.toString()); //轉成字符串
  }

運行結果如下:

2.3、字符串(String)

在dart中定義字符串可以用單引號也可以用雙引號,一行可以定義一個字符串,也可以定義多個字符串,中間用逗號隔開:

String str1 = '字符串', str2 = "雙引號字符串"; //字符串的定義

在dart中如何進行字符串拼接呢?答案很簡單,可以直接使用加號“+”拼接,當然還有另外一種方法,在上面數字類型的講解中也有使用到,我們可以使用"$"加上變量名去引用一個變量,這個變量可以是數字類型當然也可以是字符串類型:

String str3 = 'str1:$str1 str2:$str2'; //字符串拼接
String str4 = 'str1:' + str1 + "str2:" + str2; //字符串拼接

接着來看dart中字符串有哪些常用的api呢?字符串中的方法有很多,這裏只介紹幾種常用的,其它的方法大家可以自行學習,學習的方法也很簡單,將鼠標移至字符串操作中的某個方法上,比如.substring()上面,然後Windows下按住ctrl鍵,Mac下按住command鍵,點進去就到了String這個類的源碼當中,這裏面有所有字符串操作的方法,每個方法都有對應的註釋說明,看不懂英文的網上找個翻譯軟件跟着學習就行,下面介紹幾種常用的:

//字符串截取,包含開始索引,不包含結束索引
String substring(int startIndex, [int endIndex]);
//獲取一個字符串在另一個字符串中的位置
int indexOf(Pattern pattern, [int start]);
//判斷一個字符串是否是以某種匹配規則開始的
bool startsWith(Pattern pattern, [int index = 0]);
//判斷一個字符串是否包含某個匹配項
bool contains(Pattern other, [int startIndex = 0]);
//將某個字符串按照某種匹配規則進行拆分,並返回子字符串列表
List<String> split(Pattern pattern);
//將所有與from匹配的子字符串替換爲replace,from和replace爲方法的入參
String replaceAll(Pattern from, String replace);

其實這些方法和我們在java中使用的都是差不多的,我們再來寫個方法進行實際查看一下結果,加深理解:

///字符串操作
  _stringType() {
    //字符串常用方法
    String str5 = '常用數據類型,請看控制檯輸出';
    print(str5.substring(1, 5)); //字符串截取
    print(str5.indexOf('請看'));
    print(str5.startsWith('常')); //是否以xx開始的
    print(str5.contains("數據"));
    print(str5.split(","));
    print(str5.replaceAll("類型","安奇"));
  }

結果如下:

2.4、布爾

Dart是強bool類型檢查,只有bool類型的值是true,才被認爲是true,對於bool類型來說,實際開發中用的比較多的就是邏輯運算,常用的也就是邏輯與和邏輯或的運算,這一塊比較簡單,寫個方法驗證一下即可:

///布爾類型,Dart是強bool類型檢查,只有bool類型的值爲true,才被認爲是true
  _boolType() {
    bool success = true, fail = false;
    print(success);
    print(fail);
    print(success || fail); //true
    print(success && fail); //false
  }

結果如下:

2.5、集合之List

1、List集合的初始化

在Dart中定義集合使用List關鍵字,List<E>表明集合是個泛型,這裏可以傳入任何數據類型。

List集合可以使用“[]”進行初始化,例如:List list = [1,2,'測試']; 這種形式,這裏沒使用泛型所以中括號裏面添加元素時既可以傳入數字也可以傳入字符串,如果需要指定泛型類型,例如:List<int> list1 = []; 這種形式下,添加元素的時候只能添加int類型的數據。如果我們把list集合直接賦值給list1集合會怎麼樣呢?可以思考一下,也就是 list1 = list; 這樣,答案是會報錯,如下所示:

原因是什麼呢?是因爲list這個集合我們並沒有給它指定泛型,在dart裏面有一個動態數據類型,也就是說list集合是動態數據類型的集合,我們將一個動態數據類型賦值給一個確定類型的集合時會報錯,錯誤是動態類型集合不是確定類型集合的子類型,這一點需要注意。

除了上面的這種[]裏面直接添加元素的方式初始化以外,我們還可以通過集合的add()或者addAll()方法進行初始化集合的操作,比如下面的代碼:

List list = [1, 2, 3, '集合']; //初始化添加元素
List list3 = [];
list3.add('list3'); //通過add方法添加元素
list3.addAll(list);
print(list3);

結果就是:

2、常用方法

這裏只介紹一個集合中常用到的方法——集合的生成函數,其它的函數大家點到源碼裏面自行學習吧:

//創建一個具有length位置的列表,並用創建的值填充它,範圍爲0——length-1的每個索引升序排列
List.generate(int length, E generator(int index));

什麼意思呢?舉個栗子:

List list4 = List.generate(3, (index) => index * 3);
print(list4);

結果如下:

這裏對照着註釋我們來做個說明:函數體中第一個參數length傳入的值爲3,說明我們生成的這個集合的長度爲3,第二個參數實質上是一個方法體,“=>”符號在這裏我們可以當成是一個箭頭表達式,並且是方法體只包含一個表達式時才能這樣使用,所以這裏的第二個參數其實就是一個有返回值的函數,函數體是index(索引)乘以3,將得到的值進行返回,這個表達式也就等同於return index*3;的值,那麼這樣就很簡單了,在函數說明的時候我們說了範圍是0 - length-1的每個索引,那這裏的索引值也就是0,1,2,然後將每個索引值乘以3得到的值依次爲0,3,6,這樣就得到了我們的集合[0,3,6]。

除了集合的生成函數外,集合還有很多經常用到的方法,我就不再進行詳細的說明了,因爲這些方法我們在Java中也經常使用,所以大家肯定是見其面知其意,下面大致列舉幾個:

//刪除集合中的某個元素
bool remove(Object value);
//從集合中刪除指定位置處的元素
E removeAt(int index);
//在集合的指定位置處插入某個對象
void insert(int index, E element);
//截取指定範圍內的集合元素並返回成一個新的集合,入參的索引範圍同樣是包含左邊不包含右邊
List<E> sublist(int start, [int end]);
//查找集合中某個元素第一次出現的位置索引
int indexOf(E element, [int start = 0]);

3、List集合的遍歷

這裏介紹集合的常用的幾種遍歷方式:

第一種:沒有語言之分的for循環方式:

for (int i = 0; i < list.length; i++) {
    print(list[i]);
}

第二種:for...in...,同樣是for,但是表達式內部我們做一點修改,使用var關鍵字定義一個變量,然後使用in關鍵字在集合中進行遍歷:

for (var o in list) {
   print(o);
}

第三種:forEach()循環,將函數應用於集合的每個元素,括號內傳入的爲集合的元素:

list.forEach((val) {
    print(val);
});

三種遍歷方式得到的結果肯定都是一樣的,如下所示:

2.6、集合之Map

1、Map集合的初始化

Map是將key和value相關聯的對象,key和value都可以是任意類型的對象,並且key是唯一的,如果key重複,後面添加的key會替換前面的內容。

定義Map使用大括號“{}”,因爲map是key-value的形式,所以添加元素的時候也是以鍵值對的形式進行添加,鍵和值中間使用冒號“:”進行分隔,比如:'a':'小明' 的形式,元素和元素之間使用逗號“,”分隔。除了這種初始化的方式外,我們還可以使用另外一種更加靈活的初始化的方式,首先可以初始化一個空的map,比如 Map map = {};  然後我們往這個空的map裏面添加元素,我們使用中括號“[]”,中括號裏面跟上元素的key,然後使用等號“=”連接,在等號右邊爲其賦值,比如 map['a']='小明';

這裏簡單的寫個例子,這樣看起來更加直觀:

///Map初始化
Map names = {'xiaoming': '小明', "xiaohong": "小紅"};
print(names);
Map ages = {};
ages['xiaoming'] = 12;
ages['xiaohong'] = 18;
print(ages);

結果如下:

2、常用api

//根據集合中的某個key,刪除相關聯的元素
V remove(Object key);
//判斷集合中是否包含指定的key
bool containsKey(Object key);

3、Map的遍歷

第一種:forEach

它的裏面需要一個回調函數,回調函數裏面會輸出我們的key和value,代碼也很簡單:

///Map遍歷方式
ages.forEach((k, v) {
    print('$k,$v');
});

通過$引用key或者value,我們就可以根據需要去使用它的鍵或者值了。

第二種:map()方法

我們可以調用Map集合的map()方法遍歷生成一個新的map集合,這個方法接收一個回調函數,入參爲key、value,函數內部必須接受一個return,也就是說它會返回一個新的map,這裏通過MapEntry來返回之前Map裏面每一項的元素,我這裏將原map的key和value進行顛倒,那麼就可以得到一個相反的集合,來看一下代碼:

Map ages2 = ages.map((k, v) {
    return MapEntry(v, k);
});
print(ages2);

結果如下:

第三種:for循環

首先循環遍歷map集合中所有的key,可以通過map.keys獲取,它返回的是一個所有key值的數組(同樣的也有map.values),然後我們就可以通過map[key]獲取集合中的每一個元素了,代碼如下:

for (var key in ages.keys) {
    print('$key , ${ages[key]}');
}

這裏需要注意,我們使用字符串拼接的時候,如果需要調用方法的時候,就像上面ages[key]這樣的時候,必須在$後面跟上大括號這種方式進行調用,結果如下:

2.7、dynamic、var和Object的區別

1、dynamic 

先上一段代碼,看了之後再來說點具體的:

dynamic x = 'jarchie';
print(x.runtimeType);
print(x);
//x.foo(); //編譯不會報錯,運行時纔會發現x並無此方法,會報錯
x = 123;
print(x.runtimeType);
print(x);

結果如下:

它是dart裏面的動態數據類型,我們使用這個關鍵字定義了一個變量,打印了它的運行時,並且打印了這個變量值,通過結果可以看出它的運行時是一個String,也就是說動態數據類型在編譯時不知道你是什麼類型,然後在運行的時候根據你後面的值去推測你是什麼類型,它的好處是通過它可以定義任何的數據類型,缺點是它可以使dart的語法檢查失效,爲什麼會失效呢?因爲語法檢查是靜態語法檢查,也就是在不運行代碼的時候的語法檢查,比如上面我註釋掉的那行代碼,編譯的時候不會報錯,當你運行的時候會報錯:Class 'String' has no instance method 'foo',意思就是說這個變量並沒有foo()這個方法,所以我們最好不要直接去使用它,爲了避免帶來一些不必要的錯誤。我們在代碼中還更改了它的值爲整型數據123,此時它的運行時也就變成了int類型。

2、var

var是一個關鍵字,不必關心它的類型是什麼,系統也會自動推斷它的數據類型,它和動態數據類型最大的區別是,當它的類型被確定之後,它是不允許修改的,就是說編譯期語法檢查都過不去,舉個栗子:

    var a = "jarchie";
    print(a.runtimeType);
    print(a);
//    a=123; //下方報紅,語法檢查時有錯誤
    a = "anqi";

變量a的數據類型是已經確定爲字符串了,不能再賦值爲整型。

3、Object

Object是Dart裏對象的基類,當我們將一個變量定義爲Object類型的時候,系統就會認爲這個變量就是Object類型,對於Object類型它裏面有一些定義的方法,此時這個變量就可以調用相應的方法,它和動態數據類型最大的區別就是你不可以調用Object不存在的方法,編譯器語法檢查也是過不去的,因爲它的數據類型也是確定的。

好了,本篇Dart的常用數據類型部分就寫到這裏,下一篇準備寫Dart的面向對象,我也是希望自己能有時間去儘快的整理出來,實在抽不開身我也是沒有辦法啊,我太難了!要學的東西太多,學不動了。。。。。。大家加油,我先洗洗睡了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章