使用構造方法
var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
var p1 = new Point(2, 2);
var p2 = new Point.fromJson({'x': 1, 'y': 2});
上面這兩種寫法都是可以的,Dart2中new關鍵字已經成為一個可選項
常量構造方法
有些類提供常量構造函數。要使用常量構造函數建立編譯時常量,請将const關鍵字放在構造函數名稱之前
var p = const ImmutablePoint(2, 2);
構造兩個相同的編譯時常量會産生一個規範的執行個體:
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);
assert(identical(a, b)); // They are the same instance!
如果将const關鍵字前置的話,後面的const是可以省略的,比如
// Lots of const keywords here.
const pointAndLine = const {
'point': const [const ImmutablePoint(0, 0)],
'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};
上面的代碼可以寫成
// Only one const, which establishes the constant context.
const pointAndLine = {
'point': [ImmutablePoint(0, 0)],
'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};
擷取運作時類型
要在運作時擷取對象的類型,可以使用Object的runtimeType屬性,該屬性傳回Type對象。
print('The type of a is ${a.runtimeType}');
####聲明構造函數
class Point {
num x, y;
// Syntactic sugar for setting x and y
// before the constructor body runs.
Point(this.x, this.y);
}
上面是一種簡化版的構造函數,隻是為了指派,是以省略了方法體
如果您未聲明構造函數,則會為您提供預設構造函數。
預設構造函數沒有參數,并在超類中調用無參數構造函數。
####命名構造函數
使用命名構造函數為類實作多個構造函數或提供額外的清晰度:
class Point {
num x, y;
Point(this.x, this.y);
// Named constructor
Point.origin() {
x = 0;
y = 0;
}
}
跟Java等語言不同,Dart的多重構造方法是一種類名.自定義方法名來實作的,如果你按照傳統的方法來寫的話,例如這樣:
class Grammar2 {
var x, y, z;
Grammar2(this.x,this.y); //錯誤
Grammar2(this.x); //不能同時擁有兩個這樣的構造函數
}
正确的寫法
class Grammar2 {
var x, y, z;
Grammar2.translate(this.x, this.y); //TODO 構造方法的重載
Grammar2(this.x,this.y);
printRealVar() {
print('x=' + x.toString() + "y=" + y.toString());
return 2;
}
@override
String toString() {
// TODO: implement toString
return "this is Grammar2";
}
}
調用非預設的超類構造函數
預設情況下,子類中的構造函數調用超類的未命名的無參數構造函數。
超類的構造函數在構造函數體的開頭被調用。
如果還使用初始化清單,則在調用超類之前執行。
總之,執行順序如下:
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:
// in Person
// in Employee
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
(emp as Person).firstName = 'Bob';
}
這段代碼的執行結果就是:
in Person
in Employee
除了調用超類構造函數之外,還可以在構造函數體運作之前初始化執行個體變量。
用冒号分隔初始化程式。
// 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)');
}
這個示例中,我們在調用fromjson這個構造方法之前我們搶先初始化了x和y的值,中間用冒号隔開
你也可以在調用初始化方法之前進行一些參數的驗證,比如:
Point.withAssert(this.x, this.y) : assert(x >= 0) {
print('In Point.withAssert(): ($x, $y)');
}
這個示例中,構造方法調用之前,我們驗證了x必須為正數
構造函數的重定向
我們在開發中經常會有這樣的情景,我們構造了好幾個構造方法,但是這些構造方法本身并不執行任何操作,隻是為了調用其他構造 方法,在Dart中,我們稱之為構造方法的重定向(這個文法在前面示例中出現過)
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);
}
####常量構造方法
假如你的示例在整個程式從始至終都不會變更執行個體,這個時候你可以考慮一下使用常量構造方法,在構造方法前面加上const關鍵字(是不是很像單例模式?)
class ImmutablePoint {
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
final num x, y;
const ImmutablePoint(this.x, this.y);
}
工廠構造方法
跟工廠設計模式類似,需要什麼給你什麼,根據一個特定的辨別産生不同的執行個體,在Dart中,通過傳入一個特定的辨別符,來檢視我的靜态緩存裡面有沒有這個緩存,如果有,直接傳回,如果沒有,我便new 一個對象存入緩存再傳回
class Logger {
final String name;
bool mute = false;
// _cache is library-private, thanks to
// the _ in front of its name.
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
工廠構造函數無權通路 this
對象之間的操作符運算
您可以覆寫下表中顯示的運算符。
例如,如果定義Vector類,則可以定義一個+方法來添加兩個向量。(翻譯自官網)
來個示例,自己體會
class Vector {
final int x, y;
Vector(this.x, this.y);
Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
// Operator == and hashCode not shown. For details, see note below.
// ···
}
void main() {
final v = Vector(2, 3);
final w = Vector(2, 2);
assert(v + w == Vector(4, 5));
assert(v - w == Vector(0, 1));
}
要在代碼嘗試使用不存在的方法或執行個體變量時檢測或做出反應,您可以覆寫noSuchMethod():
class A {
// Unless you override noSuchMethod, using a
// non-existent member results in a NoSuchMethodError.
@override
void noSuchMethod(Invocation invocation) {
print('You tried to use a non-existent member: ' +
'${invocation.memberName}');
}
}
枚舉類
enum Color { red, green, blue }
枚舉中的每個值都有一個索引getter,它傳回枚舉聲明中值的從零開始的位置。
例如,第一個值具有索引0,第二個值具有索引1。
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
要擷取枚舉中所有值的清單,請使用枚舉值常量。
List colors = Color.values;
assert(colors[2] == Color.blue);
switch case中使用枚舉
var aColor = Color.blue;
switch (aColor) {
case Color.red:
print('Red as roses!');
break;
case Color.green:
print('Green as grass!');
break;
default: // Without this, you see a WARNING.
print(aColor); // 'Color.blue'
}
Mixin
Mixins是一種在多個類層次結構中重用類代碼的方法,B繼承于A,但是B也要用到C的一些特性,多繼承在很多語言中是行不通的,Dart中的Mixin就是為了解決這種問題出現的
要使用mixin,請使用with關鍵字,後跟一個或多個mixin名稱。
以下示例顯示了兩個使用mixins的類:
class Musician extends Performer with Musical {
// ···
}
class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
注意:要實作一個mixin,建立一個擴充Object的類,聲明沒有構造函數,并且沒有調用super。
例如:
abstract class Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}
泛型方法(隻看代碼不解釋,跟java幾乎一樣)
T first<T>(List<T> ts) {
// Do some initial work or error checking, then...
T tmp = ts[0];
// Do some additional checking or processing...
return tmp;
}
導入
Dart目前都要手動導入包,Dart内置的library可以直接用import ‘Interface.dart’;方法導入,自定義的包可以在前面加入一個package關鍵字導入
import 'package:flutter_app/Grammar2.dart';
import 'SuperGrammar.dart';
import 'Interface.dart';
import 'FactoryClass.dart';
import 'package:meta/meta.dart';
import 'ConstantClass.dart';
有一種情況例外,加入導入的兩個包裡面有同名的類,這個時候如何區分,java 是用全路徑來辨別,Dart裡面可以給這個包裡面所有的類設定一個别名
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2; //這裡利用as來設定 别名
// Uses Element from lib1.
Element element1 = Element();
// Uses Element from lib2.
lib2.Element element2 = lib2.Element();
如果你想導入的是一個包中的部分類
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
設定這個功能的出發點是可以降低包體積麼??? 不得而知
improt 懶加載
這個是為了在使用導入的類的時候才會去載入這個包,主要是為了提升啟動效率
如果需要使用懶加載的功能,請使用deferred as 關鍵字
import 'package:greetings/hello.dart' deferred as hello;
//需要的時候調用别名.loadLibiary方法
Future greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
在前面的這段代碼中 await 關鍵字的作用是暫停程式的運作直到包導入完成
-
延遲庫的常量不是導入檔案中的常量。
請記住,在加載延遲庫之前,這些常量不存在。
-
您不能在導入檔案中使用延遲庫中的類型。
相反,請考慮将接口類型移動到由延遲庫和導入檔案導入的庫。
- Dart隐式地将loadLibrary()插入到使用deferred as namespace定義的命名空間中。loadLibrary()函數傳回Future。