Dart 語法

重要的概念

  • 任何保存在變量中的都是一個 對象 , 并且所有的對象都是對應一個 的實例。 無論是數(shù)字,函數(shù)和 null 都是對象。所有對象繼承自 Object 類。

  • 盡管 Dart 是強類型的,但是 Dart 可以推斷類型,所以類型注釋是可選的。var number = 42;, number 被推斷為 int 類型。 如果要明確說明不需要任何類型, 需要使用特殊類型 dynamic。

  • Dart 支持泛型,如 List <int> (整數(shù)列表)或 List <dynamic> (任何類型的對象列表)。

  • Dart 支持頂級函數(shù)(例如 main() ), 同樣函數(shù)綁定在類或?qū)ο笊希ǚ謩e是 靜態(tài)函數(shù)實例函數(shù) )。 以及支持函數(shù)內(nèi)創(chuàng)建函數(shù) ( 嵌套局部函數(shù) ) 。

  • 類似地, Dart 支持頂級 變量 , 同樣變量綁定在類或?qū)ο笊希o態(tài)變量和實例變量)。 實例變量有時稱為字段或?qū)傩浴?/p>

  • 與 Java 不同,Dart 沒有關(guān)鍵字 “public” , “protected” 和 “private” 。 如果標識符以下劃線(_)開頭,則它相對于庫是私有的(私有方法必須要抽離在單獨文件中,否則不生效。)。 有關(guān)更多信息,參考 庫和可見性。

  • 標識符 以字母或下劃線(_)開頭,后跟任意字母和數(shù)字組合。

  • Dart 語法中包含 表達式( expressions )(有運行時值)和 語句( statements )(沒有運行時值)。 例如,條件表達式 condition ? expr1 : expr2 的值可能是 expr1expr2 。 將其與 if-else 語句 相比較,if-else 語句沒有值。 一條語句通常包含一個或多個表達式,相反表達式不能直接包含語句。

  • Dart 工具提示兩種類型問題:警告錯誤。 警告只是表明代碼可能無法正常工作,但不會阻止程序的執(zhí)行。 錯誤可能是編譯時錯誤或者運行時錯誤。 編譯時錯誤會阻止代碼的執(zhí)行; 運行時錯誤會導致代碼在執(zhí)行過程中引發(fā) [異常](#exception)。

語法

變量與常量

1. 變量初始化
// 沒有明確類型,編譯的時候根據(jù)值明確類型
var name = 'Bob';
dynamic name = 'Bob';
Object name = 'Bob'

// 顯示聲明將被推斷類型, 可以使用String顯示聲明字符串類型
String name = 'Bob' ;
2. 默認值

未初始化的變量默認值是 null。即使變量是數(shù)字 類型默認值也是 null,因為在 Dart 中一切都是對象,數(shù)字類型 也不例外。

3. Object 和 dynamic
  dynamic a = 'string';
  a = 10;
  a = 1.1;
  a.foo();

  Object b = 'string';
  b = 10;
  b = 1.1;
  // 編譯錯誤 "The method 'foo' isn't defined for the type 'Object'."
  // b.foo();

  1. dynamic和object類型是可以變的
  2. Object 是靜態(tài)類型檢測的,所以Object 對象只能調(diào)用Object 的方法,調(diào)用其他方法會產(chǎn)生編譯錯誤
  3. dynamic是運行時檢測的,所以可以調(diào)用任何方法,(注意會產(chǎn)生運行時錯誤,盡量避免使用)
4. Final 和 Const
  1. 使用過程中從來不會被修改的變量, 可以使用 final 或 const
  2. 實例變量可以是 final 類型但不能是 const 類型。 必須在構(gòu)造函數(shù)體執(zhí)行之前初始化 final 實例變量
  3. Final 變量的值只能被設置一次, 最高級 final 變量或類變量在第一次使用時被初始化(運行時)
class Name {
  // 1. 直接設置默認值
  final a = 10;
  
  // 2. 在初始化列表中初始化
  final a;
  Name(this.a)
}
  1. Const 變量在編譯時就已經(jīng)固定 (Const 變量 是隱式 Final 的類型.)
  2. Const 變量必須由常量初始化
  var a = 10;
  const b = 10;

  // 編譯報錯 "Const variables must be initialized with a constant value."
  const c = a;

  const d = b;
  1. 在集合字面量之前添加 const 關(guān)鍵字,可以定義編譯時常量
  var a = const [1, 2, 3];
  var b = const {1, 2, 3};
  var c = const {1: 1, 2: 2};

內(nèi)建類型

  • Dart 語言支持以下內(nèi)建類型:
  • Number
  • String
  • Boolean
  • List (也被稱為 Array)
  • Map
  • Set
  • Rune (用于在字符串中表示 Unicode 字符)
  • Symbol
1. Number
  1. Dart 語言的 Number 有兩種類型: int double
  2. int 整數(shù)值不大于64位, 具體取決于平臺
  3. double 64位(雙精度)浮點數(shù)
2. String
  1. Dart 字符串是一組 UTF-16 單元序列。 字符串通過單引號或者雙引號創(chuàng)建。
  2. 字符串可以通過 ${expression} 的方式內(nèi)嵌表達式。 如果表達式是一個標識符,則 {} 可以省略。
  3. Flutter中字符串格式化只有插值,可以借助第三方庫sprintf來實現(xiàn)格式化字符串
3. Boolean
  1. Dart 使用 bool 類型表示布爾值。 Dart 只有字面量 true and false 是布爾類型, 這兩個對象都是編譯時常量。
  2. Dart 的類型安全意味著不能使用 if (nonbooleanValue) 或者 assert (nonbooleanValue)。
3. Set
  var names = Set();
  var names = Set<String>();
  var names = <String>{};
  // var names = {}; // 這樣會創(chuàng)建一個 Map ,而不是 Set 。  

函數(shù)

函數(shù)也是對象,并且有它的類型 Function。這也意味著函數(shù)可以被賦值給變量或者作為參數(shù)傳遞給其他函數(shù)。 也可以把 Dart 類的實例當做方法來調(diào)用。

  1. 如果函數(shù)中只有一句表達式,可以使用簡寫語法:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
  1. 在箭頭 (=>) 和分號 (;) 之間只能使用一個 表達式 ,不能是 語句。
  2. 函數(shù)有兩種參數(shù)類型: required 和 optional。 required 類型參數(shù)在參數(shù)最前面, 隨后是 optional 類型參數(shù)。 命名的可選參數(shù)也可以標記為 “@ required”
  3. 所有函數(shù)都有返回值,沒有明確指定返回值,函數(shù)隱式添加return null;
1. 命名可選參數(shù)
  1. 定義函數(shù)是,使用 {param1, param2, …} 來指定命名參數(shù)
void enableFlags({bool bold, bool hidden}) {...}
  1. 調(diào)用函數(shù)時,可以使用指定命名參數(shù) paramName: value,
enableFlags(bold: true, hidden: false);
2. 位置可選參數(shù)
  1. 定義函數(shù)是,使用 [param1, param2, …] 來指定位置可選參數(shù)
void enableFlags([bool bold, bool hidden]) {...}
  1. 調(diào)用函數(shù), 自動按順序?qū)?shù)據(jù)賦值給位置參數(shù)
enableFlags(true, true);
3. 默認參數(shù)值

在定義方法的時候,可以使用 = 來定義可選參數(shù)的默認值。 默認值只能是編譯時常量。 如果沒有提供默認值,則默認值為 null。

  1. 可選參數(shù)才能設置默認值
// 位置可選
void enableFlags([bool bold = false, bool hidden = false]) { ... }
// 命名可選
void enableFlags({bool bold = false, bool hidden = false}) { ... }
  1. 位置可選參數(shù)和命名可選參數(shù)不能混用。
4. 匿名函數(shù)(block)
// 1
var testFunc = (String a) { ... };
// 2
Function(String a) testFunc;
testFunc = (String a) { ... };
// 3 
bool Function(String a) testFunc;
testFunc = (String a) { ... };
// 4 
typedef MyFunc = bool Function(String a);
MyFunc testFunc;

運算符

  1. 級聯(lián)運算符 (..) 可以實現(xiàn)對同一個對像進行一系列的操作。 除了調(diào)用函數(shù), 還可以訪問同一對象上的字段屬性。 這通常可以節(jié)省創(chuàng)建臨時變量的步驟, 同時編寫出更流暢的代碼。
querySelector('#confirm') // 獲取對象。
  ..text = 'Confirm' // 調(diào)用成員變量。
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));
  1. switch 和 case
    在非空 case必須加break、continue、thow或return
    空case允許程序以 fall-through 的形式執(zhí)行
    非空case 實現(xiàn) fall-through 需要使用 continue 語句結(jié)合 lable 的方式實現(xiàn):
var command = 'CLOSED';
switch (command) {
  case 'CLOSED':
    executeClosed();
    continue nowClosed;
  // Continues executing at the nowClosed label.

  nowClosed:
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeNowClosed();
    break;
}

異常

  1. Dart 中的所有異常是非檢查異常。 方法不會聲明它們拋出的異常, 也不要求捕獲任何異常。
  2. Dart 提供了 ExceptionError 類型, 以及一些子類型。 當然也可以定義自己的異常類型。 但是,此外 Dart 程序可以拋出任何非 null 對象, 不僅限 Exception 和 Error 對象。
// 拋出異常
throw FormatException('Expected at least 1 section');
throw 'Out of llamas!';

捕獲
try {
  // ···
} on Exception catch (e) {
  print('Exception details:\n $e');
} catch (e, s) {
  print('Exception details:\n $e');
  print('Stack trace:\n $s');
} finally {
  // Always clean up, even if an exception is thrown.
  cleanLlamaStalls();
}
  1. 捕獲語句中可以同時使用 on 和 catch ,也可以單獨分開使用。 使用 on 來指定異常類型, 使用 catch 來 捕獲異常對象。
  2. catch() 函數(shù)可以指定1到2個參數(shù), 第一個參數(shù)為拋出的異常對象, 第二個為堆棧信息 ( 一個 StackTrace 對象 )。

1. 構(gòu)造函數(shù)
  1. 通過 構(gòu)造函數(shù) 創(chuàng)建對象。 構(gòu)造函數(shù)的名字可以是 ClassName 或者 ClassName.identifier。
class Point {
  final x;
  final y;
  Point(this.x, this.y);
  Point.fromJson(this.x, this.y);
}

var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
  1. 構(gòu)造函數(shù)實例變量賦值簡寫
class Point {
  num x, y;
// 1 手動初始化屬性
  Point(num x, num y) {
    // 還有更好的方式來實現(xiàn)下面代碼,敬請關(guān)注。
    this.x = x;
    this.y = y;
  }
// 2 自動初始化屬性
  Point(this.x, this.y)
// 3. 初始化列表
  Point(int x, int y) : this.x = x, this.y = y;
}

  1. 在沒有聲明構(gòu)造函數(shù)的情況下, Dart 會提供一個默認的構(gòu)造函數(shù)。 默認構(gòu)造函數(shù)沒有參數(shù)并會調(diào)用父類的無參構(gòu)造函數(shù)。
  2. 子類不會繼承父類的構(gòu)造函數(shù)。 子類不聲明構(gòu)造函數(shù),那么它就只有默認構(gòu)造函數(shù) (匿名,沒有參數(shù)) 。
  3. 使用命名構(gòu)造函數(shù)可為一個類實現(xiàn)多個構(gòu)造函數(shù), 也可以使用命名構(gòu)造函數(shù)來更清晰的表明函數(shù)意圖
  4. 常量構(gòu)造函數(shù)
  const Point.ImmutablePoint(this.x, this.y);

  var a = const Point.ImmutablePoint(10, 11);
  var b = const Point.ImmutablePoint(10, 11);
  print(identical(a, b));  // true

包含常量構(gòu)造函數(shù)的類中只能包含final屬性
在常量構(gòu)造函數(shù)前加const 會創(chuàng)建出唯一編譯時常量

  1. 工廠構(gòu)造函數(shù)(可以手動返回一個對象
    當執(zhí)行構(gòu)造函數(shù)并不總是創(chuàng)建這個類的一個新實例時,則使用 factory 關(guān)鍵字。 例如,一個工廠構(gòu)造函數(shù)可能會返回一個 cache 中的實例, 或者可能返回一個子類的實例。
    以下示例演示了從緩存中返回對象的工廠構(gòu)造函數(shù)(工廠構(gòu)造函數(shù)無法訪問 this。):
class Logger {
  final String name;
  bool mute = false;

  // 從命名的 _ 可以知,
  // _cache 是私有屬性。
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
    } else {
      final logger = Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}

使用工廠方法實現(xiàn)單例

  Singleton._privateConstructor();

  static final Singleton _instance = Singleton._privateConstructor();

  factory Singleton(){
    return _instance;
  }

工廠方法 只是為了手動返回一個實例, 下面兩種實現(xiàn)等價。

// 工廠方法 只是為了手動返回一個實例
class Test {
  Test._internal();

  static final Test _instance = Test._internal();

  // 1.
  static Test init1() {
    return _instance;
  }

  // 2.
  factory Test.init2() {
    return _instance;
  }
}
2. 調(diào)用父類非默認構(gòu)造函數(shù)

默認情況下,子類的構(gòu)造函數(shù)會自動調(diào)用父類的默認構(gòu)造函數(shù)(匿名,無參數(shù))。 父類的構(gòu)造函數(shù)在子類構(gòu)造函數(shù)體開始執(zhí)行的位置被調(diào)用。 如果提供了一個 initializer list (初始化參數(shù)列表), 則初始化參數(shù)列表在父類構(gòu)造函數(shù)執(zhí)行之前執(zhí)行。 總之,執(zhí)行順序如下(類似于Swift 的兩段式初始化):

  • initializer list (初始化參數(shù)列表)
  • superclass’s no-arg constructor (父類的無名構(gòu)造函數(shù))
  • main class’s no-arg constructor (主類的無名構(gòu)造函數(shù))

如果父類中沒有匿名無參的構(gòu)造函數(shù), 則需要手工調(diào)用父類的其他構(gòu)造函數(shù)。 在當前構(gòu)造函數(shù)冒號 (:) 之后,函數(shù)體之前,聲明調(diào)用父類構(gòu)造函數(shù)。

class Person {
  String firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person does not have a default constructor;
  // you must call super.fromJson(data).
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}
3. 實例變量
class Point {
  num x; // 聲明示例變量 x,初始值為 null 。
  num y; // 聲明示例變量 y,初始值為 null 。
  num z = 0; // 聲明示例變量 z,初始值為 0 。
}
  1. 未初始化實例變量的默認人值為 “null” 。
  2. 所有實例變量都生成隱式 getter 方法。 非 final 的實例變量同樣會生成隱式 setter 方法。 有關(guān)更多信息,參考 Getters 和 setters.
  3. 如果在聲明時進行了實例變量的初始化, 那么初始化值會在實例創(chuàng)建時賦值給變量, 該賦值過程在構(gòu)造函數(shù)及其初始化列表執(zhí)行之前。
4. Getter 和 Setter
class Rectangle {
  num left, top, width, height;

  Rectangle(this.left, this.top, this.width, this.height);

  // 定義兩個計算屬性: right 和 bottom。
  num get right => left + width;
  set right(num value) => left = value - width;
  num get bottom => top + height;
  set bottom(num value) => top = value - height;
}
5. 抽象類
abstract class Doer {
  // 定義實例變量和方法 ...

  void doSomething(); // 定義一個抽象方法。
}
  1. 抽象類不能實例化
  2. 抽象類中包含抽象方法,普通方法。抽象方法必須被重寫
6. 隱式接口

在Dart 中沒有interface。每個Class都是一個隱式接口。
使用implements 實現(xiàn)接口

// person 類。 隱式接口里面包含了 greet() 方法聲明。
class Person {
  // 包含在接口里,但只在當前庫中可見。
  final _name;

  // 不包含在接口里,因為這是一個構(gòu)造函數(shù)。
  Person(this._name);

  // 包含在接口里。
  String greet(String who) => 'Hello, $who. I am $_name.';
}

// person 接口的實現(xiàn)。
class Impostor implements Person {
  get _name => '';

  String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));
}

實現(xiàn)多個接口

class  Point  implements  Comparable,  Location  {...}
7. 繼承
  1. Dart 是單繼承。使用 extends 關(guān)鍵字來創(chuàng)建子類, 使用 super 關(guān)鍵字來引用父類:
class Television {
  void turnOn() {
    _illuminateDisplay();
    _activateIrSensor();
  }
  // ···
}

class SmartTelevision extends Television {
  void turnOn() {
    super.turnOn();
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
  }
  // ···
}
  1. 子類可以重寫實例方法,getter 和 setter。 可以使用 @override 注解指出想要重寫的成員:
class SmartTelevision extends Television {
  @override
  void turnOn() {...}
  // ···
}
8. 為類添加功能: Mixin

Mixin 是復用類代碼的一種途徑, 復用的類可以在不同層級,之間可以不存在繼承關(guān)系。

  1. 通過 with 后面跟一個或多個混入的名稱,來 使用 Mixin , 下面的示例演示了兩個使用 Mixin 的類:
class Maestro extends Person
    with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}
  1. 通過創(chuàng)建一個繼承自 Object 且沒有構(gòu)造函數(shù)的類,來 實現(xiàn) 一個 Mixin 。 如果 Mixin 不希望作為常規(guī)類被使用,使用關(guān)鍵字 mixin 替換 class 。 例如:
mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}
  1. 指定只有某些類型可以使用的 Mixin - 比如, Mixin 可以調(diào)用 Mixin 自身沒有定義的方法 - 使用 on 來指定可以使用 Mixin 的父類類型:
mixin MusicalPerformer on Musician {
  // ···
}
9. noSuchMethod()

當代碼嘗試使用不存在的方法或?qū)嵗兞繒r, 通過重寫 noSuchMethod() 方法,來實現(xiàn)檢測和應對處理:

class A {
  // 如果不重寫 noSuchMethod,訪問
  // 不存在的實例變量時會導致 NoSuchMethodError 錯誤。
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ' +
        '${invocation.memberName}');
  }
}

除非符合下面的任意一項條件, 否則沒有實現(xiàn)的方法不能夠被調(diào)用:

  • receiver 具有 dynamic 的靜態(tài)類型 。
  • receiver 具有靜態(tài)類型,用于定義為實現(xiàn)的方法 (可以是抽象的), 并且 receiver 的動態(tài)類型具有 noSuchMethod() 的實現(xiàn), 該實現(xiàn)與 Object 類中的實現(xiàn)不同。

枚舉

枚舉中的每個值都有一個 index getter 方法, 該方法返回值所在枚舉類型定義中的位置(從 0 開始)。 例如,第一個枚舉值的索引是 0 , 第二個枚舉值的索引是 1。

枚舉類型具有以下限制:

  • 枚舉不能被子類化,混合或?qū)崿F(xiàn)。
  • 枚舉不能被顯式實例化。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容