Dart 如何正確使用構(gòu)造函數(shù)?

前言

Dart 語言的構(gòu)造函數(shù)和其他語言會(huì)有些不同,我們列舉一下 Dart 中的構(gòu)造函數(shù)的幾種形式。

// 最常見的形式
class Person {
  String name;
  int age;
  Person(this.name, this.age);
}

// 命名構(gòu)造函數(shù)
class Person {
  late String name;
  late int age;

  Person.fromJson(Map<String, dynamic> json) {
    name = json['name'];
    age = json['age'];
  }
}

// 工廠構(gòu)造函數(shù)
class Person {
  late String name;
  static final Map<String, Person> _cache =
      <String, Person>{};

  factory Person.withName(String name) {
    return _cache.putIfAbsent(
        name, () => Person._internal(name));
  }
  
  Person._internal(this.name);
}

// 常量構(gòu)造函數(shù)
class Person {
  final String name;
  final int age;
 
  const Person(this.name, this.age);
}

// 使用其他構(gòu)造函數(shù)構(gòu)造
class Person {
  String name;
  int age;
    
  Person(this.name, this.age);
  Person.anymous(int age): this('Anymous', age);
}

// 帶參數(shù)斷言的構(gòu)造函數(shù)(debug 模式有效)
class Person {
  String name;
  int age;
  Person.withAssert(this.name, this.age)
      : assert(age >= 0),
        assert(name.length > 0);
}

// 使用父類構(gòu)造函數(shù)構(gòu)建
class Student extends Person {
  String school;
  Student(name, age, this.school) : super(name, age);
}

這里比較容易混淆的是命名構(gòu)造函數(shù)工廠構(gòu)造函數(shù)。實(shí)際上工廠構(gòu)造函數(shù)的特點(diǎn)是不一定返回新的實(shí)例,比如我們示例的代碼,可以從緩存中取出已有對(duì)象返回。同時(shí),工廠構(gòu)造函數(shù)還可以返回該類的子類。而且工廠構(gòu)造函數(shù)是要通過 return 語句返回一個(gè)對(duì)象,而命名構(gòu)造函數(shù)不允許返回,只能構(gòu)建當(dāng)前類的對(duì)象。這么多構(gòu)造函數(shù),該如何合理使用,我們來看看官方的指引規(guī)范。

規(guī)則1:盡可能使用構(gòu)造函數(shù)直接初始化成員的方式

Dart 提供了一種快捷初始化成員屬性的方式,那就是在構(gòu)造函數(shù)中使用 this.語法,這時(shí)候?qū)?yīng)的成員會(huì)自動(dòng)賦值而無需手動(dòng)進(jìn)行賦值。這樣的初始化成員的方式更加簡(jiǎn)潔。

// 正確示例
class Point {
  double x, y;
  Point(this.x, this.y);
}

// 錯(cuò)誤示例
class Point {
  double x, y;
  Point(double x, double y)
      : x = x,
        y = y;
}

規(guī)則2:如果構(gòu)造函數(shù)會(huì)初始化成員,那么不要使用 late 修飾。

聲明式 null safety 要求非空字段必須在使用之前被初始化。由于成員屬性可能在構(gòu)造函數(shù)中使用,因此如果不初始化非空成員的話,會(huì)導(dǎo)致編譯器報(bào)錯(cuò)??梢酝ㄟ^在成員前加 late 修飾,這時(shí)候如果不初始化而直接使用該成員的話 ,會(huì)將編譯時(shí)錯(cuò)誤轉(zhuǎn)換為運(yùn)行時(shí)錯(cuò)誤。這種情況下最好的解決辦法是為構(gòu)造函數(shù)提供成員清單進(jìn)行初始化。

// 正確示例
class Point {
  double x, y;
  Point.polar(double theta, double radius)
      : x = cos(theta) * radius,
        y = sin(theta) * radius;
}

// 錯(cuò)誤示例
class Point {
  late double x, y;
  Point.polar(double theta, double radius) {
    x = cos(theta) * radius;
    y = sin(theta) * radius;
  }
}

使用初始化清單的形式的好處是在使用這些成員之前能夠確保已經(jīng)得到了初始化,哪怕是構(gòu)造函數(shù)中。我們可以理解為是一種語法糖,在構(gòu)造函數(shù)最開始處對(duì)這些成員進(jìn)行了初始化。

規(guī)則3:對(duì)于空構(gòu)造函數(shù)體,使用分號(hào)結(jié)束而不是{}空函數(shù)體

在 Dart 中,如果構(gòu)造函數(shù)體為空,那么可以簡(jiǎn)單地用分號(hào)結(jié)束函數(shù),而無需使用大括號(hào)來寫一個(gè)空的函數(shù)體。

// 正確示例
class Point {
  double x, y;
  Point(this.x, this.y);
}

//錯(cuò)誤示例
class Point {
  double x, y;
  Point(this.x, this.y) {}
}

規(guī)則4:不要使用 new 來構(gòu)建新對(duì)象

Dart 2版本以后,new 關(guān)鍵字是可選的。new 關(guān)鍵字實(shí)際上在 Dart 中已經(jīng)被標(biāo)記為棄用了。當(dāng)你習(xí)慣了沒有 new 的方式后,你肯定會(huì)和我一樣,覺得加了 new 關(guān)鍵字的代碼很丑陋,尤其是在組件樹中。

// 正確示例
Widget build(BuildContext context) {
  return Row(
    children: [
      RaisedButton(
        child: Text('Increment'),
      ),
      Text('Click!'),
    ],
  );
}

// 錯(cuò)誤示例
Widget build(BuildContext context) {
  return new Row(
    children: [
      new RaisedButton(
        child: new Text('Increment'),
      ),
      new Text('Click!'),
    ],
  );
}

規(guī)則5:不要加多余的 const

當(dāng)一個(gè)對(duì)象在上下文中必須是常量時(shí),const 關(guān)鍵字是隱式的,而無需再單獨(dú)寫。下面列舉的上下文中的表達(dá)式是默認(rèn)就是 const 的:

  • 一個(gè)不變的集合;
  • 調(diào)用聲明為 const 的構(gòu)造函數(shù);
  • 元數(shù)據(jù)的注解;
  • 用于常量聲明時(shí)的初始化對(duì)象(見下面的示例)
  • switch-case 語句中的 case 冒號(hào)后面的表達(dá)式。
// 正確示例
const primaryColors = [
  Color('red', [255, 0, 0]),
  Color('green', [0, 255, 0]),
  Color('blue', [0, 0, 255]),
];

// 錯(cuò)誤示例
const primaryColors = const [
  const Color('red', const [255, 0, 0]),
  const Color('green', const [0, 255, 0]),
  const Color('blue', const [0, 0, 255]),
];

基本上,在 Dart 2中,如果一個(gè)對(duì)象前面加 new 來替代 const 會(huì)報(bào)錯(cuò)的話,那么就隱式是 const 的,此時(shí)無需再額外加 const

總結(jié)

Dart 語言為我們提供了很多簡(jiǎn)寫構(gòu)造函數(shù)的語法糖,雖然按其他語言那種形式編寫也不會(huì)有什么問題,但是遵循舊的方式如何能夠體現(xiàn) Dart 這門年輕語言的優(yōu)勢(shì)呢?因此,多了解 Dart 語言自身的一些特性,可以讓我們的編碼效率更高,代碼更整潔。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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