【dart 學習】 構造函數


dart 構造函數

ClassName(...) //普通構造函數

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

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有語法糖給你哦:

class Point {
  num x, y;

  // Syntactic sugar for setting x and y
  // before the constructor body runs.
  Point(this.x, this.y);
}
它可以將x,y的賦值變得簡單一些,就不用寫構造函數的方法體了,記得括號后用分號哦。


Classname.identifier(...) //命名構造函數

 命名構造函數

class Point {
  num x, y;

  Point(this.x, this.y);

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

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


const ClassName(...) //常量構造函數

常量構造函數總結如下幾點:

常量構造函數需以const關鍵字修飾
const構造函數必須用於成員變量都是final的類
構建常量實例必須使用定義的常量構造函數
如果實例化時不加const修飾符,即使調用的是常量構造函數,實例化的對象也不是常量實例
下面結合實例,對以上幾點加以說明

 

正確的常量構造函數定義
根據以上的總結,定義一個Point類,包含一個常量構造函數,注意其成員變量都是final類型,且構造函數用const修飾

class Point {
  final int x;
  final int y;
  const Point(this.x, this.y);
}
常量構造函數需以const關鍵字修飾
如下代碼定義一個const對象,但是調用的構造方法不是const修飾的,則會報The constructor being called isn't a const constructor.錯誤

void main() {
  const point = Point(1, 2); // 報錯
}
 
class Point {
  final int x;
  final int y;
  Point(this.x, this.y);
}
const構造函數必須用於成員變量都是final的類
如下代碼中成員變量x為非final,會報Can't define a const constructor for a class with non-final fields.錯誤

class Point {
  int x;
  final int y;
  const Point(this.x, this.y);
}
 

構建常量實例必須使用定義的常量構造函數
如下代碼,定義一個const對象,但是調用的卻是非常量構造函數,會報The constructor being called isn't a const constructor.錯誤

void main() {
  var point = const Point(1, 2); // 報錯
  print(point.toString());
}
 
class Point {
  int x;
  int y;
  Point(this.x, this.y); // 非const構造函數
  
  String toString() {
    return 'Point(${x}, ${y})';
  }
}
 

如果實例化時不加const修飾符,即使調用的是常量構造函數,實例化的對象也不是常量實例
如下代碼,用常量構造函數構造一個對象,但是未用const修飾,那么該對象就不是const常量,其值可以再改變

void main() {
  var point = Point(1, 2); // 調用常量構造函數,但是未定義成常量
  print(point.toString());
  point = Point(10, 20); // 可以重新賦值,說明定義的變量為非常量
  print(point.toString());
}
 
class Point {
  final int x;
  final int y;
  const Point(this.x, this.y);
  
  String toString() {
    return 'Point(${x}, ${y})';
  }
}
 

factroy ClassName(...) //工廠構造函數

工廠構造函數的定義
工廠構造函數是一種構造函數,與普通構造函數不同,工廠函數不會自動生成實例,而是通過代碼來決定返回的實例對象.

工廠構造函數的關鍵字為factory,下面我們用工廠構造函數寫一個只能創造一個實例的類.

class A{
  String name;

  static A cache;

  factory A([String name='A']){
    if(A.cache===null){
      A.cache=new A.newObject(name);
    }
    return A.cache;
  }

  A.newObject(this.name);
}

void main(){
  A a=new A('HelloWorld');
  print(a.name);

  A b=new A('HelloDart');
  print(b.name);

  print(a===b);
}
A類具有一個名為cache的靜態成員,它將緩存A類的第一個實例.

在工廠構造函數A中,首先判斷A.cache是否已經存在實例(即判斷是否是第一次實例化),如果存在則返回緩存的實例,不存在則新建一個實例並緩存.

A.newObject是一個命名構造函數,用於創建實例.

運行這段代碼,會輸出

HelloWorld
HelloWorld
true
其中字符串”HelloWorld”是第一個實例的name成員,在聲明變量b時改用了”HelloDart”,但返回的實例的name成員仍然是”HelloWorld”.

再用===運算符判斷一下它們是否屬於同一個對象,結果為true,變量a和b指向的是同一個對象.

3.8.2 工廠構造函數的特性
工廠構造函數類似於static靜態成員,無法訪問this指針,所以在工廠構造函數中能處理的任務較為有限.

使用工廠構造函數時往往需要定義一個命名構造函數用來生產實例.

注意點

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

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

參考:
鏈接:https://www.jianshu.com/p/a0ba5f2ac5ce

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM