Flutter 之 Dart語言基礎詳解 上篇
經過了一個星期的React Native的學習和了解,感覺還是Flutter的優勢會更高一些,而且從學習成本來說感覺做安卓的同學學習flutter會相對低一點,門檻會低很多。
當然dart的基礎筆者還是從其他朋友的資料總結而來,這裡我儘可能的說的清楚一些!
首先是關鍵字(56個)
關鍵字 | - | - | - |
abstract | do | import | super |
as | dynamic | in | switch |
assert | else | interface | sync* |
enum | implements | is | this |
async* | export | library | throw |
await | external | mixin | true |
break | extends | new | try |
case | factory | null | typedef |
catch | false | operator | var |
class | final | part | void |
const | finally | rethrow | while |
continue | for | return | with |
covariant | get | set | yield* |
default | if | static | deferred |
從上面的關鍵字裡面可以看出和Java中的關鍵字還是有很多一樣的,含義也是如此。
變數的宣告
- var
- dynamic
- Objec
首先宣告一個變數,變數的型別可以改變:
var name; name = 'tom'; name = 123;
dynamic name; name = 'tom'; name = 123;
Object name; name = 'tom'; name = 123;
這裡是不會報錯的,說明變數的型別是可以改變的,並且都是可以print出來。
宣告一個初始化的變數,變數型別不能再更改:
var name = 'tom'; name = 123;//這裡是不對的,編譯器會報錯
這裡宣告一個name被發現時String型別的之後,就不能轉變其他的型別了。
但是:
dynamic 和 Object 宣告的變數初始化後,變數的型別仍可改變:
dynamic name = 'tom'; name = 123;
Object name = 'tom'; name = 123;
這裡dynamic和Object宣告的型別是可以改變的。
使用確定型別顯示宣告變數,變數的型別不能再改變:
String name = 'tom'; name = 123;//這裡已經定義name是Stiing型別的,就不能更改為int型別
預設值
看到這裡我們想了解了,如果宣告一個變數,沒有初始值的時候他的預設值是什麼呢?
dart裡面的預設值都是null,一切皆物件,物件的預設值是null。
var name; assert(name == null); print("assert pass");//可以正常列印
這裡我們發現此處的斷言是可以是真的,程式不會崩潰,說明預設值是null。
final 和 const
這兩個關鍵字很重要
首先被這兩個關鍵字修飾的變數,變數型別是可以省略的:
const age = 1; final sex = '男';
被其修飾的變數無法更改其值,並且宣告出來之後必須要進行初始化,相信學過Java的同學肯定對final這個關鍵字很熟悉了吧D)
var varList = const [1, 2, 3]; final finalList = const [1, 2, 3]; const constList = [1, 2, 3]; print([varList, finalList, constList]); varList = [1];//這裡允許更改 // constList = [1];//這裡不允許更改 // finalList = [1];
可以更改非 final,非 const 變數的值,即使它曾經具有 const 值。
final List ls = [1, 2, 3]; ls[2] = 444; print(ls); const List cLs = [4, 5, 6]; cLs[1] = 4; print("\n"); print(cLs);
這裡同樣是更改集合中某個元素的數值,final的是沒有問題的,const的編譯時沒問題,但是執行起來會報錯:
Unsupported operation: Cannot modify an unmodifiable list
不能更改一個不能修改的集合。
final finalList1 = [1, 2, 3]; final finalList2 = [4, 5, 6]; print("\n"); print(identical(finalList1, finalList2)); //identical用於檢查兩個引用是否指向同一個物件 const constList1 = [1, 2]; const constList2 = [1, 2]; print("\n"); print(identical(constList1, constList2)); //identical用於檢查兩個引用是否指向同一個物件
這裡相同的集合final宣告的會在記憶體中重複建立,const宣告的就不會重複建立,上面列印:
external bool indentical(Object a, Object b);這個方法傳入兩個引用來檢測是否指向同一個物件,返回bool型別。
常量如果是類級別的,必須要使用 static const來修飾:
class C{ static const String a = 'hehe'; //這裡只有類級別的常量的時候我們請使用static const來修飾,並且初始化 }
如果去掉static編譯就會報錯:Only static fields can be declared as const,只有靜態欄位可以宣告為const。
內建型別
Number數值(num,int,double)
首先int和double都是num的子類,用法跟int和double一樣,都是可以直接進行運算:
num n1 = 1; num n2 = 1.0; print('n1 + n2 = ${n1+n2}');
輸出:
n1 + n2 = 2.0
自動識別double型別輸出2.0不會丟失精度。
轉換
轉換這個環節是必不可少的,在Java中我們只int和double、float都是可以進行和String互相轉換的,dart中也是可以的:
int i2 = int.parse('1'); print('i2---->${i2}'); double d2 = 1;//當 double 的值為 int 值時,int 自動轉為 double print('d2:${d2}'); int i3 = int.tryParse('1.0');//返回 null print('i3:${i3}');
輸出如下:
這裡細心地同學看到i3為什麼輸出是null,而不是1或者1.0呢,我們為什麼呼叫tryParse而不用parse呢,試著去解析,如果有問題不會崩潰,個人理解這就是這個方法的真正的目的所在,1.0被識別出是double型別,我們用int去解析並且接受就會導致丟失精度的問題所以不予通過,方法會返回null,但是我們用parse來看看就發現程式崩潰了:
所以也就很容易理解了。
String 字串
說道String,Java的同學肯定很熟悉啦,不過dart裡面的String是UTF-16編碼的,所以我們可以用單引號''或者雙引號“”來宣告字串。
String string = 'haha'; String string1 = "hahaha";
都是ok的!
var name = 'HelloWorld'; //可以在字串中使用表示式: ${expression},如果表示式是一個識別符號,可以省略 {}。 //如果表示式的結果為一個物件,則 Dart 會呼叫物件的 toString() 函式來獲取一個字串 var names = 'HelloWorld ${name}'; //r 字首可以建立一個 “原始 raw” 字串 //加了r,轉義符號 \n 換行 \t (按一次tab鍵的水平製表符)不起作用了 var rawNames = r"HelloWorld ${name}"; print('name:${names}'); print('rawNames :${rawNames}');
這裡我們發現${}表示式可以直接拿去變數值來進行輸出,並且在字串前面加上r只有會發現這個表示式效果失效了,那這也是dart的一個規則吧,可以試一下字串裡面加上 \n、\t等轉義字元,會發現這些也都失效了,都被列印了出來!
看看下面程式碼:
//可以使用三個單引號或者雙引號也可以 建立多行字串物件 var multiLinesString = ''' Java Android Flutter'''; print('mutiLinesString:${multiLinesString}');
這裡我們發現用了三個‘來宣告一個字串,這樣得宣告有何意義呢?看一下效果:
你們會發現竟然跟我們擺放的字串格式一樣,對的,他的含義就是這樣!
接下來看一下StringBuffer的使用:
/// StringBuffer var sb = StringBuffer(); //dart 2 可以省略 new sb..write('aaa')..write('bbb')..write('ccc');//..級聯符實現鏈式呼叫 sb.writeAll(['aaa','bbb','ccc'],',');//第二個引數表示分隔符,將第一個引數列表裡的資料用這個分隔符拼接起來 print('sb:${sb}');
..的作用就是可以實現鏈式呼叫,writeAll方法:
external void writeAll(Iterable objects, [String separator = ""]);
方法點進去可以看到宣告的時候我們需要傳兩個引數,集合、切割符號,這正如輸出的結果我們看到確實如此!
Booleans 布林值 (bool)
bool的運用很簡單,跟Java是一樣的:
bool isNull; print('isNull:${isNull}');
執行結果:
大家肯定知道了,因為isNull沒有初始化所以預設值肯定是null,那如果我們初始化之後輸出就會如下:
isNull:false or isNull:true
List 列表(陣列 List)
//宣告一個自動長度的陣列 List growableList = new List(); growableList..add(1)..add(2)..add('HelloWorld'); print('growbleList: ${growableList}');
這裡我們用到了new這個關鍵字進行List例項的建立,通過..符號進行鏈式操作新增集合資料,列印如下:
growbleList: [1, 2, HelloWorld]
也可以換一種宣告方式:
var list = List(6); list[0] = "a"; list[1] = "b"; list[2] = "c"; list[3] = "d"; list[4] = "e"; list[5] = "f"; print('list:${list}');
這裡我們聲明瞭一個固定長度的集合並且挨個新增資料,列印如下:
list:[a, b, c, d, e, f]
我們還可以固定元素:
var typeList = List<String>(); typeList..add("1")..add("2")..add("3"); print('typeList:${typeList}');
如果放入其他的型別編譯器就會報錯。
還可以這樣宣告:
var varList = [1, 2, 3];
List ls = [1, 2, 3];
都是可以的。
還有List的一些常用方法,比如獲取第一個元素、最後一個元素等,還可以直接增刪、新增集合addAll等方法跟Java很類似,方法名都是顧名思義,很容易理解,這裡就不一一列舉了!
Maps 鍵值對集合 (Map)
Map的宣告有兩種方式:
1、直接宣告,用{}表示,裡面寫key和value,每組鍵值對中間用逗號隔開。
Map companys = {'Alibaba': '阿里巴巴', 'Tencent': '騰訊', 'baidu': '百度'}; // 輸出:{Alibaba: 阿里巴巴, Tencent: 騰訊, baidu: 百度} print(companys);
2、先宣告,再賦值
Map schoolsMap = new Map();//這裡用var宣告也是可以的 schoolsMap['first'] = '清華'; schoolsMap['second'] = '北大'; schoolsMap['third'] = '復旦'; // 列印結果 {first: 清華, second: 北大, third: 復旦} print(schoolsMap);
看起來是不是也是很容易呢!
接下來看一下它的Api:
Map中的賦值可以這樣做:
// Map的賦值,中括號中是Key,這裡可不是陣列 aMap[1] = '小米';
相同的Key可以覆蓋value數值,key是唯一的,value可以時null也可以是空‘’。
// 檢索Map是否含有某Key assert(aMap.containsKey(1));
//刪除某個鍵值對 aMap.remove(1);
可以看出它的api也是很容易,相比Java有些地方我覺得方便不少呢!
注意事項:
// 注意事項 // 1.map的key型別不一致也不會報錯。 // 2.新增元素的時候,會按照你新增元素的順序逐個加入到map裡面,哪怕你的key, // 比如分別是 1,2,4,看起來有間隔,事實上新增到map的時候是{1:value,2:value,4:value} 這種形式。 // 3.map裡面的key不能相同。但是value可以相同,value可以為空字串或者為null
Set 集合 (Set)
set是無重複列表
看下面:
var dynamicSet = Set(); dynamicSet.add('a'); dynamicSet.add('b'); dynamicSet.add('c'); dynamicSet.add('1'); dynamicSet.add('1'); print('dynamicSet :${dynamicSet}');
這裡會輸出:
dynamicSet :{a, b, c, 1}
看到重複的不存在了!
set裡面有一個方法difference(),用來返回兩個set之間交集,比如,a.difference(b),則返回a有但是b沒有的,反之則反。
intersection這個方法是返回兩個集合的交集共有的;
union這個方法返回兩個集合的並集。
Runes 符號字元
//Runes用於在字串中表示Unicode字元 //https://copychar.cc/emoji/ String runesStr = '