Flutter-Dart構造函數介紹

寫flutter 真的是}})))}}})))改到崩潰。。。。

【轉】
Dart構造函數介紹

介紹

因為Flutter和Dart語言非常容易上手,很多學習Flutter的同學,一般都會直接寫Flutter頁面,對Dart語言也是一知半解,包括我自己。

Dart語言和很多現代語言都很類似,但是其構造函數,其靈活性,還是比我了解的其它語言要多的,所以在寫構造函數的時候,要么莫名其妙報錯,要么寫的很復雜,沒有將其精髓掌握。

下面跟大家總結一下Dart構造函數的語法,方便大家查閱

語法介紹

格式

Dart構造函數有4種格式:

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); //常量構造函數,用來創(chuàng)建編譯期常量?

插播廣告

如果想知道某個變量屬于哪個類,可以使用runtimeType:

print('The type of a is ${a.runtimeType}');

定義

1. 默認構造函數

如果你定義了一個類,而沒有定義構造函數,那么它將有一個默認的構造函數,這個構造函數?沒有參數

如果這個類有父類,那么默認構造函數,還會調用父類的無參數構造函數。

2. 普通構造函數

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

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的賦值變得簡單一些,就不用寫構造函數的方法體了,記得括號后用分號哦。

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:?

????//inPerson?

????//inEmployee

}?

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

5. 初始化列表

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

// Initializer list sets instance variables before

// the constructor body runs.

????Point.fromJson(Map json)? ? :

????????????x = json['x'],? ?

????????????? y = json['y'] {

????????print('In Point.fromJson(): ($x, $y)');

}?

尤其是初始化那些final修飾的成員變量時,初始化列表很有用,因為在方法體中,不能給final修飾的成員變量賦值,因為在執(zhí)行方法體的時候,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);

}?

如果你的類,創(chuàng)建的對象永遠不會改變,你可以在編譯期就創(chuàng)建這個常量實例,并且定義一個常量構造函數,并且確保所有的成員變量都是final的。

8. 工廠構造函數

有時候可能有一種需求,并不需要每次都創(chuàng)建新的類實例,而是每一種情況,只需要一個實例:

class Logger {?

????????final String name;?

????????????bool mute =false;?

????????????// _cache is library-private, thanks to?

????????????// the _infront of its name.?

????????????static final Map _cache =? ? ? {};?

????????factory Logger(String name) {

????????????if(_cache.containsKey(name)) {

????????????return_cache[name];? ?

????????????}else{? ?

????????????? final logger = Logger._internal(name);?

????????? ? _cache[name] = logger;returnlogger;? ? }? }? ????????????Logger._internal(this.name);?

????????void log(String msg) {

????????????if(!mute)print(msg);?

????????}}

????????main() {? ?

????????var logger = Logger('UI');? ?

????????logger.log('Button clicked');

}?

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

上例的意思是,類中又一個靜態(tài)緩存_cache保存著一些Logger類實例,創(chuàng)建實例時,給工廠構造函數傳遞的name,如果在緩存中已經存在,就用緩存中現成的實例,如果沒有,就新建一個實例,并且也放到緩存中。

如此這般,我們可以創(chuàng)建名字為UI / SYS / API 等的實例,然后在debug的時候,如果設置名字為UI的Logger實例的mute為true,就不會打印UI相關的log,而不影響其它兩個名字的log。是不是很方便呢?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容