想要寫好Flutter
,那么對(duì)Dart
的基本關(guān)鍵字的掌握是必不可少的杠巡,今天就再探究一下其他的關(guān)鍵字。
as is si!
as
is
is!
,運(yùn)算符用于運(yùn)行時(shí)處理類型檢查:
當(dāng)obj
實(shí)現(xiàn)了T
的接口時(shí),obj is T
是true
,obj as T
可以將obj
類型轉(zhuǎn)換成T
類型:
class Person {
void play(){
print('person');
}
}
class PersonSub extends Person{}
class Person2 {
void play(){
print('person2');
}
}
Person person = PersonSub();
if(person is Person2){
(person as Person2).play();
}
if(person is PersonSub){
(person as PersonSub).play();
}
當(dāng)person
類型是Person2
執(zhí)行第一個(gè)if
函數(shù),如果直接(person as Person2).play();
卧晓,則會(huì)崩潰,每次轉(zhuǎn)換類型的時(shí)候赴捞,提交校驗(yàn)a is T
是有必要的逼裆。
enum
枚舉類型也稱為 enumerations
或 enums
, 是一種特殊的類赦政,用于表示數(shù)量固定的常量值胜宇。
throw catch on final rethrow
捕獲異常可以避免異常繼續(xù)傳遞(除非重新拋出(rethrow
)異常)恢着。 可以通過(guò)捕獲異常的機(jī)會(huì)來(lái)處理該異常:
try {
breedMoreLlamas();
} on OutOfLlamasException {
buyMoreLlamas();
}
通過(guò)指定多個(gè) catch
語(yǔ)句桐愉,可以處理可能拋出多種類型異常的代碼。 與拋出異常類型匹配的第一個(gè) catch
語(yǔ)句處理異常掰派。 如果 catch
語(yǔ)句未指定類型从诲, 則該語(yǔ)句可以處理任何類型的拋出對(duì)象:
try {
breedMoreLlamas();
} on OutOfLlamasException {
// 一個(gè)特殊的異常
buyMoreLlamas();
} on Exception catch (e) {
// 其他任何異常
print('Unknown exception: $e');
} catch (e) {
// 沒(méi)有指定的類型,處理所有異常
print('Something really unknown: $e');
}
如上述代碼所示靡羡,捕獲語(yǔ)句中可以同時(shí)使用 on
和 catch
系洛,也可以單獨(dú)分開(kāi)使用。 使用 on 來(lái)指定異常類型略步, 使用 catch
來(lái) 捕獲異常對(duì)象描扯。
catch()
函數(shù)可以指定1到2個(gè)參數(shù), 第一個(gè)參數(shù)為拋出的異常對(duì)象趟薄, 第二個(gè)為堆棧信息 ( 一個(gè) StackTrace
對(duì)象 )荆烈。
try {
// ···
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}
如果僅需要部分處理異常, 那么可以使用關(guān)鍵字 rethrow
將異常重新拋出竟趾。
void misbehave() {
try {
dynamic foo = true;
print(foo++); // Runtime error
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // Allow callers to see the exception.
}
}
void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}
不管是否拋出異常憔购,finally
中的代碼都會(huì)被執(zhí)行。 如果 catch
沒(méi)有匹配到異常岔帽, 異常會(huì)在 finally
執(zhí)行完成后玫鸟,再次被拋出:
try {
breedMoreLlamas();
} finally {
// Always clean up, even if an exception is thrown.
cleanLlamaStalls();
}
任何匹配的 catch
執(zhí)行完成后,再執(zhí)行 finally
:
try {
breedMoreLlamas();
} catch (e) {
print('Error: $e'); // Handle the exception first.
} finally {
cleanLlamaStalls(); // Then clean up.
}
factory
當(dāng)執(zhí)行構(gòu)造函數(shù)并不總是創(chuàng)建這個(gè)類的一個(gè)新實(shí)例時(shí)犀勒,則使用 factory
關(guān)鍵字屎飘。 例如妥曲,一個(gè)工廠構(gòu)造函數(shù)可能會(huì)返回一個(gè) cache
中的實(shí)例, 或者可能返回一個(gè)子類的實(shí)例钦购。
以下示例演示了從緩存中返回對(duì)象的工廠構(gòu)造函數(shù):
class Logger {
final String name;
bool mute = false;
// 從命名的 _ 可以知檐盟,
// _cache 是私有屬性。
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);
}
}
const
使用過(guò)程中從來(lái)不會(huì)被修改的變量押桃, 可以使用 final 或 const, 而不是 var 或者其他類型葵萎, Final 變量的值只能被設(shè)置一次; Const 變量在編譯時(shí)就已經(jīng)固定 (Const 變量 是隱式 Final 的類型.) 最高級(jí) final 變量或類變量在第一次使用時(shí)被初始化唱凯。
提示: 實(shí)例變量可以是 final 類型但不能是 const 類型羡忘。 必須在構(gòu)造函數(shù)體執(zhí)行之前初始化 final 實(shí)例變量 —— 在變量聲明中,參數(shù)構(gòu)造函數(shù)中或構(gòu)造函數(shù)的初始化列表中進(jìn)行初始化磕昼。
創(chuàng)建和設(shè)置一個(gè) Final 變量:
final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';
final
不能被修改:
name = 'Alice'; // Error: 一個(gè) final 變量只能被設(shè)置一次卷雕。
如果需要在編譯時(shí)就固定變量的值,可以使用 const 類型變量票从。 如果 Const 變量是類級(jí)別的漫雕,需要標(biāo)記為 static const。 在這些地方可以使用在編譯時(shí)就已經(jīng)固定不變的值峰鄙,字面量的數(shù)字和字符串蝎亚, 固定的變量,或者是用于計(jì)算的固定數(shù)字:
const bar = 1000000; // 壓力單位 (dynes/cm2)
const double atm = 1.01325 * bar; // 標(biāo)準(zhǔn)氣壓
operator
重寫運(yùn)算符先馆,下面的運(yùn)算符可以被重寫躺彬。
< | + | | | [] | |
---|---|---|---|---|
> | / | ^ | [] | = |
<= | ~/ | & | ~ | |
>= | * | << | == | |
– | % | >> |
提示: 你可能會(huì)被提示 != 運(yùn)算符為非可重載運(yùn)算符仿野。 因?yàn)?e1 != e2 表達(dá)式僅僅是 !(e1 == e2) 的語(yǔ)法糖。
下面示例演示一個(gè)類重寫 + 和 - 操作符:
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);
// 運(yùn)算符 == 和 hashCode 部分沒(méi)有列出。 有關(guān)詳情亿扁,請(qǐng)參考下面的注釋从祝。
// ···
}
void main() {
final v = Vector(2, 3);
final w = Vector(2, 2);
assert(v + w == Vector(4, 5));
assert(v - w == Vector(0, 1));
}
如果要重寫 == 操作符,需要重寫對(duì)象的 hashCode getter 方法擎浴。 重寫 == 和 hashCode 的實(shí)例贮预,參考 Implementing map keys.
part part of
covariant
Function
Dart 是一門真正面向?qū)ο蟮恼Z(yǔ)言萌狂, 甚至其中的函數(shù)也是對(duì)象茫藏,并且有它的類型 Function 。 這也意味著函數(shù)可以被賦值給變量或者作為參數(shù)傳遞給其他函數(shù)。 也可以把 Dart 類的實(shí)例當(dāng)做方法來(lái)調(diào)用挟伙。 有關(guān)更多信息,參考 Callable classes.
已下是函數(shù)實(shí)現(xiàn)的示例:
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
雖然在 Effective Dart 中推薦 公共API中聲明類型, 但是省略了類型聲明,函數(shù)依舊是可以正常使用的:
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
如果函數(shù)中只有一句表達(dá)式齿坷,可以使用簡(jiǎn)寫語(yǔ)法:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
=> expr 語(yǔ)法是 { return expr; } 的簡(jiǎn)寫。 => 符號(hào) 有時(shí)也被稱為 箭頭 語(yǔ)法。
提示: 在箭頭 (=>) 和分號(hào) (;) 之間只能使用一個(gè) 表達(dá)式 蚕愤,不能是 語(yǔ)句 饺蚊。 例如:不能使用 if 語(yǔ)句 污呼,但是可以是用 條件表達(dá)式.
with
default
return yield
deferred hide
延遲加載庫(kù)
Deferred loading
(也稱之為 lazy loading
) 可以讓應(yīng)用在需要的時(shí)候再加載庫(kù)包竹。 下面是一些使用延遲加載庫(kù)的場(chǎng)景:
- 減少 APP 的啟動(dòng)時(shí)間苗缩。
- 執(zhí)行 A/B 測(cè)試彼乌,例如 嘗試各種算法的 不同實(shí)現(xiàn)灶挟。
- 加載很少使用的功能墅垮,例如可選的屏幕和對(duì)話框。
要延遲加載一個(gè)庫(kù)剃允,需要先使用 deferred as 來(lái)導(dǎo)入:
import 'package:greetings/hello.dart' deferred as hello;
當(dāng)需要使用的時(shí)候斥废,使用庫(kù)標(biāo)識(shí)符調(diào)用 loadLibrary()
函數(shù)來(lái)加載庫(kù):
Future greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
在一個(gè)庫(kù)上你可以多次調(diào)用 loadLibrary() 函數(shù)牡肉。但是該庫(kù)只是載入一次。
使用延遲加載庫(kù)的時(shí)候逾雄,請(qǐng)注意一下問(wèn)題:
延遲加載庫(kù)的常量在導(dǎo)入的時(shí)候是不可用的。 只有當(dāng)庫(kù)加載完畢的時(shí)候做鹰,庫(kù)中常量才可以使用击纬。
在導(dǎo)入文件的時(shí)候無(wú)法使用延遲庫(kù)中的類型。 如果你需要使用類型誊垢,則考慮把接口類型移動(dòng)到另外一個(gè)庫(kù)中掉弛, 讓兩個(gè)庫(kù)都分別導(dǎo)入這個(gè)接口庫(kù)。
Dart 隱含的把 loadLibrary() 函數(shù)導(dǎo)入到使用 deferred as 的命名空間 中喂走。 loadLibrary() 方法返回一個(gè) Future殃饿。
show hide
導(dǎo)入庫(kù)的一部分
如果你只使用庫(kù)的一部分功能,則可以選擇需要導(dǎo)入的 內(nèi)容芋肠。例如:
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;