Flutter學習記錄(一)Dart學習

蟹蟹本尊 發表於 2019-11-28

程式碼規範

順序

為了使檔案前面部分保持整潔,我們規定了關鍵字出現順序的規則。每個“部分”應該使用空行分割。

要把 “dart:” 匯入語句放到其他匯入語句之前。

要把 “package:” 匯入語句放到專案相關匯入語句之前。

import 'dart:async';
import 'dart:html';

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

import 'util.dart';
複製程式碼

推薦 把外部擴充套件 “package:” 匯入語句放到其他語句之前。

如果你使用了多個 “package:” 匯入語句來匯入自己的包以及其他外部擴充套件包,推薦將自己的包分開放到一個額外的部分。

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

import 'package:my_package/util.dart';
複製程式碼

要 把匯出(export)語句作為一個單獨的部分放到所有匯入語句之後。

import 'src/error.dart';
import 'src/foo_bar.dart';

export 'src/error.dart';
複製程式碼

變數

在 Dart 中,未初始化的變數擁有一個預設的初始化值:null。即便數字也是如此,因為在 Dart 中一切皆為物件,數字也不例外。

int lineCount;
assert(lineCount == null);
複製程式碼

var

在Dart中用var宣告一個變數後,Dart在編譯時會根據第一次賦值資料的型別來推斷其型別,編譯結束後其型別就已經被確定。

dynamic和Object

Object 是Dart所有物件的根基類,也就是說所有型別都是Object的子類(包括Function和Null),所以任何型別的資料都可以賦值給Object宣告的物件. dynamic與var一樣都是關鍵詞,宣告的變數可以賦值任意物件。 而dynamic與Object相同之處在於,他們宣告的變數可以在後期改變賦值型別。

dynamic t;
 Object x;
 t = "hi world";
 x = 'Hello Object';
 //下面程式碼沒有問題
 t = 1000;
 x = 1000;
複製程式碼

dynamic與Object不同的是,dynamic宣告的物件編譯器會提供所有可能的組合, 而Object宣告的物件只能使用Object的屬性與方法, 否則編譯器會報錯。

dynamic的這個特性與Objective-C中的id作用很像. dynamic的這個特點使得我們在使用它時需要格外注意,這很容易引入一個執行時錯誤.

final和const

如果您從未打算更改一個變數,那麼使用 final 或 const,不是var,也不是一個型別。 一個 final 變數只能被設定一次,兩者區別在於:const 變數是一個編譯時常量,final變數在第一次使用時被初始化。被final或者const修飾的變數,變數型別可以省略,如:

//可以省略String這個型別宣告
final str = "hi world";
//final String str = "hi world"; 
const str1 = "hi world";
//const String str1 = "hi world";
複製程式碼

函式

Dart是一種真正的物件導向的語言,所以即使是函式也是物件,並且有一個型別Function。這意味著函式可以賦值給變數或作為引數傳遞給其他函式,這是函數語言程式設計的典型特徵。

Dart函式宣告如果沒有顯式宣告返回值型別時會預設當做dynamic處理,注意,函式返回值沒有型別推斷。

bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}
typedef bool CALLBACK();

//不指定返回型別,此時預設為dynamic,不是bool
isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}
void test(CALLBACK cb){
   print(cb()); 
}
//報錯,isNoble不是bool型別
test(isNoble);
複製程式碼

級聯運算子(..)

級聯運算子(..)可以讓你在同一個物件上連續呼叫多個物件的變數或方法。

比如下面的程式碼:

querySelector('#confirm') // 獲取物件 (Get an object).
  ..text = 'Confirm' // 使用物件的成員 (Use its members).
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));
複製程式碼

第一個方法 querySelector 返回了一個 Selector 物件,後面的級聯操作符都是呼叫這個 Selector 物件的成員並忽略每個操作的返回值。

上面的程式碼相當於:

var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.lis
複製程式碼

ten((e) => window.alert('Confirmed!')); 級聯運算子可以巢狀,例如:

final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = '[email protected]'
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();
複製程式碼

使用類的成員 物件的 成員 由函式和資料(即 方法 和 例項變數)組成。方法的 呼叫 要通過物件來完成,這種方式可以訪問物件的函式和資料。

使用(.)來訪問物件的例項變數或方法:

var p = Point(2, 2);
// 為例項變數 y 賦值。
p.y = 3;
// 獲取 y 的值。
assert(p.y == 3);
// 呼叫變數 p 的 distanceTo() 方法。
num distance = p.distanceTo(Point(4, 4));
複製程式碼

使用 ?. 代替 . 可以避免因為左邊表示式為 null 而導致的問題:

// If p is non-null, set its y value to 4.
// 如果 p 為非空則將其屬性 y 的值設為 4
p?.y = 4;
複製程式碼

使用建構函式 可以使用 建構函式 來建立一個物件。建構函式的命名方式可以為 類名 或 類名.識別符號 的形式。例如下述程式碼分別使用 Point() 和 Point.fromJson() 兩種構造器建立了 Point 物件:

var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
複製程式碼

以下程式碼具有相同的效果,但是建構函式名前面的的 new 關鍵字是可選的:

var p1 = new Point(2, 2);
var p2 = new Point.fromJson({'x': 1, 'y': 2});
複製程式碼
從 Dart 2 開始,new 關鍵字是可選的。
複製程式碼

獲取物件的型別 可以使用 Object 物件的 runtimeType 屬性在執行時獲取一個物件的型別,該物件型別是 Type 的例項。

print('The type of a is ${a.runtimeType}');
複製程式碼