1 方法
1.1 一等方法對象 Function
void fun() {
print('hhaha');
}
void main() {
Function f = fun; // 方法都是對象,可以賦值給Function對象
f(); // 調(diào)用fun()方法
}
Function還可以作為參數(shù)傳入
void fun2(Function function) { // 沒有辦法標(biāo)識要傳遞的這個(gè)方法參數(shù)和返回值
print('hhaha222');
function(); // 調(diào)用傳入的方法,無參。如果傳入的方法是有參的,運(yùn)行時(shí)報(bào)錯(cuò)
}
void main() {
Function f2 = fun2; // 方法都是對象,可以賦值給Function對象
// f2(); // 運(yùn)行報(bào)錯(cuò),需要傳參
f2(f); // 調(diào)用fun2()方法,傳入方法
// 也可以傳入一個(gè)匿名方法
f2(() {
print('傳入的方法參數(shù)是匿名方法'); // 不會執(zhí)行,需要在fun2中調(diào)用才會執(zhí)行。
});
// 匿名方法可以隨意定義參數(shù)和返回值
// 在fun2需要調(diào)用時(shí),傳入的參數(shù)需要和這里定義的參數(shù)類型、數(shù)量相同,否則會運(yùn)行報(bào)錯(cuò)。
// 這就有些不方便了,那如果傳入的參數(shù)錯(cuò)誤,有什么辦法可以在編譯器就能檢查出來呢?這就要引入typedef關(guān)鍵字了。
f2((int a, int b) {
return "1";
});
typedef關(guān)鍵字的使用
// 定義一個(gè)類型,F(xiàn)類型,這個(gè)F類型其實(shí)就是一個(gè)方法,接收兩個(gè)int參數(shù),返回void
typedef void F(int i, int j);
定義一個(gè)方法,將F作為參數(shù)傳入。
void fun3(F f) {
f(1, 2); // 這邊在編譯時(shí)就會校驗(yàn)傳參是否正確。
print('hhaha3333');
}
調(diào)用fun2()方法
// 方法1
Function f3 = fun3;
f3((int i, int j) { // 這邊好像要在運(yùn)行時(shí)才會報(bào)錯(cuò)。
});
// 方法2
fun3((i, j) { // 這邊在編譯時(shí)也就會校驗(yàn)傳參是否正確。
});
如果不想使用typedef,直接將方法的原形作為參數(shù)傳入也是可以的
void fun4(void f1(int i, int j)) { // 這種寫法可以表達(dá)傳遞的這個(gè)方法參數(shù)和返回值,但寫起來比較麻煩
f1(1, 2);
}
使用場景示例:
如果我們之前在java中設(shè)置一個(gè)onClick監(jiān)聽,需要傳入接口,并實(shí)現(xiàn)接口的方法。但在dart中就可以直接傳入一個(gè)方法接口。
typedef void onClick();
void setOnClickListener(onClick click){
click(); // 通過這種方式就可以直接回調(diào)出去了。
}
1.2 可選位置參數(shù)
可以當(dāng)做是為了解決java中的方法重載問題。
如果我們提供了同一個(gè)方法名的兩個(gè)方法,只是傳入的參數(shù)不同。fun(int a)、fun(int a,int b)
在dart中,我們只需要提供一個(gè)方法fun(int a,int b)即可,讓使用者決定傳入哪個(gè)。只需要加上中括號即可
void fun(int a, int b) {}
// 可選位置參數(shù)
void fun1([int aa = 0, int bb = 0]) {
// 最新的版本中一定要給一個(gè)默認(rèn)值,否則編譯報(bào)錯(cuò)。之前版本好像沒問題
}
void main() {
fun(1, 2); // 必須傳兩個(gè)參數(shù)
fun1(); // 可以不傳參數(shù)
fun1(1); // 也可以只傳一個(gè),1會賦值個(gè)aa。如果要傳bb參數(shù),aa必須要傳
fun1(1, 2); // 也可以傳兩個(gè)
}
1.3 可選命名參數(shù)
與可選位置參數(shù)不同的是,中括號改成大括號,就是可選命名參數(shù)
// 可選命名參數(shù)
void fun2({int aa = 0, int bb = 0}) {
// 最新的版本中一定要給一個(gè)默認(rèn)值,否則編譯報(bào)錯(cuò)。之前版本好像沒問題
}
void main() {
fun2(); // 不傳參數(shù),也沒問題
// fun2(1); // 只傳一個(gè)參數(shù),這樣寫就不行了。需要給傳入的這個(gè)值命名
fun2(aaa: 1); // 帶入變量名,就可以給任意一個(gè)值傳值了。
fun2(bbb: 2);
fun2(bbb: 2, aaa: 1); // 順序也可以隨便傳
}
1.4 默認(rèn)參數(shù)值
可選位置參數(shù)和可選命名參數(shù)都使用到了默認(rèn)參數(shù)值。
1.5 匿名方法
沒有方法名的方法
void fun(Function function) {}
void main() {
fun(() {
});
fun((int, String) {
});
}
2 異常
void fun() {
throw Exception();
}
void main() {
// fun(); // 不需要像java中一樣調(diào)用try-catch。但是也支持
try {
fun();
} catch (e) {
// 不需要聲明類型,傳入一個(gè)變量名。e就是拋出的異常對象
print(e);
}
try {
fun();
} catch (e, a) {
// 打印結(jié)果:Exception
print(e);
// 也可以傳入兩個(gè)變量名。第二個(gè)參數(shù)是StackTrace 調(diào)用棧信息。打印結(jié)果:
// #0 fun (package:untitled/%E5%BC%82%E5%B8%B8/%E5%BC%82%E5%B8%B8.dart:2:3)
// #1 main (package:untitled/%E5%BC%82%E5%B8%B8/%E5%BC%82%E5%B8%B8.dart:16:5)
// #2 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
// #3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
print(a);
}
}
在dart中可以拋出任意一種類型
void fun() {
// throw Exception(); // 在dart中不光可以拋出一個(gè)異常
// throw Error(); // 還可以拋出error
// throw 1; // 還可以拋出一個(gè)int值
// throw "異常信息"; // 拋出一個(gè)字符串
throw fun2; // 甚至是一個(gè)方法、類
}
void fun2() {
print("我是一個(gè)方法");
}
根據(jù)不同的異常類型進(jìn)行不同的處理
// 在catch前添加on+拋出類型。
void main() {
try {
fun();
} on Function catch (e) {
print("拋出了一個(gè)方法 $e");
e(); // 如果拋出的是一個(gè)方法,甚至可以直接在這里調(diào)用這個(gè)方法。
} on int catch (e) {
print("拋出了一個(gè)int值 $e");
} on String catch (e) {
print("拋出了一個(gè)字符串 $e");
} on MissingPluginException catch (e) {
print("拋出了一個(gè)MissingPluginException異常 $e");
} on Exception catch (e) {
print("拋出了一個(gè)Exception異常 $e");
} finally { // finally用法和java一樣
}
}