1. 程式人生 > >Flutter 之 Dart語言基礎詳解 上篇

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中的關鍵字還是有很多一樣的,含義也是如此。

變數的宣告

  1. var
  2. dynamic
  3. 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 = '