Dart構造函數介紹

介紹

由於Flutter和Dart語言很是容易上手,不少學習Flutter的同窗,通常都會直接寫Flutter頁面,對Dart語言也是隻知其一;不知其二,包括我本身。json

Dart語言和不少現代語言都很相似,可是其構造函數,其靈活性,仍是比我瞭解的其它語言要多的,因此在寫構造函數的時候,要麼莫名其妙報錯,要麼寫的很複雜,沒有將其精髓掌握。緩存

下面跟你們總結一下Dart構造函數的語法,方便你們查閱bash

語法介紹

格式

Dart構造函數有4種格式:ide

  • ClassName(...) //普通構造函數
  • Classname.identifier(...) //命名構造函數
  • const ClassName(...) //常量構造函數
  • factroy ClassName(...) //工廠構造函數

使用

在定義本身的構造函數以前,咱們會接觸到構造函數的使用,其用法以下:函數

var p1 = Point(2, 2); //Dart2中,能夠省略構造函數前的new
var p2 = Point.fromJson({'x': 1, 'y': 2});
var p = const ImmutablePoint(2, 2); //常量構造函數,用來建立編譯期常量
複製代碼

插播廣告
若是想知道某個變量屬於哪一個類,可使用runtimeType:
print('The type of a is ${a.runtimeType}');學習

定義

1. 默認構造函數

若是你定義了一個類,而沒有定義構造函數,那麼它將有一個默認的構造函數,這個構造函數 沒有參數ui

若是這個類有父類,那麼默認構造函數,還會調用父類的無參數構造函數。this

2. 普通構造函數

這就是咱們普通的構造函數,其樣子和其它語言幾乎同樣spa

class Point {
  num x, y;

  Point(num x, num y) {
    // There's a better way to do this, stay tuned. this.x = x; this.y = y; } } 複製代碼

上例中只有兩個成員變量,若是有10個,豈不是麻煩死?因此Dart有語法糖給你哦:debug

class Point {
  num x, y;

  // Syntactic sugar for setting x and y
  // before the constructor body runs.
  Point(this.x, this.y);
}
複製代碼

它能夠將x,y的賦值變得簡單一些,就不用寫構造函數的方法體了,記得括號後用分號哦。

3. 命名構造函數

class Point {
  num x, y;

  Point(this.x, this.y);

  // 命名構造函數,新增代碼
  Point.origin() {
    x = 0;
    y = 0;
  }
}

複製代碼

請記住,命名構造函數不可繼承,若是子類想要有 和父類同樣的命名構造函數,那就寫個同名的(一般也會在子類的命名構造函數裏,調用父類的同名命名構造函數)

4. 構造函數調用父類構造函數的順序

若是你的類,繼承於父類,那麼子類的構造函數,勢必要調用父類的構造函數,這時候就要分兩種狀況:

  • Dart語言幫你調用父類的無參數構造函數
  • 代碼中顯式調用父類的構造函數
4.1 默認調用調用父類的無參數構造函數

若是你沒有顯式調用父類的構造函數,而且父類有一個無參數構造函數,那麼Dart就會幫你在子類的構造函數方法體的最前面,調用父類的無參數構造函數。固然,後面咱們會說道,構造函數分紅好幾部分來初始化成員變量,調用的順序以下:

  • 初始化列表
  • 父類的無參數構造函數
  • 子類的無參數構造函數

固然,若是父類沒有無參數構造函數,或者Dart這種隱式調用沒法知足你的要求,那就須要顯式調用父類的構造函數了

4.2 顯式調用父類構造函數

顯式調用父類構造函數,應該在初始化列表中完成(記得好像在C++中見到過初始化列表?過久了忘記了)

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');
  }
}

main() {
  var emp = new Employee.fromJson({});

  // Prints:
  // in Person
  // in Employee
}
複製代碼

初始化列表就是構造函數名的冒號後面,打括號前面的部分。

5. 初始化列表

初始化列表的執行順序,在整個構造函數的最前面,它除了能夠調用父類的構造函數,還能夠在構造函數方法體以前,初始化一些成員變量。

// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map<String, num> json)
    : x = json['x'],
      y = json['y'] {
  print('In Point.fromJson(): ($x, $y)');
}
複製代碼

尤爲是初始化那些final修飾的成員變量時,初始化列表頗有用,由於在方法體中,不能給final修飾的成員變量賦值,由於在執行方法體的時候,final修飾的成員變量已經不能變了。這個地方不少人犯錯。

import 'dart:math';

class Point {
  final num x;
  final num y;
  final num distanceFromOrigin;

  Point(x, y)
      : x = x,
        y = y,
        distanceFromOrigin = sqrt(x * x + y * y);
}

main() {
  var p = new Point(2, 3);
  print(p.distanceFromOrigin);
}
複製代碼

6. 構造函數傳遞

定義構造函數的時候,除了一個普通構造函數,還能夠有若干命名構造函數,這些構造函數之間,有時候會有一些相同的邏輯,若是分別書寫在各個構造函數中,會有些多餘,因此構造函數能夠傳遞。

class Point {
  num x, y;

  // The main constructor for this class.
  Point(this.x, this.y);

  // Delegates to the main constructor.
  Point.alongXAxis(num x) : this(x, 0);
}
複製代碼

傳遞構造函數,沒有方法體,會在初始化列表中,調用另外一個構造函數。

7. 常量構造函數

class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);

  final num x, y;

  const ImmutablePoint(this.x, this.y);
}
複製代碼

若是你的類,建立的對象永遠不會改變,你能夠在編譯期就建立這個常量實例,而且定義一個常量構造函數,而且確保全部的成員變量都是final的。

8. 工廠構造函數

有時候可能有一種需求,並不須要每次都建立新的類實例,而是每一種狀況,只須要一個實例:

class Logger {
  final String name;
  bool mute = false;

  // _cache is library-private, thanks to
  // the _ in front of its name.
  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);
  }
}

main() {
    var logger = Logger('UI');
    logger.log('Button clicked');
}
複製代碼

工廠構造函數,沒有權利訪問this

上例的意思是,類中又一個靜態緩存_cache保存着一些Logger類實例,建立實例時,給工廠構造函數傳遞的name,若是在緩存中已經存在,就用緩存中現成的實例,若是沒有,就新建一個實例,而且也放到緩存中。

如此這般,咱們能夠建立名字爲UI / SYS / API 等的實例,而後在debug的時候,若是設置名字爲UI的Logger實例的mute爲true,就不會打印UI相關的log,而不影響其它兩個名字的log。是否是很方便呢?

相關文章
相關標籤/搜索