Dart 是一門徹底的面向對象有語言。甚至函數
也是一個對象,它的類型是 Function
,這意味着函數能夠賦值給變量,也能夠被做爲參數傳遞給另外一個函數git
下面來看下 Dart
一個簡單的函數:github
bool isEven(int position) {
return nums[position] % 2 == 0;
}
複製代碼
雖然 Dart 官方不建議省略 type annotation (函數返回類型、變量類型等), 可是 Dart 語法依然容許咱們省略:bash
isEven(int position) {
return nums[position] % 2 == 0;
}
複製代碼
上面的函數體內只有一個表達式,因此咱們可使用箭頭函數,這樣看上去更加簡潔:閉包
bool isEven(int position) => nums[position] % 2 == 0;
複製代碼
根據官方上對箭頭函數的描述:=>
和 分號 ;
之間只能是一個表達式而不是語句. 好比 =>
和 ;
之間不能放 if 語句
,但能夠放 條件表達式(condition ? expr1 : expr2)
app
可是通過測試發現 =>
和 ;
之間一條非控制流語句,如:ide
wrapPrint() => print("fat arrow function");
複製代碼
上面提到 =>
和 ;
之間不能放 if語句
, 可能開發者再把普通函數改爲箭頭函數忘記了刪除花括號{}
函數
test() => {
if (true) {print("success")}
};
複製代碼
這不是使用了 if表達式 了嗎?可是上面的例子 =>
和 ;
之間實際上是一個 Set 集合
, {}
不只在定義函數的時候用到,在構建 Set、Map集合字面量
的時候也用到了,而後在構建 Set 字面量的時候使用 if 語句而已(collection if-for), 這些已經在前面的文字講過了:學習
咱們能夠打印一下 test
函數的返回類型就知道了:測試
main() {
print(test().runtimeType);
}
// 輸出
_CompactLinkedHashSet<Set<void>>
複製代碼
因此上面的例子 =>
和 ;
之間依然是一個表達式.ui
在調用一個可選參數的函數, 能夠指定指定某個須要傳遞的參數, 或者一個參數都不傳遞
語法格式:funcName(param1, param2, {opt1, opt2, …})
void enableFlags({bool bold, bool hidden}) {}
main() {
enableFlags(bold: false);
enableFlags(bold: false);
enableFlags(bold: false,hidden: false);
}
複製代碼
還可使用 meta
包下的 @required
註解來指定哪些參數是必須的:
void enableFlags({bool bold, @required bool hidden}) {}
複製代碼
語法格式:funcName(param1, param2, [opt1, opt2, …])
void enableFlags(bool bold, bool hidden, [bool underline]) {}
main() {
enableFlags(false, false);
enableFlags(false, false, true);
}
複製代碼
咱們可使用 =
爲可選參數提供默認值:
//可選參數
void enableFlags({bool bold = true, bool hidden = false}) {}
// dart 也容許使用 `:` 代替 `=`, 可是已經不建議使用
void enableFlags({bool bold : true, bool hidden : false}) {}
// 可選的位置參數
void enableFlags2([bool bold = true, bool hidden = false]) {}
複製代碼
須要注意的是參數的默認值必須是編譯時常量(runtime-constants):
void doStuff(
{List<int> list = const [1, 2, 3],
Map<String, String> gifts = const {
'first': 'paper',
'second': 'cotton',
'third': 'leather'
}}) {
print('list: $list');
print('gifts: $gifts');
}
複製代碼
函數做爲一等公民能夠將其做爲參數傳遞給另外一個函數,例如:
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// Pass printElement as a parameter.
list.forEach(printElement);
複製代碼
也能夠將函數賦值給一個變量:
void printMessage(String message) {
print(message);
}
main() {
var p = printMessage;
p("assigning function to a variable");
}
複製代碼
匿名函數顧名思義就是沒有名字的函數, 能夠把沒有名字的函數稱之爲 匿名函數、lambda、閉包
匿名函數的語法格式:
([[Type] param1[, …]]) {
codeBlock;
};
複製代碼
例以下面一個使用匿名函數的案例:
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
複製代碼
forEach
函數式這樣的定義的:
void forEach(void f(E element)){
//...
}
複製代碼
而後咱們傳遞了一個匿名函數給 forEach 函數, 若是匿名函數體只有一條語句可使用箭頭函數簡化:
list.forEach((item) => print('${list.indexOf(item)}: $item'));
複製代碼
Lexical scope
也稱之爲 靜態做用域(Static Scope)
, 也就是說變量的做用域是靜態肯定的
外部不能訪問內部做用域的變量, 可是內部做用域能夠訪問外部做用域的變量
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);
}
}
}
複製代碼
相對地, 有 Static Scope
就有 Dynamic Scope
, 動態做用域就是說變量的做用域是動態肯定的
void fun(){
printf("%d", x);
}
void dummy1(){
int x = 5;
fun();
}
複製代碼
例如上面的代碼, 在 fun
函數中並無定義 x
變量, 該變量在 dummy1
函數中定義了, dummy1
函數調用了 fun
函數, 因此 fun
函數中使用的 x
變量就是 dummy1
函數的中 x
closures 能夠理解爲一個匿名函數, 它能夠訪問它本身的做用域內的變量, 哪怕變量已經超過了外部函數的做用域
例以下面的一個例子:
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
void main() {
// Create a function that adds 2.
var add2 = makeAdder(2);
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
複製代碼
上面的 makeAdder
函數返回一個匿名函數, 該匿名函數體內使用到了外部函數的變量 addBy
makeAdder
函數調用完畢後, 匿名函數依然可使用 addBy
變量.
關於 Dart 函數就講到這裏, 更多的關於 Android
學習資料能夠查看個人GitHub:
stackoverflow.com/questions/1… dart.dev/guides/lang…
下面是個人公衆號,乾貨文章不錯過,有須要的能夠關注下,有任何問題能夠聯繫我: