從0開始寫一個基於Flutter的開源中國客戶端(2)——Dart語法基礎

yuxiyu發表於2018-07-20

上一篇介紹了跨平臺移動開發解決方案Flutter以及Flutter開發環境的搭建,由於Flutter開發使用的是Dart語言,故本篇記錄的是Dart語言的語法基礎,希望跟小夥伴們一起溫故知新。

索引 文章
1 從0開始寫一個基於Flutter的開源中國客戶端(1)
Flutter簡介及開發環境搭建 | 掘金技術徵文
?2 從0開始寫一個基於Flutter的開源中國客戶端(2)
Dart語法基礎
3 從0開始寫一個基於Flutter的開源中國客戶端(3)
初識Flutter & 常用的Widgets
4 從0開始寫一個基於Flutter的開源中國客戶端(4)
Flutter佈局基礎
5 從0開始寫一個基於Flutter的開源中國客戶端(5)
App整體佈局框架搭建
6 從0開始寫一個基於Flutter的開源中國客戶端(6)
各個靜態頁面的實現
7 從0開始寫一個基於Flutter的開源中國客戶端(7)
App網路請求和資料儲存
8 從0開始寫一個基於Flutter的開源中國客戶端(8)
外掛的使用

Dart語言簡介

Dart是Google推出的一門程式語言,最初是希望取代Javascript執行在瀏覽器端,後來慢慢發展成可以開發Android、iOS和Web端App的一門高質量的程式語言,目前Dart的版本是Dart2,官網是:www.dartlang.org/

在Dart官方網站上,對於Dart的描述如下:

Developers at Google and elsewhere use Dart to create high-quality, mission-critical apps for iOS, Android, and the web. With features aimed at client-side development, Dart is a great fit for both mobile and web apps.

Google和其他地方的一些開發者使用Dart語言為Android、iOS和web構建高質量,關鍵任務的應用程式,針對客戶端開發的特點,Dart非常適合移動和Web應用程式。

Dart語言的特性

Productive(豐富多產的)

Dart’s syntax is clear and concise, its tooling simple yet powerful. Sound typing helps you to identify subtle errors early. Dart has battle-hardened core libraries and an ecosystem of thousands of packages.

Dart的語法清晰明瞭,工具簡單但功能強大。Sound typing有助於早期識別細微的錯誤。Dart擁有久經沙場的核心庫和數以千計的生態系統。

Fast(快速的)

Dart provides optimizing ahead-of-time compilation to get predictably high performance and fast startup across mobile devices and the web.

Dart提供提前優化編譯,以在移動裝置和Web上獲得可預測的高效能和快速啟動。

Portable(可移植的)

Dart compiles to ARM and x86 code, so that Dart mobile apps can run natively on iOS, Android, and beyond. For web apps, Dart transpiles to JavaScript.

Dart可編譯成ARM和X86程式碼,這樣Dart移動應用程式可以在iOS、Android和其他地方執行。對於Web應用程式,DART可編譯成JavaScript。

Approachable(親切的)

Dart is familiar to many existing developers, thanks to its unsurprising object orientation and syntax. If you already know C++, C#, or Java, you can be productive with Dart in just a few days.

Dart對於許多現有的開發人員來說是熟悉的,這得益於其令人驚訝的物件定位和語法。如果你已經知道C++,C語言,或者Java,你可以在短短几天內用Dart來開發。

Reactive(反應式的)

Dart is well-suited to reactive programming, with support for managing short-lived objects—such as UI widgets—through Dart’s fast object allocation and generational garbage collector. Dart supports asynchronous programming through language features and APIs that use Future and Stream objects.

Dart非常適合於反應式程式設計,支援通過Dart的快速物件分配和代垃圾收集器來管理諸如UI小部件之類的短命物件。Dart通過使用未來和流物件的語言特徵和API支援非同步程式設計。

Dart語法簡介

關於Dart的語法,如果你熟悉Java,應該很快能掌握Dart,官網上對於Dart的語法也有詳細介紹,不過是全英文的,如果對英文沒有什麼閱讀障礙,可以直接移步官方文件

為了瞭解Dart的語法基礎,這裡我們使用Android Studio作為開發工具(你也可以使用dartpad來執行程式碼,它是一個基於瀏覽器的dart執行時環境),如果你按照上一篇文章中搭建好了Flutter開發環境,那麼可以直接在Android Studio中新建Flutter專案,如下圖所示:

從0開始寫一個基於Flutter的開源中國客戶端(2)——Dart語法基礎
新建立的Flutter專案,Dart程式碼主要在lib/main.dart檔案中,由於本篇主要是講Dart的語法,故暫時不看main.dart檔案,在lib目錄下我們建立一個新的.dart檔案demo.dart,如下圖所示:
從0開始寫一個基於Flutter的開源中國客戶端(2)——Dart語法基礎
在新建的demo.dart檔案中,輸入如下程式碼:

// Define a function.
printInteger(int aNumber) {
  print('The number is $aNumber.'); // Print to console.
}

// This is where the app starts executing.
main() {
  var number = 42; // Declare and initialize a variable.
  printInteger(number); // Call a function.
}
複製程式碼

然後在程式碼編輯區域滑鼠右鍵,選擇Run demo.dart,即可執行一個最簡單的dart程式,如下圖所示:

從0開始寫一個基於Flutter的開源中國客戶端(2)——Dart語法基礎
執行後控制檯輸出如下圖:
從0開始寫一個基於Flutter的開源中國客戶端(2)——Dart語法基礎
關於上面的程式碼,有如下幾點需要說明:

  1. Dart中單行註釋使用//,Dart同時支援多行註釋和文件註釋,可以點選這裡檢視更多

  2. int是Dart中的一種資料型別,同時還有其他的一些內建資料型別如String List bool

  3. 控制檯輸出使用print語句

  4. 字串使用單引號或雙引號均可,如'hello', "hello"

  5. 字串插入可以使用類似$name${name}的語法,比如下面的程式碼:

      var name = 'zhangsan';
      print("hello, I am $name");
      int a = 10, b = 20;
      print("$a + $b = ${a + b}");
    複製程式碼

    如果使用${name}這種方式,大括號中可以是表示式

  6. 你可能已經注意到了,Dart的變數型別是可選的,你可以為某個變數指定型別,或者使用var定義變數,Dart會自動推斷變數的型別

重要概念

當你在學習Dart語言時,下面的這些事實和概念請牢記於心:

  • 在Dart中,一切都是物件,一切物件都是class的例項,哪怕是數字型別、方法甚至null都是物件,所有的物件都是繼承自Object
  • 雖然Dart是強型別語言,但變數型別是可選的因為Dart可以自動推斷變數型別
  • Dart支援範型,List<int>表示一個整型的資料列表,List<dynamic>則是一個物件的列表,其中可以裝任意物件
  • Dart支援頂層方法(如main方法),也支援類方法或物件方法,同時你也可以在方法內部建立方法
  • Dart支援頂層變數,也支援類變數或物件變數
  • 跟Java不同的是,Dart沒有public protected private等關鍵字,如果某個變數以下劃線(_)開頭,代表這個變數在庫中是私有的,具體可以看這裡
  • Dart中變數可以以字母或下劃線開頭,後面跟著任意組合的字元或數字
  • 有時重要的是某事是一個表達還是一個陳述,所以這兩個詞的精確性是有幫助的
  • Dart工具可以報告兩種問題:警告和錯誤。警告只是指示程式碼可能無法工作,但它們不會阻止程式執行。錯誤可以是編譯時,也可以是執行時發生。編譯時錯誤根本不允許程式碼執行;執行時錯誤導致程式碼執行時引發異常。

變數

變數定義

以下程式碼是Dart中定義變數的方法:

main() {
  var a = 1;
  int b = 10;
  String s = "hello";
  dynamic c = 0.5;
}
複製程式碼

你可以明確指定某個變數的型別,如int bool String,也可以用vardynamic來宣告一個變數,Dart會自動推斷其資料型別。

變數的預設值

注意:沒有賦初值的變數都會有預設值null

final和const

如果你絕不想改變一個變數,使用finalconst,不要使用var或其他型別,一個被final修飾的變數只能被賦值一次,一個被const修飾的變數是一個編譯時常量(const常量毫無疑問也是final常量)。可以這麼理解:final修飾的變數是不可改變的,而const修飾的表示一個常量。

注意:例項變數可以是final的但不能是const的

下面用程式碼說明:

  final String name = 'zhangsan';
  name = 'lisi'; // 編譯不通過,被final修飾的是常量,不可重新賦值
  const a = 0;
  a = 1; // 錯誤
複製程式碼

finalconst的區別:

  • 區別一:final 要求變數只能初始化一次,並不要求賦的值一定是編譯時常量,可以是常量也可以不是。而 const 要求在宣告時初始化,並且賦值必需為編譯時常量。
  • 區別二:final 是惰性初始化,即在執行時第一次使用前才初始化。而 const 是在編譯時就確定值了。

內建資料型別

Dart有如下幾種內建的資料型別:

  • numbers
  • strings
  • booleans
  • lists(或者是arrays)
  • maps
  • runes(UTF-32字符集的字元)
  • symbols

下面用一段程式碼來演示以上各類資料型別:

main() {
  // numbers
  var a = 0;
  int b = 1;
  double c = 0.1;

  // strings
  var s1 = 'hello';
  String s2 = "world";

  // booleans
  var real = true;
  bool isReal = false;

  // lists
  var arr = [1, 2, 3, 4, 5];
  List<String> arr2 = ['hello', 'world', "123", "456"];
  List<dynamic> arr3 = [1, true, 'haha', 1.0];

  // maps
  var map = new Map();
  map['name'] = 'zhangsan';
  map['age'] = 10;
  Map m = new Map();
  m['a'] = 'a';

  //runes,Dart 中 使用runes 來獲取UTF-32字符集的字元。String的 codeUnitAt and codeUnit屬性可以獲取UTF-16字符集的字元
  var clapping = '\u{1f44f}';
  print(clapping); // 列印的是拍手emoji的表情

  // symbols
  print(#s == new Symbol("s")); // true
}
複製程式碼

函式

函式的返回值

Dart是一個物件導向的程式語言,所以即使是函式也是一個物件,也有一種型別Function,這就意味著函式可以賦值給某個變數或者作為引數傳給另外的函式。雖然Dart推薦你給函式加上返回值,但是不加返回值的函式同樣可以正常工作,另外你還可以用=>代替return語句,比如下面的程式碼:

// 宣告返回值
int add(int a, int b) {
  return a + b;
}

// 不宣告返回值
add2(int a, int b) {
  return a + b;
}

// =>是return語句的簡寫
add3(a, b) => a + b; 

main() {
  print(add(1, 2)); // 3
  print(add2(2, 3)); // 5
  print(add3(1, 2)); // 3
}
複製程式碼

命名引數、位置引數、引數預設值

命名引數

使用花括號將函式的引數括起來就是定義了命名引數,如下面的程式碼所示:

sayHello({String name}) {
  print("hello, my name is $name");
}

sayHello2({name: String}) {
  print("hello, my name is $name");
}

main() {
  // 列印 hello, my name is zhangsan
  sayHello(name: 'zhangsan');

  // 列印 hello, my name is wangwu
  sayHello2(name: 'wangwu');
}
複製程式碼

可以看到,定義命名引數時,你可以以{type paramName}或者{paramName: type}兩種方式宣告引數,而呼叫命名引數時,需要以funcName(paramName: paramValue)的形式呼叫。

命名引數的引數並不是必須的,所以上面的程式碼中,如果呼叫sayHello()不帶任何引數,也是可以的,只不過最後列印出來的結果是:hello, my name is null,在Flutter開發中,你可以使用@required註解來標識一個命名引數,這代表該引數是必須的,你不傳則會報錯,比如下面的程式碼:

const Scrollbar({Key key, @required Widget child})
複製程式碼

位置引數

使用中括號[]括起來的引數是函式的位置引數,代表該引數可傳可不傳,位置引數只能放在函式的引數列表的最後面,如下程式碼所示:

sayHello(String name, int age, [String hobby]) { // 位置引數可以有多個,比如[String a, int b]
  StringBuffer sb = new StringBuffer();
  sb.write("hello, this is $name and I am $age years old");
  if (hobby != null) {
    sb.write(", my hobby is $hobby");
  }
  print(sb.toString());
}

main() {
  // hello, this is zhangsan and I am 20 years old
  sayHello("zhangsan", 20);
  // hello, this is zhangsan and I am 20 years old, my hobby is play football
  sayHello("zhangsan", 20, "play football");
}
複製程式碼

引數預設值

你可以為命名引數或者位置引數設定預設值,如下程式碼所示:

// 命名引數的預設值
int add({int a, int b = 3}) { // 不能寫成:int add({a: int, b: int = 3})
  return a + b;
}

// 位置引數的預設值
int sum(int a, int b, [int c = 3]) {
  return a + b + c;
}
複製程式碼

main()函式

不論在Dart還是Flutter中,必須都需要一個頂層的main()函式,它是整個應用的入口函式,main()函式的返回值是void,還有一個可選的引數,引數型別是List<String>

函式作為一類物件

你可以將一個函式作為引數傳給另一個函式,比如下面的程式碼:

printNum(int a) {
  print("$a");
}

main() {
  //  依次列印:
  //  1
  //  2
  //  3
  var arr = [1, 2, 3];
  arr.forEach(printNum);
}
複製程式碼

你也可以將一個函式賦值給某個變數,比如下面的程式碼:

printNum(int a) {
  print("$a");
}

main() {
  var f1 = printNum;
  Function f2 = printNum;
  var f3 = (int a) => print("a = $a");
  f1(1);
  f2(2);
  f3(6);
}
複製程式碼

匿名函式

大多數函式都是有名稱的,比如main() printName()等,但是你也可以寫匿名函式,如果你對Java比較熟悉,那下面的Dart程式碼你肯定也不會陌生:

test(Function callback) {
  callback("hello");
}

main() {
  test((param) {
    // 列印hello
    print(param);
  });
}
複製程式碼

匿名函式類似於Java中的介面,往往在某個函式的引數為函式時使用到。

函式返回值

所有的函式都有返回值,如果沒有指定return語句,那麼該函式的返回值為null

運算子

Dart中的運算子與Java中的類似,比如++a a == b b ? a : b,但是也有一些與Java不太一樣的運算子,下面用程式碼說明:

main() {
  // 與Java相同的運算子操作

  int a = 1;
  ++a;
  a++;
  var b = 1;
  print(a == b);  // false
  print(a * b); // 3
  bool real = false;
  real ? print('real') : print('not real'); // not real
  print(real && a == b); // false
  print(real || a == 3); // true
  print(a != 2); // true
  print(a <= b); // false
  var c = 9;
  c += 10;
  print("c = $c"); // c = 19
  print(1<<2); // 4

  // 與Java不太一樣的運算子操作

  // is運算子用於判斷一個變數是不是某個型別的資料
  // is!則是判斷變數不是某個型別的資料
  var s = "hello";
  print(s is String); // true
  var num = 6;
  print(num is! String); // true

  // ~/才是取整運算子,如果使用/則是除法運算,不取整
  int k = 1;
  int j = 2;
  print(k / j); // 0.5
  print(k ~/ j); // 0

  // as運算子類似於Java中的cast操作,將一個物件強制型別轉換
  (emp as Person).teach();

  // ??=運算子 如果 ??= 運算子前面的變數為null,則賦值,否則不賦值
  var param1 = "hello", param2 = null;
  param1 ??= "world";
  param2 ??= "world";
  print("param1 = $param1"); // param1 = hello
  print("param2 = $param2"); // param2 = world
  
  // ?.運算子
  var str1 = "hello world";
  var str2 = null;
  print(str1?.length); // 11
  print(str2?.length); // null 
  print(str2.length); // 報錯
}
複製程式碼

..運算子(級聯操作)

如果你對Java中的建造者模式比較熟悉的話,Dart中的..運算子也很好理解,先看下面的程式碼:

class Person {
  eat() {
    print("I am eating...");
  }

  sleep() {
    print("I am sleeping...");
  }

  study() {
    print("I am studying...");
  }
}

main() {
  // 依次列印
  //  I am eating...
  //  I am sleeping...
  //  I am studying...
  new Person()..eat()
      ..sleep()
      ..study();
}
複製程式碼

可以看到,使用..呼叫某個物件的方法(或者成員變數)時,返回值是這個物件本身,所以你可以接著使用..呼叫這個物件的其他方法,這不就類似於Java中的建造者模式,每次build某個屬性時,都返回一個this物件嗎。

控制流程

if / else switch for /while try / catch語句跟Java中都類似,try / catch語句可能稍有不同,下面用一段程式碼說明:

main() {
  // if else語句
  int score = 80;
  if (score < 60) {
    print("so bad!");
  } else if (score >= 60 && score < 80) {
    print("just so so!");
  } else if (score >= 80) {
    print("good job!");
  }

  // switch語句
  String a = "hello";
  // case語句中的資料型別必須是跟switch中的型別一致
  switch (a) {
    case "hello":
      print("haha");
      break;
    case "world":
      print("heihei");
      break;
    default:
      print("WTF");
  }

  // for語句
  List<String> list = ["a", "b", "c"];
  for (int i = 0; i < list.length; i++) {
    print(list[i]);
  }
  for (var i in list) {
    print(i);
  }
  // 這裡的箭頭函式引數必須用圓括號擴起來
  list.forEach((item) => print(item));

  // while語句
  int start = 1;
  int sum = 0;
  while (start <= 100) {
    sum += start;
    start++;
  }
  print(sum);

  // try catch語句
  try {
    print(1 ~/ 0);
  } catch (e) {
    // IntegerDivisionByZeroException
    print(e);
  }
  try {
    1 ~/ 0;
  } on IntegerDivisionByZeroException { // 捕獲指定型別的異常
    print("error"); // 列印出error
  } finally {
    print("over"); // 列印出over
  }
}
複製程式碼

類(Class)

類的定義與構造方法

Dart中的類沒有訪問控制,所以你不需要用private, protected, public等修飾成員變數或成員函式,一個簡單的類如下程式碼所示:

class Person {
  String name;
  int age;
  String gender;
  Person(this.name, this.age, this.gender);
  sayHello() {
    print("hello, this is $name, I am $age years old, I am a $gender");
  }
}
複製程式碼

上面的Person類中有3個成員變數,一個構造方法和一個成員方法,看起來比較奇怪的是Person的構造方法,裡面傳入的3個引數都是this.xxx,而且沒有大括號{}包裹的方法體,這種語法是Dart比較獨特而簡潔的構造方法宣告方式,它等同於下面的程式碼:

Person(String name, int age, String gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
}
複製程式碼

要呼叫Person類的成員變數或成員方法,可以用下面的程式碼:

  var p = new Person("zhangsan", 20, "male");
  p.sayHello(); // hello, this is zhangsan, I am 20 years old, I am a male
  p.age = 50;
  p.gender = "female";
  p.sayHello(); // hello, this is zhangsan, I am 50 years old, I am a female
複製程式碼

由於Dart中的類沒有訪問控制許可權,所以你可以直接用obj.var的方式訪問一個物件的成員變數。

類除了有跟類名相同的構造方法外,還可以新增命名的構造方法,如下程式碼所示:

class Point {
  num x, y;
  Point(this.x, this.y);
  // 類的命名構造方法
  Point.origin() {
    x = 0;
    y = 0;
  }
}

main() {
  // 呼叫Point類的命名構造方法origin()
  var p = new Point.origin();
  var p2 = new Point(1, 2);
}
複製程式碼

Dart中使用extends關鍵字做類的繼承,如果一個類只有命名的構造方法,在繼承時需要注意,如下程式碼:

class Human {
  String name;
  Human.fromJson(Map data) {
    print("Human's fromJson constructor");
  }
}

class Man extends Human {
  Man.fromJson(Map data) : super.fromJson(data) {
    print("Man's fromJson constructor");
  }
}
複製程式碼

由於Human類沒有預設構造方法,只有一個命名構造方法fromJson,所以在Man類繼承Human類時,需要呼叫父類的fromJson方法做初始化,而且必須使用Man.fromJson(Map data) : super.fromJson(data)這種寫法,而不是像Java那樣將super寫到花括號中。

有時候你僅僅只是在某個類的構造方法中,呼叫這個類的另一個構造方法,你可以這麼寫:

class Point {
  num x, y;
  Point(this.x, this.y);
  // 命名構造方法呼叫了預設的構造方法
  Point.alongXAxis(num x) : this(x, 0);
}
複製程式碼

類的成員方法

一個類的成員方法是一個函式,為這個類提供某些行為。上面的程式碼中已經有了一些類的成員方法的定義,這些定義方式跟Java很類似,你可以為某個類的成員變數提供getter/setter方法,如下程式碼:

class Rectangle {
  num left, top, width, height;

  // 構造方法傳入left, top, width, height幾個引數
  Rectangle(this.left, this.top, this.width, this.height);

  // right, bottom兩個成員變數提供getter/setter方法
  num get right => left + width;
  set right(num value) => left = value - width;
  num get bottom => top + height;
  set bottom(num value) => top = value - height;
}
複製程式碼

抽象類和抽象方法

使用abstract修飾一個類,則這個類是抽象類,抽象類中可以有抽象方法和非抽象方法,抽象方法沒有方法體,需要子類去實現,如下程式碼:

abstract class Doer {
  // 抽象方法,沒有方法體,需要子類去實現
  void doSomething();
  // 普通的方法
  void greet() {
    print("hello world!");
  }
}

class EffectiveDoer extends Doer {
  // 實現了父類的抽象方法
  void doSomething() {
    print("I'm doing something...");
  }
}
複製程式碼

運算子過載

Dart中有類似於C++中的運算子過載語法,比如下面的程式碼定義了一個向量類,過載了向量的+ -運算:

class Vector {
  num x, y;
  Vector(this.x, this.y);
  Vector operator +(Vector v) => new Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => new Vector(x - v.x, y - v.y);
  printVec() {
    print("x: $x, y: $y");
  }
}

main() {
  Vector v1 = new Vector(1, 2);
  Vector v2 = new Vector(3, 4);
  (v1 - v2).printVec(); // -2, -2
  (v1 + v2).printVec(); // 4, 6
}
複製程式碼

列舉類

使用enum關鍵字定義一個列舉類,這個語法跟Java類似,如下程式碼:

enum Color { red, green, blue }
複製程式碼

mixins

mixins是一個重複使用類中程式碼的方式,比如下面的程式碼:

class A {
  a() {
    print("A's a()");
  }
}

class B {
  b() {
    print("B's b()");
  }
}

// 使用with關鍵字,表示類C是由類A和類B混合而構成
class C = A with B;

main() {
  C c = new C();
  c.a(); // A's a()
  c.b(); // B's b()
}
複製程式碼

靜態成員變數和靜態成員方法

// 類的靜態成員變數和靜態成員方法
class Cons {
  static const name = "zhangsan";
  static sayHello() {
    print("hello, this is ${Cons.name}");
  }
}

main() {
  Cons.sayHello(); // hello, this is zhangsan
  print(Cons.name); // zhangsan
}
複製程式碼

泛型(Generics)

JavaC++語言都有泛型,Dart語言也不例外,使用泛型有很多好處,比如:

  • 正確指定泛型型別會產生更好的生成程式碼。
  • 泛型可以減小程式碼的複雜度

Dart內建的資料型別List就是一個泛型資料型別,你可以往List中塞任何你想的資料型別比如整型、字串、布林值等

關於Dart更多的泛型知識點,可以檢視這裡

Dart庫(Libraries)

Dart目前已經有很多的庫提供給開發者,許多功能不需要開發者自己去實現,只需要匯入對應的包即可,使用import語句來匯入某個包,比如下面的程式碼:

import 'dart:html';
複製程式碼

如果你想匯入自己寫的某個程式碼檔案,使用相對路徑即可,例如當前有一個demo.dart檔案,跟該檔案同級目錄下有個util.dart檔案,檔案程式碼如下:

// util.dart檔案內容

int add(int a, int b) {
  return a + b;
}
複製程式碼

demo.dart檔案中如果要引用util.dart檔案,使用下面的方式匯入:

// demo.dart

import './util.dart';

main() {
  print(add(1, 2));
}
複製程式碼

你可以使用as關鍵字為匯入的某個包設定一個字首,或者說別名,比如下面的程式碼:

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

// Uses Element from lib1.
Element element1 = Element();

// Uses Element from lib2.
lib2.Element element2 = lib2.Element();
複製程式碼

你也可以在匯入包時使用show hide關鍵字來匯入某個包中的部分功能,比如下面的程式碼:

// 只匯入foo
import 'package:lib1/lib1.dart' show foo;

// 匯入除了foo的所有其他部分
import 'package:lib2/lib2.dart' hide foo;
複製程式碼

匯入包時使用deferred as可以讓這個包懶載入,懶載入的包只會在該包被使用時得到載入,而不是一開始就載入,比如下面的程式碼:

import 'package:greetings/hello.dart' deferred as hello;
複製程式碼

非同步

Dart提供了類似ES7中的async await等非同步操作,這種非同步操作在Flutter開發中會經常遇到,比如網路或其他IO操作,檔案選擇等都需要用到非同步的知識。 asyncawait往往是成對出現的,如果一個方法中有耗時的操作,你需要將這個方法設定成async,並給其中的耗時操作加上await關鍵字,如果這個方法有返回值,你需要將返回值塞到Future中並返回,如下程式碼所示:

Future checkVersion() async {
  var version = await lookUpVersion();
  // Do something with version
}
複製程式碼

下面的程式碼使用Dart從網路獲取資料並列印出來:

import 'dart:async';
import 'package:http/http.dart' as http;

Future<String> getNetData() async{
  http.Response res = await http.get("http://www.baidu.com");
  return res.body;
}

main() {
  getNetData().then((str) {
    print(str);
  });
}
複製程式碼

關於Dart非同步操作,可以檢視這篇文章瞭解更多。

結束語

本篇部落格較長,主要是對官方文件的一個翻譯(大部分),如果你對英文閱讀沒有太大障礙,建議直接檢視官方的英文文件,希望各位都能愉快的學習DartFlutter

參考

我的開源專案

  1. 基於Google Flutter的開源中國客戶端,希望大家給個Star支援一下,原始碼:
從0開始寫一個基於Flutter的開源中國客戶端(2)——Dart語法基礎 從0開始寫一個基於Flutter的開源中國客戶端(2)——Dart語法基礎
  1. 基於Flutter的俄羅斯方塊小遊戲,希望大家給個Star支援一下,原始碼:
從0開始寫一個基於Flutter的開源中國客戶端(2)——Dart語法基礎 從0開始寫一個基於Flutter的開源中國客戶端(2)——Dart語法基礎
上一篇 下一篇
從0開始寫一個基於Flutter的開源中國客戶端(1)
——Flutter簡介及開發環境搭建
從0開始寫一個基於Flutter的開源中國客戶端(3)
——初識Flutter & 常用的Widgets

相關文章