作者 | 弗拉德
來源 | 弗拉德(公衆號:fulade_me)
Dart 同樣也是一種面向對象的語音。所以即便函數也是一個對象。類型爲
Function
,這意味着函數可做作爲變量,也也可以作爲函數的參數。
函數
下面是定義一個函數的例子:
isEmpty(List aList) {
return aList.length == 0;
}
爲了規範其實我們需要在函數的頭部聲明一下返回值類型,當然如果不聲明也可以運行,
bool isEmpty(List aList) {
return aList.length == 0;
}
如果函數體內只包含一個表達式,你可以使用簡寫語法:
bool isEmpty(List aList) => aList == 0;
=>
表達的 是 { return 表達式; }
的簡寫,有時=>
也稱之爲胖箭頭語法。
參數
函數可以有兩種形式的參數:必選參數 和 可選參數。必選參數定義在參數列表前面,可選參數一定是定義在必要參數後面。
可選的命名參數
當你調用函數時,可以使用 參數名: 參數值 的形式來指定命名參數。例如:
enableFlags(bold: true, hidden: false);
已命名的參數是可選參數了,除非他們被特別標記爲 required
。
定義函數時,使用 {param1, param2, …}
來指定命名參數:
/// 設置 [bold] 和 [hidden] 標識……
void enableFlags({bool bold, bool hidden}) {...}
雖然命名參數是可選參數的一種類型,但是你仍然可以使用 @required
註解來標識一個命名參數是必須的參數,此時調用者則必須爲該參數提供一個值。例如:
const Scrollbar({Key key, @required Widget child})
如果調用者想要通過 Scrollbar
的構造函數構造一個 Scrollbar
對象而不提供 child 參數,則會導致編譯錯誤。
可選參數
使用 []
將一系列參數包裹起來作爲可選參數:
strings(String s1, String s2, [String s3]) {
var result = '$s1 and $s2';
if (s3 != null) {
result = '$result and $s3';
}
print(result);
}
下面是不使用可選參數調用上述函數的示例:
strings("s1", "s2");
s1 and s2
下面是使用可選參數調用上述函數的示例:
strings("s1", "s2", "s3");
s1 and s2 and s3
默認參數值
我們可以用 =
爲函數的命名參數和可選參數定義默認值,默認值必須爲編譯時常量,沒有指定默認值的情況下默認值爲 null
。
下面是設置可選參數默認值示例:
/// 設置 [bold] 和 [hidden] 標識……
void enableFlags({bool bold = false, bool hidden = false}) {...}
// bold 的值將爲 true;而 hidden 將爲 false。
enableFlags(bold: true);
下一個示例 默認值:
strings(String s1, String s2, [String s3 = 'this is s3', String s4]) {
var result = '$s1 and $s2';
if (s3 != null) {
result = '$result and $s3';
}
if (s4 != null) {
result = '$result and $s4';
}
print(result);
}
strings("s1", "s2");
s1 and s2 and this is s3
main() 函數
每個 Dart
程序都必須有一個 main()
頂級函數作爲程序的入口,main()
函數返回值爲 void
。
下面是一個 Flutter 應用的 main()
函數示例:
void main() {
runApp(MyApp());
}
函數作爲參數
可以將函數作爲參數傳遞給另一個函數。例如:
void printElement(int element) {
print(element);
}
// 將 printElement 函數作爲參數傳遞。
var list = [1, 2, 3];
list.forEach(printElement);
你也可以將函數賦值給一個變量,比如:
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
var result = loudify('hello');
print(result);
匿名函數
大多數方法都是有名字的,比如
main()
或printElement()
。你可以創建一個沒有名字的方法,稱之爲 匿名函數,其實匿名函數很常見,也有不同的叫法,在C++裏面叫Lambda表達式,在Objective-C叫Block閉包。你可以將匿名方法賦值給一個變量然後使用它。
匿名方法看起來與命名函數h類似,在括號之間可以定義參數,參數之間用逗號分割。
後面大括號中的內容則爲函數體:
([[類型] 參數[, …]]) {
函數體;
};
下面代碼定義了只有一個參數 item
且沒有參數類型的匿名方法。List
中的每個元素都會調用這個函數,打印元素位置和值的字符串:
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
如果函數體內只有一行語句,你可以使用胖箭頭縮寫法。下面代碼的運行結果,與上面代碼的運行結果是一致的。
list.forEach(
(item) => print('${list.indexOf(item)}: $item'));
變量作用域
變量的作用域在寫代碼的時候就確定了,大括號內定義的變量只能在大括號內訪問,與 Java 類似。
下面是一個嵌套函數中變量在多個作用域中的示例:
bool topLevel = true;
void main() {
var insideMain = true;
void myFunction() {
var insideFunction = true;
void nestedFunction() {
var insideNestedFunction = true;
assert(topLevel);
assert(insideMain);
assert(insideFunction);
assert(insideNestedFunction);
}
}
}
注意 nestedFunction()
函數可以訪問包括頂層變量在內的所有的變量。
返回值
所有的函數都有返回值。沒有顯示返回語句的函數最後一行默認爲執行 return null
;。
foo() {}
assert(foo() == null);
本文所有代碼都已上傳到Github