Flutter開發之Dart語言基礎

xiangzhihong發表於2019-07-25

Flutter 發展歷史

Flutter是Google開發的一款用於幫助開發者在iOS和Android兩個平臺構建高質量原生應用的全新移動UI框架。說到Flutter,很多同學可能會將它和下面的幾個詞關聯起來:新興的、移動端、動態化、跨平臺、開發框架。

簡單來說,Flutter是一款移動應用程式SDK,包含框架、widget和工具,為開發人員提供了一種在Android和iOS上構建和部署精美移動應用程式的簡單高效的方式。

Flutter專案由來已久,但真正為人所熟知確是在2017年5月Google I/O大會上,下面就讓我們來看一下Flutter專案的發展歷程:

  • 2014.10: Flutter的前身Sky在GitHub上開源。
  • 2015.10: 經過一年的開源,Sky正式改名為Flutter,低調期。
  • 2017.5: Google I/O正式向外界公佈了Flutter,這個時候Flutter才正式進去大家的視野。
  • 2018.6: 距5月Google I/O 1個月的時間,Flutter1.0預覽版。
  • 2018.12:Flutter1.0釋出,它的釋出將大家對Flutter的學習和研究推到了一個新的起點。
  • 2019.2:Flutter1.2釋出主要增加對web的支援。
  • 2019.5 :Flutter 1.5 釋出,此版本Flutter 釋出了Web版本, 正式開啟了 Flutter 的全平臺 UI 框架之路。
  • 2019.7 :Flutter 1.7 釋出,新增對AndroidX、Android App Bundles 和 64 位的 Android 應用的支援,加入一些新的功能和Widget以及解決一些開發者提出的問題。

隨著Flutter逐漸走向成熟,其開發生態圈也在不斷的發展,學習Flutter成為前端開發者不可缺少的傍身技能。

Dart語言基礎

簡介

Dart是由Google開發的一門全新的計算機程式語言,後來被ECMA批准為標準的計算機程式語言,適用於伺服器、瀏覽器、移動應用和物聯網等領域的開發。 Dart SDK由谷歌推出,附帶其編譯器 - Dart VM。 SDK還包括一個實用程式 - dart2js,一個生成與Dart指令碼等效的JavaScript的轉換程式。 總體來說,Dart是一種物件導向的語言,具有C語言風格的語法,可以選擇將它編譯成JavaScript。它支援各種程式設計輔助工具,如:介面,類,集合,泛型和可選型別。 Dart可以廣泛用於建立單頁面應用程式。單頁應用程式僅適用於網站和Web應用程式。單頁應用程式可以在網站的不同螢幕之間進行導航,而無需在瀏覽器中載入不同的網頁。

下面是Dart與JavaScript的一些簡單區別:

在這裡插入圖片描述
ps:谷歌釋出了一個特殊的Chromium版本 - Dart VM 。使用Dartium可以在瀏覽器上進行測試之前,不必將程式碼編譯為JavaScript。

Dart 開發環境

執行Dart 程式碼,可以使用兩種方式,本地編輯器環境和線上執行環境。

線上執行環境

可以使用 dartpad.dartlang.org/ 線上編輯器線上執行程式碼,如下圖所示:

在這裡插入圖片描述

本地編輯器

在本地執行Dart程式碼需要先安裝Dart Sdk,可以從以下地址進行下載:

完成SDK安裝後,將Dart可執行檔案新增環境變數,如下所示:

<dart-sdk-path>\bin
複製程式碼

如果要驗證是否成功安裝Dart,可以開啟命令提示符並輸入以下命令 :

dart
複製程式碼

如果輸出相應的資訊,即說明安裝成功!

IDE

目前,支援Dart的IDE主要有Eclipse、VSCode、IntelliJ、Android Studio和WebStorm。使用IDE開發Dart應用程式時,只需要安裝Dart外掛即可。例如,下面是Android Studio安裝Dart外掛:

在這裡插入圖片描述

dart2js工具

art2js工具用於將Dart程式碼編譯為JavaScript。將Dart程式碼編譯為JS可以在不支援Dart VM的瀏覽器上執行Dart指令碼。 dart2js工具作為Dart SDK的一部分提供,可以在/dartsdk/bin資料夾中找到。要將Dart編譯為JavaScript,可以在終端中鍵入以下命令:

dart2js - - out = <output_file>.js  <dart_script>.dart
複製程式碼

執行此命令後輝生成一個檔案,即與Dart程式碼等效的JavaScript。

第一個Dart程式

學習一門新的語言,都會來一個“Hello World!”,學習Dart 之前,我們也來一個“Hello World!”。

main() { 
   print("Hello World!"); 
}
複製程式碼

其中,main()函式是Dart中的預定義方法,此方法充當應用程式的入口點。執行上面的程式碼,輸出結果如下:

Hello World!
複製程式碼

說明,JavaScript沒有預定義的入口函式,但在Dart程式中,每個app都必須有一個頂級的main()函式作為應用程式的入口點。

Dart基礎語法

程式碼註釋

註釋是提高程式可讀性的一種有效方法,註釋通常包含程式碼的作者、函式/構造提示等資訊。編譯器在編譯程式時會忽略註釋。目前,Dart支援以下型別的註釋:

// 單行註釋

/*
 * 多行註釋
 */

/**
 * 文件註釋
 */

/// 使用三個斜槓開頭
/// 這是Dart特有的文件註釋
複製程式碼

Dart關鍵字

關鍵字在語言的上下文中具有特殊含義,下表是Dart語言中的一些關鍵字:

在這裡插入圖片描述
說明,和Java等面嚮物件語言一樣,如下一些規則對Dart也適用:

空白和換行 Dart忽略程式中出現的空格,製表符和換行符。可以在程式中自由使用空格,製表符和換行符,並且可以自由地以簡潔一致的方式格式化和縮排程式,使程式碼易於閱讀和理解。

大小寫區分 Dart區分大小寫,Dart中大寫和小寫字元表示不同地含義。

宣告以分號結尾 每行指令都稱為語句。每個dart語句必須以分號(;)結尾。一行可以包含多個語句。但是,這些語句必須用分號分隔。

類與物件

Dart是一種物件導向的語言,物件導向是一種遵循真實世界建模的軟體開發範例。在物件導向的程式設計世界裡, 物件可以認為是任何實體的實時表示,具有如下幾個特徵:

  • 狀態:由物件的屬性描述。
  • 行為:描述物件的行為方式。
  • 標識:將物件與一組類似此類物件區分開的唯一值。

而類則是建立物件的藍圖/模板,類可以封裝物件的資料。

class TestClass {   
   void display() {     
      print("Dart and Object Orientation"); 
   } 
}  
void main() {   
   TestClass c = new TestClass();   
   c.display();  
}
複製程式碼

內建資料型別

Dart支援的內建資料型別主要有以下幾種:

  • numbers 數字
  • strings 字串
  • booleans 布林
  • lists(也被稱之為arrays)list和陣列
  • sets set集合
  • maps map集合
  • runes(用於在字串中表示Unicode字串)
  • symbols 符號

其中,沒有初始化的變數預設值為 null。數值型別變數的預設值也是 null。數值型別num有兩個具體子類,分別為int和double,其中int為整數值,範圍是-2^53 -2^53之間;double則是64位的雙精度浮點數。

變數與常量

變數

Dart中定義變數有兩種方式,一種是靜態型別語言常用的方式,即顯式指定變數的型別;另一種則是動態語言的常用方式,不指定型別,由vm自動推斷。例如:

// 1.通過顯式指定型別來定義變數
String name = "張三";
num age = 18;

// 2.使用關鍵字var,不指定型別
var address = "深南大道";
var id = 100;
複製程式碼

需要說明的是,使用var定義變數時,即使未顯式指定型別,一旦賦值後型別就被固定,如果再改變變數的型別,則會報錯:

var number = 19;
// 以下程式碼錯誤,無法執行,number變數已確定為int型別
number = "2019";
複製程式碼

對於上面的情況,可以使用動態改變變數的資料型別,即使用dynamic或Object來定義變數。

// dynamic宣告變數
dynamic var1 = "hello";
var1 = 19;
print(var1);                 // 19

// Object宣告變數
Object var2 = 20;
var2 = "Alice";
print(var2);              // Alice

複製程式碼

常量

Dart支援的常量定義方式也有兩種,一種是使用final關鍵字,同Java中的用法, 一個 final 變數只能賦值一次;另一種是Dart的方式,使用const關鍵字定義,也是JavaScript採用的方式。

// 使用final關鍵字定義常量
final height = 10;

// 使用const關鍵字定義常量
const pi = 3.14;
複製程式碼

需要說明的是,final定義的常量是執行時常量,而const常量則是編譯時常量,也就是說final定義常量時,其值可以是一個變數,而const定義的常量,其值必須是一個字面常量值。

final time = new DateTime.now(); // 正確
const time = new DateTime.now(); // 錯誤


const list = const[1,2,3];       // 正確
const list = [1,2,3];            // 錯誤

複製程式碼

Dart基本型別操作

Dart支援的基本資料型別主要有以下幾種:

  • 數字
  • 字串
  • 布林
  • 列表(類似於陣列)
  • 集合
  • 對映符文(用於表示字串中的Unicode字元)
  • 符號

數字

Dart中的數字型別有兩種型別:整數和雙精度型別。

  • 整數:整數值表示非小數值,即沒有小數點的數值。例如,10是整數。
  • 雙精度數:Dart還支援小數數值,即帶小數點的值,Dart中的Double資料型別表示64位(雙精度)浮點數。例如,10.10。
//整數
var x = 123;
var hex = 0xDEADBEEF;

//雙精度數
var y = 1.199;
var exponents = 1.42e5;

複製程式碼

從Dart 2.1開始,必要時整數會自動轉換為雙精度數,例如:

double z = 10;  // 相當於 double z = 10.0.
複製程式碼

除此之外,字串也可以轉換為數字,例如:

// String 轉為 int
var one = int.parse('1');
assert(one == 1);

// String 轉為 double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);

// int 轉為 String
String oneAsString = 1.toString();
assert(oneAsString == '1');

// double 轉為 String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');
複製程式碼

字串

字串代表一系列字元。例如,如果要儲存一些資料,如名稱,地址等,則應使用字串資料型別。Dart字串是一系列UTF-16程式碼單元。符文用於表示UTF-32程式碼單元序列。

Dart使用關鍵字String來表示字串文字,字串的值支援單引號或雙引號方式。

var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";

複製程式碼

同事,可以使用${expression}將表示式的值放在字串中。如果表示式是識別符號,則可以跳過{}。

var name = "王五";
var aStr = "hello,${name}";
print(aStr);  
複製程式碼

Dart還支援使用"+"操作符拼接字串。

var greet = "hello" + " world";
複製程式碼

使用帶有單引號或雙引號的三引號建立多行字串。

var s1 = '''
You can create
multi-line strings like this one.
''';
複製程式碼

布林型別

和Java語言中的boolean型別類似,Dart中的布林型別僅有false、true兩個值,不能使用0、非0或者null、非null來表達false和true。

bool flags;
print(flags);    // null
複製程式碼

列表

在Dart中,陣列是一個List物件,大多數人也將它稱為列表。Dart中列表操作與JavaScript中的陣列相似。

var list = [1, 2, 3];
複製程式碼

列表使用從0開始的索引,其中0是第一個元素的索引,list.length-1是最後一個元素的索引。可以獲得列表的長度並像在JavaScript中一樣引用列表元素,例如:

var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);

list[1] = 1;
assert(list[1] == 1);
複製程式碼

要建立一個編譯時常量的列表,可以在列表文字之前新增const關鍵字,例如:

var constantList = const [1, 2, 3];
複製程式碼

同事,Dart 在2.3版本引入了擴充套件運算子(...)和空值感知擴充套件運算子(...?),它提供了一種將多個元素插入集合的簡潔方法。例如,使用擴充套件運算子(...)將列表的所有元素插入另一個列表:

var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
複製程式碼

如果擴充套件運算子右側的表示式可能為null,則可以通過使用支援null的擴充套件運算子(...?)來避免異常:

var list;
var list2 = [0, ...?list];
assert(list2.length == 1);
複製程式碼

集合

Dart中的Set是無序的唯一項的集合,Dart支援由Set文字和Set型別提供的集合。例如,下面是一個簡單的Dart集合:

var test = {'yiibai.com', 'chlorine', 'bromine', 'iodine', 'astatine'};
複製程式碼

集合支援使用add()或addAll()方法,例如:

var elements = <String>{};
elements.add('hello');
elements.addAll(test);
複製程式碼

同樣,要建立一個編譯時常量的集合,請在set文字之前新增const關鍵字:

final constantSet = const {
  'fluorine',
  'chlorine',
  'bromine',
  'iodine',
  'astatine',
};
複製程式碼

對映

對映,又稱為關聯陣列,相當於Java中的HashMap。對映由關聯鍵和值構成,鍵和值都可以是任何型別的物件。每個鍵只出現一次,但可以多次使用相同的值。

var gifts = {
  // Key:    Value
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};

var nobleGases = {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};
複製程式碼

當然,Dart還可以使用Map建構函式建立相同的物件。

var gifts = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
複製程式碼

要建立一個編譯時常量的對映,可以在map文字之前新增const關鍵字,例如:

final constantMap = const {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};
複製程式碼

符文

在Dart中,符文使用的是字串的UTF-32程式碼點。Unicode為世界上所有書寫系統中使用的每個字母,數字和符號定義唯一的數值。由於Dart字串是UTF-16程式碼單元的序列,因此在字串中表示32位Unicode值需要使用特殊語法。

在Dart中,String類有幾個屬性可用於提取符文資訊。codeUnitAt和codeUnit屬性返回16位程式碼單元。

符號

Symbol物件表示Dart程式中宣告的運算子或識別符號。可能永遠不需要使用符號,但它們對於按名稱引用識別符號的API非常有用,因為縮小會更改識別符號名稱而不會更改識別符號符號。

要獲取識別符號的符號,請使用符號文字,例如:

#radix
#bar
複製程式碼

函式

函式是一組用於執行特定任務的程式碼塊,我們可以將程式看成是多個函式按照某種邏輯組建的程式碼塊。

在Dart中,函式(或方法)也是一個物件,它的型別是 Function。 這意味著,函式可以賦值給變數,也可以當做其他函式的引數。

基本定義

在Dart中定義函式,基本上與Java類似,例如:

/ 定義一個不帶返回值的函式,可以帶void, 也可以不帶
void say(var word){
    print("I say '${word}'";
}
 
// 引數可以不用指定型別,如果不指定,則預設是var
bool isInt(numVar){
    return numVar is int;
}
 
// 如果函式只有一個return 語句可以用 => 簡寫
// 需要注意 => 後面只能是一個表示式或者是單條語句。
bool isInt2(numVar) => numVar is int;
 
main(){
   say('hello world'); // I say 'hello world'
   print(isInt('a')); // false
   print(isInt(1)); // true
}

複製程式碼

引數

Dart支援命名可選引數和位置可選引數。其中,命名可選引數使用的是{}, 位置可選引數使用的是[]。區別就是, 如果用{}宣告,在使用時必須帶著引數名,如:a:123;如果用[]宣告,在使用時需要按照順序使用。 命令可選引數

// 定義一個函式,引數列表用花括號包裹
enableFlags({bool bold, bool hidden}) {
    // do something
}

// 呼叫方式,傳參時使用"引數名:值"的形式
enableFlags(hidden:true,bold:false);
複製程式碼

位置可選引數

// 定義add函式
add(int x, [int y, int z]){
    int result = x;
    if (y !=  null){
        result = result + y;
    }

    if (z !=  null){
        result = result + z;
    }
    print(result);
}

// 呼叫
add(18);           // 18
add(18,12);        // 30
add(18, 12, 15);   // 45

複製程式碼

如果要給位置可選引數設定預設值,可以使用下面的方式:

add(int x, [int y=0, int z=0]){
    print(x +y+z);
}
複製程式碼

匿名函式

大部分情況下,函式都有自己的名字,但我們也可以建立沒有名字的函式,稱為匿名函式。

var func = (x,y){
    return x + y;
};

print(func(10,11));        // 21
複製程式碼

閉包

閉包(Closure)是一種能被呼叫物件,它儲存了建立它的作用域的資訊,因此閉包可以讀取其他作用域內的變數使用。使用匿名函式可以輕鬆的實現Dart的閉包,例如:

Function makeAdder(num){
  return (addNum){
    return addNum + num;
  };
}
main(){
  var add5 = makeAdder(5);
  var add10 = makeAdder(10);
 
  print(add5(1)); // 6
  print(add10(1)); // 11
}

複製程式碼

運算子

Dart語言中的運算子與Java中的運算子絕大多數相同,主要的運算子有如下一些:

  • 算術運算子
  • 相等和關係運算子
  • 型別檢查運算子
  • 按位運算子
  • 賦值運算子
  • 邏輯運算子

算術運算子

Dart的算術運算子,除了常見的+、-、*、/、%之外,Dart中又多出了一個整除運算子~/,與普通除號的區別是將相除後的結果取整返回。

在這裡插入圖片描述

assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5);
assert(5 ~/ 2 == 2);
assert(5 % 2 == 1);
複製程式碼

關係運算子

關係運算子測試或定義兩個實體之間的關係型別。Dart的關係運算子如下表:

在這裡插入圖片描述
例如:

assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);
複製程式碼

型別檢查運算子

型別檢查運算子可以方便地在執行時檢查型別,Dart的型別檢查運算子主要由as、is和is!組成。

在這裡插入圖片描述

按位運算子

Dart支援的按位運算子及其作用如下表:

在這裡插入圖片描述
例如:

final value = 0x22;
final bitmask = 0x0f;

assert((value & bitmask) == 0x02);
assert((value & ~bitmask) == 0x20);
assert((value | bitmask) == 0x2f);
assert((value ^ bitmask) == 0x2d);
assert((value << 4) == 0x220);
assert((value >> 4) == 0x02);

複製程式碼

賦值運算子

賦值用 = 運算子,如果在前面加上其他運算子(比如 += )就可以組成複合賦值運算子。Dart支援的賦值運算子如下表:

在這裡插入圖片描述

邏輯運算子

邏輯運算子用於組合兩個或多個條件, 邏輯運算子返回一個布林值。

在這裡插入圖片描述
例如:

if (!done && (col == 0 || col == 3)) {
  // ...
}
複製程式碼

條件分支

Dart中條件表示式和其他語言類似,主要由if語句、if…else語句和else…if語句組成。

在這裡插入圖片描述
例如,if條件分支

if(i < 0){
  print('i < 0');
}else if(i == 0){
  print('i = 0');
} else {
  print('i > 0');
}
複製程式碼

switch條件分支:

String command = 'OPEN';
switch (command) {
  case 'CLOSED':
    break;
  case 'OPEN':
    break;
  default:
    print('Default');
}
複製程式碼

迴圈語句

和Java的迴圈語句類似,Dart的迴圈語句主要由for迴圈、while迴圈和do…while迴圈等迴圈語句構成。其中,for迴圈和for…in迴圈又稱為確定(Definite)迴圈,如下表:

在這裡插入圖片描述
例如:

for(int i = 0; i < 9; i++) {
  print(i);
}
複製程式碼

while迴圈和do…while迴圈被稱為無限迴圈,如下表:

在這裡插入圖片描述
例如:

/ while迴圈
while(true){
  //do something
}

// do-while迴圈
do{
  //do something
} while(true);
複製程式碼

為了控制迴圈語句,可以使用break語句和continue語句,如下表:

在這裡插入圖片描述
例如: break控制語句

void main() { 
   outerloop: // This is the label name 

   for (var i = 0; i < 5; i++) { 
      print("Innerloop: ${i}"); 
      innerloop: 

      for (var j = 0; j < 5; j++) { 
         if (j > 3 ) break ; 

         // Quit the innermost loop 
         if (i == 2) break innerloop; 

         // Do the same thing 
         if (i == 4) break outerloop; 

         // Quit the outer loop 
         print("Innerloop: ${j}"); 
      } 
   } 
}
複製程式碼

continue控制語句

void main() { 
   outerloop: // This is the label name 

   for (var i = 0; i < 3; i++) { 
      print("Outerloop:${i}"); 

      for (var j = 0; j < 5; j++) { 
         if (j == 3){ 
            continue outerloop; 
         } 
         print("Innerloop:${j}"); 
      } 
   } 
}
複製程式碼

附錄:Dart語言基礎教程

相關文章