寫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。是不是很方便呢?