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

前言

Dart 語言的構(gòu)造函數(shù)和其他語言會有些不同鲫尊,我們列舉一下 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ù)。實際上工廠構(gòu)造函數(shù)的特點是不一定返回新的實例咐吼,比如我們示例的代碼吹缔,可以從緩存中取出已有對象返回。同時锯茄,工廠構(gòu)造函數(shù)還可以返回該類的子類厢塘。而且工廠構(gòu)造函數(shù)是要通過 return 語句返回一個對象,而命名構(gòu)造函數(shù)不允許返回肌幽,只能構(gòu)建當(dāng)前類的對象晚碾。這么多構(gòu)造函數(shù),該如何合理使用喂急,我們來看看官方的指引規(guī)范格嘁。

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

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

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

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

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

聲明式 null safety 要求非空字段必須在使用之前被初始化蜂嗽。由于成員屬性可能在構(gòu)造函數(shù)中使用,因此如果不初始化非空成員的話殃恒,會導(dǎo)致編譯器報錯植旧。可以通過在成員前加 late 修飾离唐,這時候如果不初始化而直接使用該成員的話 病附,會將編譯時錯誤轉(zhuǎn)換為運行時錯誤。這種情況下最好的解決辦法是為構(gòu)造函數(shù)提供成員清單進(jìn)行初始化侯繁。

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

// 錯誤示例
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ù)最開始處對這些成員進(jìn)行了初始化丽焊。

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

在 Dart 中咕别,如果構(gòu)造函數(shù)體為空技健,那么可以簡單地用分號結(jié)束函數(shù),而無需使用大括號來寫一個空的函數(shù)體惰拱。

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

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

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

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

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

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

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

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

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

// 錯誤示例
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中赞枕,如果一個對象前面加 new 來替代 const 會報錯的話,那么就隱式是 const 的,此時無需再額外加 const鹦赎。

總結(jié)

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市肩狂,隨后出現(xiàn)的幾起案子摘完,更是在濱河造成了極大的恐慌,老刑警劉巖傻谁,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件孝治,死亡現(xiàn)場離奇詭異,居然都是意外死亡审磁,警方通過查閱死者的電腦和手機(jī)谈飒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來态蒂,“玉大人杭措,你說我怎么就攤上這事〖鼗郑” “怎么了手素?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長瘩蚪。 經(jīng)常有香客問我泉懦,道長,這世上最難降的妖魔是什么疹瘦? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任漾脂,我火速辦了婚禮饥侵,結(jié)果婚禮上乙埃,老公的妹妹穿的比我還像新娘巷查。我一直安慰自己艺糜,他們只是感情好包各,可當(dāng)我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布曾雕。 她就那樣靜靜地躺著见芹,像睡著了一般钉嘹。 火紅的嫁衣襯著肌膚如雪鸯乃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機(jī)與錄音缨睡,去河邊找鬼鸟悴。 笑死,一個胖子當(dāng)著我的面吹牛奖年,可吹牛的內(nèi)容都是我干的细诸。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼陋守,長吁一口氣:“原來是場噩夢啊……” “哼震贵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起水评,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤猩系,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后中燥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寇甸,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年疗涉,在試婚紗的時候發(fā)現(xiàn)自己被綠了拿霉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡博敬,死狀恐怖友浸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情偏窝,我是刑警寧澤收恢,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站祭往,受9級特大地震影響伦意,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜硼补,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一驮肉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧已骇,春花似錦离钝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鲤竹,卻和暖如春浪读,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工碘橘, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留互订,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓痘拆,卻偏偏與公主長得像仰禽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子纺蛆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容